问题背景
- 假设有三台服务器(server1-server3)组成的集群上,平均分配,每台服务器上运行一个程序。此时由于某线上活动的开始(如抢票或低价秒杀),突然间又数以百万的用户访问服务器上的资源,等待服务器处理并应答。
- 其中有K台受不住负载压力,导致服务器奔溃。在这种情况下,如果客户端无法感知服务器的状态(在线/离线),部分已经向服务器发送请求的客户端将长时间无法应答,无法切换至3-k台正常的服务器进行交互。
- 因此,在这种场景下,如果客户端能够及时感知集群中哪些节点已经奔溃,哪些节点仍然完好,就可以切换至完好的节点并发送请求。
如何让客户端感知到服务器的上下线状态,以便切换请求发送的地址?
Zookeeper
ZooKeeper用来协调管理多个分布式应用程序,用于管理分布式机器集群,替用户监听指定的数据。ZooKeeper数据结构采用的是多叉树,在ZooKeeper的树结构中,每一个节点被称为znode。
znode有四种类型:
- PERSISTENT :持久不带序号
- EPHEMERAL :短暂不带序号
- PERSISTENT 且 SEQUENTIAL :持久且带序号
- EPHEMERAL 且 SEQUENTIAL :短暂且带序号
实现
ZKServer 服务器端代码
服务器端创建节点类型为EPHEMERAL.服务器上线时创建与zk之间的session并向zk注册节点,只要服务器正常,session便不会结束,EPHEMERAL节点会一直存在,当session结束时,EPHEMERAL节点会被自动删除,客户端无法感知到该服务器。
public class ZKServer {
//创建zookeeper对象
ZooKeeper zk = null;
public void connect() throws Exception {
zk = new ZooKeeper("master:2181,slave1:2181,slave2:2181", 2000, null);
}
//注册服务器,节点类型为临时有序
public void register(String host,String port) throws KeeperException, InterruptedException {
Stat stat = zk.exists("/servers", false);
if(stat == null) {
zk.create("/servers", null, Ids