zl程序教程

您现在的位置是:首页 >  其他

当前栏目

微服务应用的多机房部署

2023-04-18 12:41:29 时间

为了实现高可用性,微服务一般部署在多机房,只要部署到多机房就万无一失了?考虑如下问题:

1 多机房负载均衡

当服务部署在多个机房时,最简单的就是遵循用户就近访问原则,比如北方用户访问联通机房,南方用户访问电信机房。

为了实现负载均衡,还会在每个机房分别部署四层负载均衡器VIP以及七层负载均衡器Nginx。 比如来自北方用户的请求:

  • 通过DNS解析到联通机房下任一VIP
  • 然后通过VIP,把请求转发给联通机房下任一Nginx
  • Nginx再把请求转发给联通机房下任一Tomcat容器

以实现各个机房内高并发访问下的负载均衡。

这是最理想情况,实际部署时经常会遇到:

  • 某机房流量较大,但该机房服务器不足以支撑线上流量
  • 某机房服务有问题,需切一部分流量到另外一个机房

因此实际部署时,有时并不能完全遵循就近访问原则,而是要根据需要调配流量,达到各个机房流量均衡

可以通过两种方法来切换流量:

  • 在DNS解析时,把一部分北方用户请求解析到电信机房的VIP反之亦然
  • 在Nginx转发请求时,把一部分电信机房的Tomcat容器配置到联通机房的Nginx的upstream里或把一部分联通机房的Tomcat容器配置到电信机房的Nginx的upstream里

2 多机房数据同步

想要实现服务部署到多机房,供用户访问是有前提的,即每个机房的数据都一样,这就要求多机房间数据必须保持同步。

高并发访问的服务,数据通常都会有两层存储即缓存层和数据库层

要保证多机房的数据一致,不仅要保证数据库层的数据一致,还需要保证缓存层的数据一致,应该如何实现呢?

1.主从机房架构

以一个机房为主机房,所有写请求都只发给主机房:

  • 主机房的处理机更新本机房的缓存和DB
  • 其他机房的缓存也通过主机房的处理机更新
  • DB通过MySQL的binlog实现数据同步
  • 主从机房数据同步方案

这样做有一个很大的风险,若主机房出现问题,就没法更新缓存和DB,所以有了下个方案。

2.独立机房架构

联通和电信机房都有写请求,通过消息同步组件把各自机房的写请求同步一份给对方机房,相当于每个机房都有全量写请求。

  • 每个机房的处理机接收到写请求后更新各自的缓存
  • 只有一个机房会更新DB,其他机房DB通过MySQL的binlog同步

该架构的优势是任一机房异常,都不影响其它机房数据更新,因为每个机房都是全量写消息,所以每个机房可以更新自己缓存,并从DB主库同步数据。

消息同步组件是如何实现的呢? 消息同步组件是把一个机房写请求发给其它机房,实现原理如下:

  • reship 把本机房的写请求分发一份给其它机房
  • collector 从其它机房读取写请求,再把请求转发给本机房处理机

如何

实现消息同步功能

MQ实现

  • 采用MQ的实现方案

联通机房的写请求写入到联通机房的MQ,然后联通机房的reship就从MCQ读,写到电信机房MQ。 电信机房collector就能从电信机房MQ读取到写请求,再写到电信机房的另一个MQ,电信机房的队列机就会从这个MQ读出写请求,然后更新缓存。

这种方案缺点:

  • 流程比较长,需要多次与MQ交互,当有大量写请求时,不仅要扩容reship和collector,还需要扩容MQ以确保能够承受大量读取和写入。

更简单方案如下:

RPC调用实现

联通机房写请求会调用联通机房reship RPC=》调用电信机房collector RPC=》调用电信机房的处理机RPC,达到把联通机房写请求同步给电信机房处理机

多机房数据一致性

还要确保同步后的数据是一致的,因为同步过程各种原因都会导致各机房间数据不一致,需要确保数据一致性。 不同业务对数据一致性要求不同,金融类业务要求多机房间数据必须强一致,其它类型业务则没这么高要求,只需要能达到最终一致即可。 常见的是通过消息对账机制来保证最终一致性。

系统会给每次写请求生成一个全局唯一requestId,联通机房写请求:

  1. 调用联通机房的处理机RPC修改缓存和DB
  2. 调用联通机房的reship RPC,reship RPC再调用电信机房的collector RPC同步写请求,电信机房的collector RPC最后会调用电信机房的处理RPC来更新缓存。整个过程requestId始终保持向下传递,无论是处理成功或失败都记录一条包含requestId和机房标记的处理日志,并写到Elasticsearch集群。然后通过一个定时线程,每隔1分钟去扫描Elasticsearch集群上的日志,找出包含同一个requestId的不同机房的处理日志,然后验证是否在各个机房请求都处理成功了,如果有的机房某一阶段处理失败,则可以根据日志信息重试该阶段直到成功,从而保证数据的最终一致性。