特性越来越多,自然也就产生新的问题。
我们服务的特性在逐渐完善——指标监控,快照/回滚,备份/恢复,扩容,修改IO模式,只读告警等等。
整个系统本来打算演进的趋势是数据面尽可能的不依赖服务面,把一些事情尽量往容器里面做,但是后来遇到的一些现实问题,发现原来的预想比较理想。
先不说一个容器里面做太多事情违背容器的初衷(one process one container),就说要实现一个特性时,有些功能被集成在了容器的里面,它还是要依赖外部的交互才能完成,我们的理想是数据面不依赖服务面的配合就能独立交付(服务面是公有云的一组组件,而非公有云架构下,我们可能只需要独立交付数据面的docker镜像就行了),这种理想的情况需要数据面能cover住所有场景(不管是公有云架构还是非公有云架构),但现实告诉我们,它是做不到的(其实也能做到,只有一种场景,就是只有读写,没有其他功能),它只要有读写以外的关于可靠性的就需要外部的配合,这个外部可以是公有云的服务面,也可以是非公有云的服务面。
接下来通过一个例子解释一下为什么它做不到以及理想情况下的演进趋势。
我们最近在做一个特性——在线扩容,可以理解为在不影响业务的情况下动态扩容。扩容这个特性的方案出了三版,最终优化为将可能影响IO业务的时间窗口做到了极致。好,扩容特性是ok了,当然,中间也遇到过在修复分区表的过程中fence锁踩到的问题,也有一点曲折,不过最终扩容特性还是ok了。接下来,扩容后做了一次快照回滚(快照是扩容前打的),这下又不ok了,而且遇到了一个死锁的环,这个环必须从一个组件打破,否则无法解决这个不ok的问题。这个问题其实是这样的,扩容成功了,开始回滚,回滚后分区表又回到了扩容前的状态,即分区表会“复原”,也就是end位置不在整个块设备的end,k8s在拉起数据面的容器的时候,flex插件会对分区做检查,由于不在end位置,这个分区的命令(parted——插件的关键)会有多余的输出,也就是会有告警信息,这个告警信息导致flex插件不认识,然后报错,然后容器拉起失败。看到了吗,要想解决这个问题,就必须在插件检查分区之前把它修复掉,怎么修复——重建分区!
what,重建分区不是集成到容器里面了吗?容器要想被拉起就必须修复分区,修复分区就必须要容器正常启动,正常工作!卧槽,这不是我们想要的结果T﹏T
索性,把修复分区拿出来,修复分区都拿出来了,索性把重建分区也拿出来,重建分区都拿出来了,索性把resize也拿出来——至此,一切都安静了,服务面和数据面完全彻底的解藕了!我做扩容之前,直接把数据面容器杀死,扩容做完拉起,搞定,阿弥陀佛。
上面的例子解释了为什么做不到。当然,理想情况下,如果继续按照公有云架构的交付,可能有两种演进思路,一是拆分容器——我们是k8s管控的容器,一个pod管一个容器和管理两个容器几乎不会增加任何的开发成本和风险,实际上,在整个服务演进的历史进程中,我们曾经有过两次拆分为两个容器的冲动(LVM一次,重建分区一次);二是独立出来一个非公有云的版本。
因此,在公有云的架构下,后面可能有一种趋势,那就是尽可能的减少服务面和数据面的交互,实际上就是尽可能的解除依赖,对于新的特性服务面要承担越来越多的工作,数据面越来越趋向于专注做读写性能。
这么演进的好处是服务面和数据面从功能上越来越解藕,从业务上越来越亲密。
最后,没有银弹,好像真的没有银弹。
欢迎点评,欢迎吐槽。
网友评论