fourinone 实际上可以单独当做 Zookeeper 用,它使用最少的代码实现了 Zookeeper 的所有功能,并且力图做到功能更强但是使用更简洁。本文以 fourinone 为例详细解析了分布式协调的设计原理。
Fourinone(中文名字“四不像”)是一个四合一分布式计算框架,在写这个框架之前,我对分布式计算进行了长时间的思考,也看了老外写的其他开源框架。当我们把复杂的 Hadoop 当作一门学科学习时,似乎忘记了我们想解决问题的初衷:我们仅仅是想写个程序把几台甚至更多的机器一起用起来计算,把更多的 CPU 和内存利用上,来解决我们数量大和计算复杂的问题。当然这个过程中要考虑到分布式的协同和故障处理。如果仅仅是为了实现这个简单的初衷,为什么一切会那么复杂。我觉的自己可以写一个更简单的东西,它不需要过度设计,只需要看上去更酷一点,更小巧一点,功能更强一点。于是我将自己对分布式的理解融入到这个框架中,考虑到底层实现技术的相似性,我将 Hadoop,Zookeeper,MQ, 分布式缓存四大主要的分布式计算功能合为一个框架内,对复杂的分布式计算应用进行了大量简化和归纳。
Fourinone2.0 提供了一个 4 合 1 分布式框架和简单易用的编程 API,实现对多台计算机 CPU、内存、硬盘的统一利用,从而获取到强大计算能力去解决复杂问题。由于多计算机物理上独立,Fourinone 框架也提供完整的分布式协同和锁以及简化 MQ 功能,用于实现多机的协作和通讯。
Fourinone 框架提供了一系列并行计算模式(农民工 / 包工头 / 职介绍 / 手工仓库)用于利用多机多核 CPU 的计算能力; 提供完整的分布式缓存和小型缓存用于利用多机内存能力; 使提供像操作本地文件一样操作远程文件(访问、并行读写、拆分、排它、复制、解析、事务等)用于利用多机硬盘存储能力; 由于多计算机物理上独立,Fourinone 框架也提供完整的分布式协同和锁以及简化 MQ 功能,用于实现多机的协作和通讯。
Fourinone 采用 Java 开发,2.0 版本整体大小 150k,就一个 jar 和一个配置文件,没有任何依赖,很方便嵌入式开发使用。
Zookeeper 简介
Zookeeper 是 Hadoop 生态系统中协同实现,提供协调服务包括分布式锁,统一命名等。Chubby 是 Google 分布式系统中的协同实现,和 Zookeeper 类似。Zookeeper 实际上是 Google 的 Chubby 一个开源的实现。Paxos 算法是 1989 年由莱斯利.兰伯特提出,此算法被广泛用于处理分布式系统的消息传递一致性。
Zookeeper 的配置中心实现更像一个文件系统,文件系统中的所有文件形成一个树状结构。Zookeeper 维护着这样的树形层次结构,树中的节点称为 znode, 每个 znode 存储的数据有小于 1m 的大小限制。zookeeper 对 znode 提供了几种类型:临时 znode、持久 znode、顺序 node 等几种类型,用于不同的一致性需求。在 znode 发生变化时,通过“观察”(watch)机制可以让客户端得到通知。可以针对 ZooKeeper 服务的“操作”来设置观察,该服务的其他操作可以触发观察。ZooKeeper 服务的“操作”包括一些对 znode 添加修改获取操作。ZooKeeper 采用一种类似 Paxos 的算法实现领导者选举,用于解决集群宕机的一致性和协同保障。总体上,Zookeeper 提供了一个分布式协同系统,包括配置维护、名字服务、分布式同步、组服务等功能,并将相关操作接口提供给用户。
实现原理
fourinone 对分布式协同的实现, 是通过建立一个 domain、node 两层结构的节点信息去完成。domain 可以是分类或者包,node 可以是具体属性。domain 和 node 都是自己根据需求设计命名,比如可以将 domain 命名为“a.b.c...”表示一个树型类目。
一个 domain 下可以有很多个 node,每个 node 只指定一个 domain,可以通过 domain 返回它下面所有的 node。
domain 不需要单独建立,通常在建立 node 时,如果不存在 domain 会自动创建。
如果 domain 下没有 node 了,该 domain 会自动删除。
如果删除 domain,该 domain 下面 node 也都会删除。
每个 node 下可以存放一个值,可以是任意对象。
所有的节点信息存放在 parkserver 里,parkserver 提供协同者的功能。如下图所示:
图 1. 协调实现架构
从上图可以看到,其他分布式进程可以通过 parkserver 的用户接口:ParkLocal,对节点进行增加、修改、删除、指定心跳、指定权限等操作,并且结合 parkserver 提供同步备份、领导者选举、过期时间设置等功能,共同来实现众多分布式协同功能。
我们举个例子,说明两个分布式应用完成协同功能的流程:
分布式应用 A 通过 ParkLocal 在 ParkServer 上创建一个 domain/node 的节点,并且在节点里存放相应的 value,这个节点以及它的 value 值代表分布式应用 A 的某种协同信息,它存放在 ParkServer 上用于向分布式应用 B 分享。 分布式应用 B 通过 ParkLocal 操作 ParkServer,对它上面的分布式应用 A 建立的这个 domain/node 节点进行监听,如果节点 value 发生变化,那么分布式应用 B 可以获取到这个 value,并进行相应的业务处理,这样便将各自独立的分布式应用 A 和 B 协同了起来。 由于 ParkServer 保存着用于协同的节点和信息,为了
防止 ParkServer 宕机导致整体故障,ParkServer 配置为一主多备的关系,互相同步信息,在故障时可以进行领导者选举,切换到备用 ParkServer 上继续提供协同服务。
关于分布式协同的场景还有很多,可以参考:
分布式配置,多个机器的应用公用一个配置信息,并且挂掉能够通过领导者选举进行恢复,详细见 指南和demo 分布式锁,多个机器竞争一个锁,当某个机器释放锁或者挂掉,其他机器可以竞争到锁继续,详细见 指南和demo 集群管理,集群内机器可以互相感知和领导者选举,详见 指南和demo