分布式系统 服务单点问题的探讨

在分布式系统中 , 单点问题是一个比较常见的问题 , 对于单点问题可以分为有状态服务的单点问题和无状态服务的单点问题 。
无状态服务的单点问题
对于无状态的服务 , 单点问题的解决比较简单 , 因为服务是无状态的 , 所以服务节点很容易进行平行扩展 。比如 , 在分布式系统中 , 为了降低各进程通信的网络结构的复杂度 , 我们会增加一个代理节点 , 专门做消息的转发 , 其他的业务进行直接和代理节点进行通信 , 类似一个星型的网络结构 。

分布式系统 服务单点问题的探讨

文章插图

分布式系统 服务单点问题的探讨

文章插图
参考上面两个图 , 图中proxy是一个消息转发代理 , 业务进程中的消息都会经过该代理 , 这也是比较场景的一个架构 。在上图中 , 只有一个proxy , 如果该节点挂了 , 那么所有的业务进程之间都无法进行通信 。由于proxy是无状态的服务 , 所以很容易想到第二个图中的解决方案 , 增加一个proxy节点 , 两个proxy节点是对等的 。增加新节点后 , 业务进程需要与两个Proxy之间增加一个心跳的机制 , 业务进程在发送消息的时候根据proxy的状态 , 选择一个可用的proxy进行消息的传递 。从负载均衡的角度来看 , 如果两个proxy都是存活状态的话 , 业务进程应当随机选择一个proxy 。
那么该解决方案中会存在什么问题呢?
主要存在的问题是消息的顺序性问题 。一般来说 , 业务的消息都是发送、应答 , 再发送、再应答这样的顺序进行的 , 在业务中可以保证消息的顺序性 。但是 , 在实际的应用中 , 会出现这样一个情况:在业务进程1中 , 有个业务需要给业务进程3发送消息A和消息B , 根据业务的特性 , 消息A必须要在消息B之前到达 。如果业务进程1在发送消息A的时候选择了 , 在发送消息B的时候选择了 , 那么在分布式环境中 , 我们并不能确保先发送的消息A一定就能比后发送的消息B先到达业务进程3 。那么怎么解决这个问题?其实方案也比较简单 , 对于这类对消息顺序有要求的业务 , 我们可以指定对应的proxy进行发送 , 比如消息A和消息B都是使用进行发送 , 这样就可以保证消息A比消息B先到达业务进程3 。
整体来说 , 对于无状态的服务的单点问题的解决方案还是比较简单的 , 只要增加对应的服务节点即可 。
分布式系统 服务单点问题的探讨

文章插图
有状态服务的单点问题
相对无状态服务的单点问题 , 有状态服务的单点问题就复杂多了 。
如果在架构中 , 有个节点是单点的 , 并且该节点是有状态的服务 , 那么首先要考虑的是该节点是否可以去状态 , 如果可以 , 则优先选择去除状态的方案(比如说把状态存储到后端的可靠DB中 , 可能存在性能的损耗) , 然后就退化成了一个无状态服务的单点问题了 , 这就可以参考上一节的方案了 。
但是 , 并不是所有的服务都是可以去状态的 , 比如说对于一些业务它只能在一个节点中进行处理 , 如果在不同的节点中处理的话可能会造成状态的不一致 , 这类型的业务是无法去除状态的 。对于这种无法去除状态的单点的问题的解决方案也是有多种 , 但是越完善的方案实现起来就越复杂 , 不过整体的思路都是采用主备的方式 。这种通常是一台主机、一台或多台备机 , 在正常情况下主机对外提供服务 , 并把数据同步到备机 , 当主机宕机后 , 备机立刻开始服务 。