上QQ阅读APP看书,第一时间看更新
1.2 分布式协调组件
分布式系统之所以存在,最根本的原因是数据量或计算量超过了单机的处理能力,因此不得不求助于水平扩展[4],而为了协调多个节点的动作,则不得不引入分布式协调组件。
在单机操作系统中,几个相互合作的进程(如生产者/消费者模型中的生产者进程和消费者进程),如果需要进行协调,就得借助于一些进程间通信机制,如共享内存、信号量、事件等。分布式协调组件提供的功能,本质上就是分布式环境中的进程间通信机制。
也许,有人会觉得这有何难,用一个数据库不就解决了吗?如代码清单1-1所示,将分布式锁信息保存在一张数据库表中(假如表名叫LOCK_TABLE),增加一个锁就是向LOCK_TABLE表中添加一新行(假如该行ID为MYCLOCK1),要获得该锁,只需要将MYCLOCK1行的某个字段(如LOCK_STATUS)置为1;要释放该锁,只需要将此字段置为0。利用数据库本身的事务支持,这个问题不就解决了吗?
代码清单1-1 利用数据库实现分布式锁
1. ' 获得锁
2. START TRANSACTION;
3. UPDATE LOCK_TABLE
4. SET LOCK_STATUS = 1, LOCK_OWNER="process1"
5. WHERE ID="MYCLOCK1" AND LOCK_STATUS=0;
6. COMMIT;
7. 调用者检查LOCK_OWNER字段是否为"process1",即可获知是否加锁成功
8. ' 释放锁
9. START TRANSACTION;
10. UPDATE LOCK_TABLE
11. SET LOCK_STATUS = 0, LOCK_OWNER=""
12. WHERE ID="MYCLOCK1" AND LOCK_STATUS=1 AND LOCK_OWNER="process1";
13. COMMIT;
然而,事情远没有那么简单。在分布式环境中,节点/网络故障为常态,如果采用代码清单1-1所示的方案,假如数据库所在的节点宕机了,整个系统就会陷入混乱。因此,这种有单点故障的方案肯定是不可取的。
分布式协调组件对外提供的是一种分布式同步服务。为了获得健壮性,一个协调组件内部也是由多个节点组成的,节点[5]之间通过一些分布式一致性协议(如Paxos、Raft)来协调彼此的状态。如果一个节点崩溃了,其他节点就自动接管过来,继续对外提供服务,好像什么都没有发生过一样。
另外,为了应用程序的方便,分布式协调组件经常还会允许在其上存放少量的信息(如主服务器的名称),这些信息也是由分布式一致性协议来维护其一致性的。