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

如果让你自己设计一个分布式架构的中间件系统,你该怎么办?

时间:2023-03-16 18:10:15 科技观察

这篇文章是给大家说说一个生产级中间件系统的架构设计实践,希望对对中间件系统感兴趣的同学有所启发。1、Master-Slave架构的中间件系统的本质是分布式处理一些数据,但是具体的功能涉及到核心技术,这里不能直接说明。但是他的核心思想是把数据分布到很多机器上去处理,然后需要一台机器去控制N台机器的分布式处理,如下图。既然是分布式处理,必然涉及到在Master中维护集群的一些核心元数据。比如数据的分发和处理是如何调度的,具体处理过程的进度如何,以及描述集群中存储的数据的一些核心元数据。这些核心元数据肯定会不断地频繁修改。这时候你可以想到,不管你是基于外部文件还是数据库来存储这些元数据,还是zookeeper,其实都会导致它的元数据更新性能下降,因为要访问外部依赖。更重要的是,这种复杂的元数据可能不一定通过zk或数据库存储,因为它可能是非格式化的。因此,这里的一个核心设计是将核心的元数据直接存储在master的内存中,这样可以保证高并发更新元数据时的高性能,直接基于内存对外提供更新服务。如果Master部署在高配置的物理机上,比如32核128GB的物理机,支持每秒10万+请求是没有问题的。2.异步日志持久化机制但是这里有个问题。如果Master进程重启或者突然死机,内存中的数据不就丢失了吗?是的,那么对于这个问题,既然已经拒绝了基于外部存储写入元数据,那么这里可以采用异步持久化日志机制,将元数据更新日志以异步的方式写入磁盘文件。Master每次收到请求更新内存中的元数据,都需要生成元数据的更新日志,并将更新日志写入内存缓冲区。然后当内存缓冲区满了之后,一个后台线程将这里的数据刷新到磁盘中,如下图所示。肯定有人会说,如果一个更新日志刚写入缓冲区,Master就崩溃了,这时候不还是会有少量数据丢失吗?因为我还没来得及把它刷入磁盘呢。没错,为了保证高并发请求全部由内存来处理,必须使用异步持久化磁盘模式,所以必须容忍极度宕机,比如几秒可能丢失数据。那么如果是正常的Master重启呢?很简单,首先要清空logbuffer并刷入磁盘,然后正常重启Master才能保证磁盘上的所有数据不会丢失。然后在重启时,从磁盘中读取更新日志,将每一项依次返回到内存中,恢复核心元数据。3.Checkpoint机制:全量数据定时持久化但是这里还有一个问题,磁盘上的日志文件越来越大,因为元数据不断更新,最新的变更日志不断产生和写入到磁盘文件。系统运行一段时间后,是不是每次重启都需要从磁盘中读取所有的历史日志,一个一个回放到内存中,还原核心元数据?不可能,所以必须配合这里引入checkpoint机制。也就是说,每隔一段时间,就需要启动一个后台线程,将内存中的所有核心元数据序列化,并在此时作为快照文件写入到磁盘上的元数据文件中,同时清空日志文件同时。这称为检查点操作。下次重启时,只需读取元数据文件并直接反序列化到内存中,然后从日志文件中读取最后一个检查点后的变更日志回放到内存中即可恢复完整的元数据。这样可以快速重启Master,因为大部分数据都在checkpoint写入的元数据文件中。整个过程如下图所示:4.引入checkpoint节点,但是这时候又出现了一个问题。大家可以想一想,Master内存中的元数据需要高并发的访问和修改,同时每隔一段时间还要向磁盘写入checkpoints。那么在checkpoint过程中,是不是需要把所有的内存数据都锁起来,不允许别人修改呢?加锁的时候,将不会改变的数据写入磁盘文件,但是这个过程很慢,也就是说这个时候其他人的高并发写操作需要等待核心元数据的加锁。因为这时候别人把它锁住了,你不能锁住它往里面写数据,会导致系统卡死,几秒内无法响应请求。所以此时在架构设计中需要引入一个checkpoint节点,负责同步Master的changelog。然后在自己的内存中维护一个相同的核心元数据,Checkpoint节点负责每隔一段时间将内存数据写入磁盘,然后上传发送给Master。这样Master在执行checkpoint的时候就不需要锁住自己的内存数据了,如下图。在这样的架构下,对于Master来说,他只需要一个后台线程负责接收Checkpoint进程定时发送的元数据文件快照,然后写入本地磁盘即可,完全避免了对自身内存元数据的锁定。冲突问题。5.总结&思考总结一下这个架构设计,其实Master是基于内存来维护元数据的,这样一台物理机就可以支持每秒10万+的高并发请求。每次元数据更新时,都会向内存缓冲区写入一条日志,然后后台线程将日志刷新到日志文件中,同时需要向Checkpoint节点发送一条日志。Checkpoint节点会在自己的内存中维护完全相同的元数据,然后每隔一段时间执行一次checkpoint检查,写入元数据文件的快照。然后将其上传到Master节点并清除其日志文件。然后Master节点每次重启直接读取本地元数据文件的快照,只重放上一个checkpoint之后的log。这里你可能会问几个问题,比如Master节点突然宕机了怎么办?那很简单。直接的影响就是他的内存缓冲区的日志丢失了,造成少量的数据丢失,这个在我们的场景下是可以接受的。如果Checkpoint节点宕机了怎么办?那不要紧,因为他之前上传过元数据文件的快照,所以对于Master来说,数据最多同步不了。但是当Master重启后,仍然可以读取最新的元数据快照,然后回放日志。当Checkpoint节点恢复后,可以继续上次的同步日志,然后继续执行checkpoint操作。