概述
对大多数互联网利用来说,利用是没有状态的,所以不停服更新绝对较容易实现,咱们有十分多带状态服务,这里对不停服更新的实现做一些记录。
实现拆解
残缺启动
在停机更新时,此组件凋谢的粒度是整个平台,不停服更新时,凋谢的粒度是单个组件过程,组件对外之前,必须确保外部曾经初始化结束。
K8S探针
K8S定义了一些探针,其中和不停服相干的,次要是就绪探针,和启动探针,它们定义了利用在什么时候算是筹备好(业务流量什么时候进入节点):
- 就绪探针 (Readiness),循环调用,决定服务发现,有没有流量进来(包含INGRESS和DNS,DNS简直是实时的,当节点滚动更新开始后,到节点就绪探针返回胜利前,DNS无奈发现对应节点,揣测INGRESS也是依赖DNS,所以,同样部署在K8S上的HTTP服务不须要额定减少SLB)。
- 存活探针 (Liveness),循环调用,失败重启容器。
- 启动探针 (Startup),先于就绪和存活探针调用,只胜利调用一次,能够用于预热。
erlang过程启动、敞开程序梳理
- 留神启动、敞开程序,让外部服务先开启,入口后(如对外端口开启,服务发现注册)开启,被依赖项先于依赖项启动。
- 如果应用异步加载,能够应用K8S Startup 探针。
优雅敞开
http短连贯优雅敞开
节点敞开时,DNS会马上移除,思考在途包,stop脚本须要sleep一小段时间(5秒)。
nginx 能够设置一个等待时间。
worker_shutdown_timeout 10;
服务发现优雅敞开
参考启动,敞开程序是:
- 摘除服务注册信息。
- 期待在途包隐没加一小段时间。
长连贯优雅敞开
长连贯是状态的一种,须要解决流量切换。
切流控制命令字
断开参考了HTTP2的GOAWAY指令。
至多有两条对等的通道,在连贯敞开时,用其它连贯进行调用。
一个失常的敞开流程:
留神不能应用TCP半敞开,在一方敞开申请后,还可能须要回复返回包。
服务发现接口
只有接入了切流控制命令字,无需接入服务发现接口,也能够做到长连贯优雅敞开。
服务发现接口有助于:
- 负载平衡。
- 容灾,能够疾速摘除故障节点。
用k8s原生的dns是能够通过轮询感知节点变动的,因为咱们还有swarm部署形式,故用etcd实现了相似于k8s endpoints 的 long pooling 服务发现接口:
状态迁徙
对有状态的节点,须要多做一些解决:在敞开前,须要先将状态迁徙走。
此前我实现了一个有核心节点治理的一致性哈希集群库,提供了申明式的rebalance_cluster接口:
rebalance_cluster("cluster1", ["node1", "node2"])
这里参考了K8S的节点状态,核心思想是:让利用上报本人的状态到核心节点,让核心节点用rebalance_cluster接口摘除下线(terminating)节点,并将running节点主动退出到集群中。对长时间不上报的节点,认为是unknown状态,会做摘除解决。
长时间运行工作
视工作运行时常而定,能够抉择:
- 期待工作执行结束,须要关注节点最大退出工夫。
- 将大工作拆分成小工作,写入外存,分而治之。
其它
erlang的热更为什么不行?
erlang的application-upgrade-file的粒度过小了。以一个简略的无状态组件为例,如果用K8S做热更新,程序员心智累赘较小,只须要放弃接口、数据向前兼容,就能够将节点灰度上线。而erlang的application-upgrade-file,程序员要思考load module的程序,操纵内存数据等,心智累赘显著更大。
当然erlang application-upgrade-file做在线hot fix还是很适合的。
总结
这里对前段时间所做的不停服更新专项的次要思维做了一些总结。理论落地的状况比本文总结的要简约一些,这里就不探讨细节了。
不停服更新,技术上不难,难的是放弃外部接口、数据的兼容性。在外部接口、数据放弃兼容的状况下,咱们能够应用不停服更新,从而升高停服更新的频率。
参考
- https://kubernetes.io/docs/concepts/services-networking/servi...
- https://datatracker.ietf.org/doc/html/rfc7540#section-6.8
- https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecy...
- https://www.erlang.org/doc/design_principles/release_handling...