为什么需要多集群?
L0 服务,一旦故障影响巨大,所以需要保障高可用。
- 单一集群中,多个节点保证可用性,一般采用 N 2 来冗余节点。
- N 通过压测得出
- 出现集群级别的问题,例如redis集群出问题了,整个集群的服务都受影响,所以需要多集群来保障可用性。每个集群独占缓存,带来更好的性能和冗余。
- 部署到多个机房,避免单机房故障。
多集群实现
利用 pass 平台,部署时通过环境变量的形式注入集群信息,例如redis cluster信息,在服务发现注册的时候,带入这些元信息。从而达到多集群之间的隔离。
多集群产生的问题
面向各个应用搭建多个集群,例如给稿件服务提供一个账号集群,给游戏服务提供一个账号集群。问题:稿件服务的账号集群挂了,对应流量切换游戏的账号集群去,但是游戏的账号集群并没有稿件的缓存,就会造成 cache hit ratio 下降,DB压力大。解决:多集群不区分使用场景,和多节点类似。
多集群时,会存在多缓存,写操作时需要更新缓存。可以采用订阅mysql binlog,广播到各集群,清理对应缓存。
多租户
在一个微服务架构中允许多系统共存是利用微服务稳定性以及模块化最有效的方式之一,这种方式一般被称为多租户(multi-tenancy)。租户可以是测试,金丝雀发布,影子系统(shadow systems),甚至服务层或者产品线,使用租户能够保证代码的隔离性并且能够基于流量租户做路由决策。
如何解决多套测试环境的问题
背景
测试微服务,是一件很困的事情,在进入dev阶段前,每个feature都需要进行单独的测试。由于服务存在依赖关系,例如feature 1涉及服务A改动,服务A依赖服务B。feature2涉及服务B改动。测试feature 1时,需要保证服务B是稳定版本的。测试期间,有人把服务B升级,用来测试feature 2,从而可能导致feature 1测试异常。
以前公司的解决方案是,2套测试环境 人为安排测试任务。随着业务复杂,需求多,时间紧,不可能一套测试环境一天内就一个测试同学独占着,效率太低。再搭建一套测试环境?硬件成本高、维护也困难、硬件环境不同,难以做负载测试,仿真线上真实流量情况。而且,从目前来看,多套测试环境治标不治本。
利用多租户进行流量隔离
还是刚才的feature。
- feature 1 需要测试时,就部署一个服务
A-feature-1
到测试环境,再进行服务注册时,标识当前服务为A-feature-1
,不是A。 - 其他服务从注册中心拉取服务,并以标识为key,节点数组为value,放到map里。
- 测试同学通过前端设置header:
test-flag:feature-1
,发起请求。 - 后端收到请求后,解析header里的
test-flag
,放入context,服务调用时通过gRPC元数据传递context里的test-flag
。 - 本次请求的服务调用链路中,进行服务调用时,会通过目标服务名
test-flag
,从本地负载均衡map里取出对应节点。取不到再通过目标服务名去取,也就是获取稳定版的服务。
如何进行联调?
- 需要联调的应用打上相同的标签就可以了
注意事项
- 应用版本发布时的数据结构,必须保证向下兼容,数据库采用加新字段,废弃旧字段,缓存也使用新的key。
- 测试的时候需要使用不同的测试账号
- 注意来自外网的请求中的 header 必须删除,确保安全
如何进行全链路压测
前面提到过,测试环境和生产环境存在差异,导致压测数据不准确。那能不能直接在生产环境压测,但又不影响生产环境业务的正常使用?当然能,使用多租户的概念即可。
基于上诉的流量隔离可实现在生产环境压测,但这样会影响生产环境的正常业务。可通过影子系统,对基础设施进行隔离。
- 需要提前做一些数据初始化的操作,提前进行准备。
- 压测时携带压测标签,将流量自动路由到影子服务进行压测。
- 这种方案同样可以用于灰度发版当中,相对于蓝绿发布,不需要多套集群。
shadow system
数据库
- 在生产环境执行DDL语句时,同步对同一个DB实例里的影子库执行。影子库的名字以下划线开头(就一个标识,可自定义)。
- 使用数据库时,通过判断上下文里的标识(例如前面的test-flag),访问相应的数据库。
redis
- 通过key前缀进行隔离,例如压测的key为下划线 正常的key。
- 通过redis的库(默认16个)进行隔离。
消息队列
- 推送消息的时候使用不同的 topic 或者是携带一些 metadata 信息。