当前位置: 首页 > 科技观察

百亿流量全链路99.99%高可用架构优秀实践

时间:2023-03-21 15:30:00 科技观察

1.回顾上一篇文章(《?亿流量大考(4):自研ES+HBase+纯内存的高性能毫秒级查询引擎?》),说说系统架构中的查询平台。我们采用冷热数据分离:冷数据基于HBase+Elasticsearch+纯内存自研查询引擎,解决了海量历史数据的高性能毫秒级查询。热点数据基于缓存集群+MySQL集群实现当天数据几十毫秒的查询性能。最终整个查询架构可以承受每秒10万个并发查询请求,没问题。本文是本架构演进系列的最后一篇文章,我们来聊聊高可用这个话题。所谓的高可用是什么意思?简单来说,在这么复杂的架构中,任何一个环节都可能挂掉,比如MQ集群可能挂掉,KV集群可能挂掉,MySQL集群可能挂掉。那么你如何保证你的复杂架构中任何一个环节挂了,整个系统还能继续运行呢?这就是所谓的全链路99.99%高可用架构,因为我们的平台产品是付费级别的,在付费级别我们要为客户做到最好,可用性要有保障!让我们先来看看到目前为止的架构是什么样子的。2.MQ集群高可用解决方案异步转同步+限流算法+限制性丢弃流量平台几个小时不能交易,严重的几个小时公司就会损失几千万。我们之前也遇到过MQ集群故障的场景,但是在本系统中没有。想一想,如果MQ集群在这个环节出现故障会怎样?看右上角的地方,数据库binlog采集中间件无法向MQ集群写入数据,进而后面的流控集群无法向KV集群消费和存储数据。这种架构将彻底失败,无法发挥作用。这就是我们想要的效果吗?绝对不是这样。如果是这个效果,这个架构的可用性保障就太差了。因此,在这里,我们设计了一个针对MQ集群故障的高可用保障方案:异步转同步+限流算法+限制性丢弃流量。简单的说,一旦在数据库binlog采集过程中发现MQ集群故障,即多次尝试都无法向MQ集群写入数据,此时就会触发降级策略。不向MQ集群写入数据,而是直接调用流控集群提供的备流量接收接口,直接向流控集群发送数据。但是流控集群也比较尴尬。用于削峰的MQ集群。在高峰期,可以在MQ集群中积压一点数据,避免流量过大导致后台系统不堪重负。因此,流控集群的备份流量接收接口都执行限流算法,即如果发现流量超过阈值,则直接采用丢弃策略丢弃部分流量。但是丢弃部分流量也有一些特别之处。你如何丢弃流量?如果不管三七二十一,随意丢弃流量,可能会导致所有商家看到的数据分析结果不准确。所以,当时选择的策略是只丢弃一小部分商户的所有数据,而保留大部分商户的所有数据。或者说,比如你的平台有20万用户,可能在这种丢弃流量的策略下,2万个商家会发现他们看不到今天的数据,但是18万个商家的数据不会受到影响。精确的。但这总比20万商户的数据全部不准确好,所以在制定降级策略的时候,是有取舍的。在这种情况下,如果MQ集群出现故障,虽然可能会丢弃部分流量,导致最终的数据分析结果出现偏差,但绝大部分商户的数据都是正常的。看看下面的图片。高可用保证链路全部用浅红色表示,非常清晰。三、KV集群高可用保障方案Slave集群临时扩容+内存级分片存储+小时级数据粒度下一个问题,KV集群宕机怎么办?这个问题我们其实也遇到过,但不是在这个系统中,而是在我们负责的另一个核心系统中。KV集群确实出现故障,故障持续数小时,导致公司业务几近停摆。由于停产,损失也在几千万。看架构图右边部分,如果KV集群宕机了怎么办?那也是灾难性的,因为在我们的架构选择中,海量数据的存储是直接基于KV集群的。如果KV宕机,没有任何高可用保证,流控集群将无法向KV写入数据。cluster,此时后续链接无法继续计算。当时考虑要不要再引入一套存储双写,比如引入一套hbase集群,但是这样的依赖会比较复杂,需要自己努力,还需要优化我们自己的架构。所以当时选择的一套kv集群降级方案是:Slave集群临时扩容+小时级数据粒度+内存级分片存储。简单的说,一旦发现kv集群故障,就直接报警。我们收到告警后,会立即启动临时计划,手动扩容部署N倍的Slave计算集群。然后手动打开一个流控集群的降级开关,然后流控集群会根据预设的哈希算法直接将数据分发给各个Slave计算节点。这才是重点,不要再基于kv集群来存储数据了,我们的Slave集群本身就是分布式计算的,不就是分布式存储临时用的吗!流控集群直接向Slave集群分发数据就可以了,Slave节点可以将数据保存在内存中。那么Master节点在分发数据计算任务时,会保证计算任务分发给Slave节点后,只需要根据本地内存中的数据进行计算即可。重构Master节点和Slave节点。重构的成本不会太高,但是这样会达到本地数据存储+本地数据计算的效果。但是这里也有一个问题,要知道当天的数据量是非常大的!如果都放在Slave集群的内存中,还能用吗?所以,既然是降级,就得做一个平衡。我们选择了小时级别的数据粒度方案,即只在Slave集群中保存最近一个小时的数据,然后在计算数据指标时,只产生每个小时的数据指标即可。但是如果数据索引需要计算一天的数据,降级后就不能提供了,因为内存中永远只有最后一个小时的数据,这样才能保证slave集群的内存不会不知所措。对于用户来说,他们只能看到一天中每个小时的数据指标,而看不到全天的聚合数据。4、实时计算链路高可用保障方案计算任务重分配+主备切换机制接下来是实时计算链路高可用保障方案。其实这个之前也跟大家提过。实时计算环节是分布式架构,所以要么Slave节点宕机,要么Master节点宕机。其实这没什么,因为主节点感知到从节点宕机,会重新分配计算任务给其他计算节点;如果主节点宕机,基于主备高可用架构自动切换主备。我们只是将架构图中实时计算环节中的高可用环节标记为红色。5、热点数据高可用保障方案自研缓存集群查询引擎+JVM本地缓存+限流机制接下来我们看左边的数据查询。热点数据是提供实时计算链接写入当天数据的计算结果是的,MySQL集群用于托管主要数据,然后在前面挂载一个缓存集群。如果出现故障,只有两种情况:一种是MySQL集群故障,一种是缓存集群故障。我们分开说吧。如果MySQL集群出现故障,我们采用的解决方案是:将实时计算结果直接写入缓存集群,由于没有MySQL支持,无法使用SQL从MySQL汇集报表数据。因此,我们开发了一套基于缓存集群的内存级查询引擎,支持简单的查询语法,可以直接对缓存集群中的数据实现条件过滤、分组聚合、排序等基本查询语义,以及然后直接查询缓存中的数据。数据查询分析后返回。但是这样做唯一的缺点就是缓存集群承载的数据量远小于MySQL集群,所以会有部分用户看不到数据,部分用户可以看到数据。但既然是降级,肯定会损失一些用户体验。如果是缓存集群故障,我们在查询平台会有本地缓存??,可以使用ehcache等框架实现。从mysql中取出的数据可以缓存在查询平台的jvm本地缓存中,也可以作为一定的缓存支持高并发的效果。此外,查询平台实现了限流机制。如果查询流量超出其承载范围,则进行限流,直接对查询返回异常响应。6、冷数据高可用保障方案收集查询日志+离线日志分析+缓存高频查询。实现一点ES和HBase的宕机,然后想出一些降级的方案,是相当困难的。不能用ES了,可以暂时上Solr?或者HBase不能用,暂时用KV集群?不管用。那个实现复杂度太高,不适合。所以我们当时采取的方法是收集最近一段时间用户发起的离线查询的请求日志,然后分析每天凌晨的请求日志,分析每个用户会频繁发起什么样的请求、多次和频繁。冷数据查询请求,然后缓存这个特定查询对应的结果(比如一组特殊的条件、时间范围、维度组合)。这样,每天对每个用户频繁发起的冷数据查询请求的结果进行动态分析,并动态放入缓存集群。比如有的用户每天看上一周或者一个月的数据分析结果,这些结果可以提前缓存起来。一旦ES、HBase等集群出现故障,可以直接查询外部冷数据,只提供这些提前缓存好的高频查询。7.最后总结上面的系统到目前为止已经演进到一个非常好的状态,因为这个架构解决了百亿级流量,高并发写入,海量数据存储,高性能计算,高并发查询,高可用保障,以及其他技术挑战。线上生产系统运行非常稳定,足以应对各种生产层面的问题。其实这个系统架构在未来还可以继续演进,因为大型系统的架构演进可以持续N年。比如我们还有分布式系统全链路数据一致性保证,高稳定工程质量保证等等一系列的东西,但是文章就不继续写了,因为文章内容太少,很难把所有的东西都写清楚。其实很多同学跟我说,感觉看不懂这个架构演进系列的文章,其实很正常,因为文章承载的内容比较少,这里有很多详细的技术方案和实现,不能写。出来了,只能写大型系统架构的不断演进和解决线上各种技术挑战的过程。我觉得对于一些年轻的同学来说,主要是了解系统架构的演进过程。对于一些已经做过架构设计的大哥来说,应该能启发一些想法。