Kubernetes - Envoy
Kubernetes
Kubernetes 主要基于 Kernel 技术栈,缺少精细化的高级流量治理
Kubernetes 已有的流量治理能力:Service + Ingress
Service 在 L4,基于 Kernel 技术栈,无法实现精细化的高级流量管理
Ingress 在 L7,主要针对入站流量
架构演进单体
访问服务
微服务
业务代码一般会集成统一的 SDK,耦合了很多平台侧的能力
Service MeshSidecar
Service Instance 与 Sidecar Proxy 在同一个 Network Namespace,相当于一个 loopback,可以明文传输
能力下沉
通过 Sidecar 来实现微服务治理,业务部门更聚焦于业务逻辑
Istio特性
HTTP、gRPC、WebSocket、TCP 的自动负载均衡
通过丰富的路由规则实现重试、故障转移、故障注入,可以对流量行为进行细粒度控制
可插入的策略层和配置 API,支持访问控制、速率限制和配额
对出入集群入口和出口中的所有流量的自动度量指标、日志记录和跟踪
通过强大的基于身份的验证和授权,在集群 ...
Kubernetes - Scaling
Aggregated APIServer
123456789101112131415161718192021222324$ k get apiservices.apiregistration.k8s.ioNAME SERVICE AVAILABLE AGEv1. Local True 36dv1.admissionregistration.k8s.io Local True 36dv1.apiextensions.k8s.io Local True 36dv1.apps Local True ...
Kubernetes - Helm
特性
Helm Chart 是创建一个应用实例的必要的配置组,即 Spec 集合
配置信息被归类为模板和值,经过渲染后生成最终的对象
所有配置可以被打包进一个可以发布的对象中
Release 为一个特定配置的 Chart 的实例
组件
只有客户端,没有服务端
Client
本地 Chart 开发
管理 Repository
管理 Release
与 Library 交互
发送需要安装的 Chart
请求升级或者卸载存在的 Release
Library
负责与 API Server 交互
基于 Chart 和 Configuration 创建一个 Release
把 Chart 安装到 Kubernetes,并提供相应的 Release 对象
升级 + 卸载
采用 Kubernetes 存储所有配置信息 - 无需服务端
实践
开发
123456789101112131415161718$ h create myappCreating myapp$ tree myappmyapp├── Chart.yaml├── charts├── templates│ ├── NOTES.txt│ ...
Kubernetes - Operator
应用接入应用容器化开销风险
Log Driver
Blocking mode
Non-Blocking mode
共享 Kernel
共享系统参数配置
进程数共享
fd 数共享
主机磁盘共享
资源监控应用视角
容器中看到的资源是主机资源
top
Java Runtime.availableProcessors()
cat /proc/cpuinfo
cat /proc/meminfo
df -k
影响应用
Java
Concurrent GC Thread
Heap Size
线程数不可控
判断规则
查询 /proc/1/cgroup 是否包含 kubepods 关键字
12345678910111213141516171819202122232425262728293031323334$ cat /proc/1/cgroup12:cpuset:/11:devices:/init.scope10:blkio:/init.scope9:freezer:/8:net_cls,net_prio:/7:pids:/init.scope6:perf_ ...
Go - Pointer
指针类型
指针类型是依托某一类型而存在的
对于某一类型 T,以 T 为基类型的指针类型为 *T
unsafe.Pointer 不需要基类型,用于表示一个通用指针类型
任何指针类型和 unsafe.Pointer 可以相互显式转换
1234567type T struct{}func main() { var p *T var p1 = unsafe.Pointer(p) // 任意指针类型 -> unsafe.Pointer p = (*T)(p1) // unsafe.Pointer -> 任意指针类型}
如果指针类型变量没有被显式赋予初值,默认值为 nil
123456type T struct{}func main() { var p *T println(p == nil) // true}
给指针类型变量赋值
123var a int = 13var p *int = &a // & 为 ...
Go - Type Constraint
限制
对泛型函数的类型参数以及泛型函数中的实现代码设置限制
泛型函数的调用者只能传递满足限制条件的类型实参
泛型函数内部也只能以类型参数允许的方式使用这些类型实参值
在 Go 中,使用类型参数约束来表达这种限制条件
函数普通参数在函数实现中可以表现出来的性质与可以参与的运算由参数类型限制
泛型函数的类型参数由约束来限制
内置约束any
最宽松的约束
无论是泛型函数还是泛型类型,其所有的类型参数声明中都必须显式包含约束
可以使用空接口类型来表达所有类型
123func foo[T interface{}](sl []T) {}func bar[T1 interface{}, T2 interface{}](t1 T1, t2 T2) {}
空接口类型的不足:使得声明变得冗长、复杂、语义不清
builtin/builtin.go12// any is an alias for interface{} and is equivalent to interface ...
Go - Type Parameter
不支持
Feature
Desc
泛型特化
编写一个泛型函数针对某个具体类型的特殊版本
元编程
编写在编译时执行的代码来生成在运行时执行的代码
操作符方法
不能将操作符视为方法并自定义其实现
变长类型参数
容器重复代码123456789101112131415161718192021222324252627func maxInt(sl []int) int { if len(sl) == 0 { panic("empty slice") } max := sl[0] for _, v := range sl[1:] { if v > max { max = v } } return max}func maxString(sl []string) string { if len(sl) == 0 { panic("empty s ...
Go - GC
逃逸分析
在传统的不带 GC 的编程语言中,需要关注对象的分配位置,是分配在堆上还是栈上
Go 集成了逃逸分析功能来自动判断对象是应该分配在堆上还是栈上
只有在代码优化时,才需要研究具体的逃逸分析规则
escape.go123456package mainfunc main() { var m = make([]int, 10240) println(m[0])}
1234$ go build -gcflags='-m' escape.go# command-line-arguments./escape.go:3:6: can inline main./escape.go:4:14: make([]int, 10240) escapes to heap
较大的对象会被放在堆上
如果对象分配在栈上,其管理成本比较低,只需要挪动栈顶寄存器就可以实现对象的分配和释放
如果对象分配在堆上,需要经过层层的内存申请过程
逃逸分析和垃圾回收结合,可以极大地降低开发者的心智负担,无需再担心内存的分配和释放
抽象成本
Rust - 零成本抽象
一切 ...
Go - Module Maintainer
仓库布局单模块
首选:一个 repo 管理一个 module,一般情况下,module path 与仓库地址保持一致
go.mod123module github.com/zhongmingmao/srsmgo 1.18
如果对 repo 打 tag,该 tag 会成为 module 的版本号,对 repo 的版本管理即对 module 的版本管理
12345678$ tree.├── LICENSE├── go.mod├── pkg1│ └── pkg1.go└── pkg2 └── pkg2.go
该 module 对应的包导入路径为
github.com/zhongmingmao/srsm/pkg1 和 github.com/zhongmingmao/srsm/pkg2
如果 module 演进到了 2.x 版本,则包导入路径变更为 github.com/zhongmingmao/srsm/v2/pkg1
多模块1234567891011$ tree.├── LICENSE├── module1│ ├── go.mod│ └── pkg1│ └── p ...
Go - Generics
泛型概念
将算法与类型解耦,实现算法更广泛的复用
实现方向
拖慢程序员
不实现泛型,不会引入复杂性
但需要程序员花费精力重复实现同逻辑但不同类型的函数或者方法
拖慢编译器 – C++/Go
类似 C++ 的泛型实现方案,通过增加编译器的负担为每个类型实例生成一份单独的泛型函数的实现
产生大量的代码,且大部分是多余的
拖慢执行性能 – Java
类似 Java 的泛型实现方案,即伪泛型,通过隐式的装箱和拆箱操作消除类型的差异
虽然节省了空间,但代码执行效率低
泛型设计类型系统
静态强类型:C++/Java/Go;动态强类型:Python;动态弱类型:JavaScript
Go 为强类型语言,而 JavaScript 为弱类型语言,Go 的类型强度高于 JavaScript
Go 和 Python 都有较高的类型强度,但类型检查的时机不同
Go 是在编译期,而 Python 则在运行期
如果类型检查是发生在运行期,则为动态类型语言
动态类型不仅仅表现在变量的类型可以更改,在 OOP 的编程语言中,类的定义也可以动态修改
动态类型的优点
动态类型有更好的灵活 ...