背景
之前在思考双活/多活架构的时候,其实对于蓝绿发布是有一些了解的,也梳理过在底层存储是一份,服务是多份的模式有做过深入的分析。但那个时候对于Kubernetes
的了解还不是很熟悉,是通过传统的方式来考量的。
因为现在的互联网公司基本都是上云了,我们也必须对于Kubernetes
那一整套要有比较深入、熟悉的运用才能真的提高我们的效率。先聊一下,我为什么需要利用灰度+蓝绿发布的模式来去做?
现在有一个比较老的项目,应该在10年+,每天请求量大概在1.5亿+,峰值的QPS
在6000/s,存在着比较多性能问题。现在需要在它上面新增一个服务,为了后面优化做准备,比如:请求的分流、限流、熔断、日志的上报与监控(新)、统一编译处理,特殊报文转换等。也就是说,只要你新增加了一层,你才有可能更好的去做更多的事情。
那么我们需要达到一些什么的基础条件了?
- 服务流量比较大,我们需要对新服务的可靠性需要验证,需要灰度先了解
- 因为存在慢查询,不能在滚动发布中,导致请求还未执行完毕,就被k8s kill掉了,业务会感知到502
如果是你?针对于这2个基础的要求,你会如何去思考的你架构方案呢?
思考
新增服务的思考:
- 它的性能必须要强、服务稳定。一个服务的性能好不好,其实跟它的:
I/O
模型、线程模型、数据结构、算法等息息相关。比如:你在思考Redis
单线程为什么快的时候?应该就很能get到这里的点了。解决这个问题,我们选择了Go
语言来开发(当然,最熟悉的语言风险最小),为了保证性能,也是做了2轮非常细致的压测。 - 发布过程中不能因为kill掉服务导致请求
502
。如果说我在发布的过程中,我把滚动这一步省略掉,直接先准备好一份最新的,验证可以后,我一刀直接把流量引导最新服务上,老的服务也不会断掉,这是否就可以达到效果了?
方案设计
下面是我画的一个架构图,方便大家的理解,一共是3条路线:
路线1:原始的路线
Ingress
→Service:server-read
→StatefulSet:server-g3-read + server-g3-read-gray
,整条链路是通过ingress
的指向与selector
的标签:k8s-app:server-read
。
路线2:灰度方案
服务正常
就是我只能让一少部分的流量进入到新的服务(2%~10%,支持慢慢调整,其实就是pod的数量占比)。
2%
的概率走的路径:Ingress
→Service:server-gateway-read01
→StatefulSet:server-gateway-read01
→注册中心获取负载地址
→Service:server-read
→StatefulSet:server-g3-read + server-g3-read-gray
,整条链路是通过ingress
的指向与selector
的标签:server-app:server-gateway-read01
98%
的概率还是走的路线1
服务异常解决方案
- 因为这个流量是通过节点数来控制的,如果发生异常,可以把灰度节点的POD数量调整为0
- 还可以从ingress的地址切换到线路1的原始方案。这一招永远生效,因为一整套label标签依然存在。
路线3:蓝绿路线
服务正常
- 100%的流量全部走灰度方案的。即:
Ingress
→Service:server-gateway-read01
→StatefulSet:server-gateway-read01
→注册中心获取负载地址
→Service:server-read
→StatefulSet:server-g3-read + server-g3-read-gray
。但是它的selector
的标签:server-app:server-gateway-read02
服务异常解决方案
- 直接切换ingress地址到线路1或者是线路2都可以
最终的方案
后面如果长期稳定后,方案2其实就没有必要再继续灰度了,直接就替换成线路3了。相当于是一个蓝绿+主备的模式了。优缺点非常的明显:
- 优点:解决了重启中可能出现的中断问题,其实也可以通过一些
Graceful Shutdown
优化。 - 缺点:就是发布的一瞬间,你是需要多出一倍的机器来支撑服务的。
再温馨提示一下,因为做了蓝绿发布,我们的系统对应的配置中心应该也最好是要分开的。系统之间要避免蓝色通过与绿色通道之间的交叉访问等问题。
如果大家喜欢我的文章,可以关注个人订阅号。欢迎随时留言、交流。如果想加入微信群的话一起讨论的话,请加管理员微信号:chengcheng222e
,他会拉你们进群。