聊聊Zookeeper的Session会话超时重连

聊聊,zookeeper,session,超时 · 浏览次数 : 221

小编点评

**ZooKeeper 连接与会话** ZooKeeper 的连接与会话是一个客户端通过实例化 ZooKeeper 对象实现客户端与服务器创建并保持 TCP 连接的过程。会话是一个 TCP 长连接,用于存储和传递数据。 **会话的作用:** * 存储客户端与服务器之间的临时数据。 * 允许客户端提交给服务器的任何请求。 * 确保客户端和服务器之间的数据一致性。 * 当会话超时时自动消失。 **会话重连机制:** * 当客户端与服务器网络连接断开时,ZooKeeper 会自动进行反复的重连。 * 在重连过程中,客户端会尝试从地址列表中重新选取新的地址并尝试进行重新连接。 **会话失效的原因:** * 网络原因:JVM 内存不足导致 Full GC 进程阻塞。 * 会话超时:客户端在配置 sessionTimeout 参数时设置的超时时间已超过,导致会话失效。 **处理会话失效:** * 当会话失效时,客户端会重新实例化 ZooKeeper 对象,并尝试从地址列表中重新选取新的地址并进行重新连接。 * 如果重新连接失败,客户端会显示错误信息。

正文

概述

简单地说,ZooKeeper的连接与会话就是客户端通过实例化ZooKeeper对象来实现客户端与服务器创建并保持TCP连接的过程。本质上,Session就是一个TCP 长连接。

会话

Session会话的作用:

  1. ZK Server 执行任何请求之前,都需要 Client 与 Server 先建立 Session;
  2. Client 提交给 Server 的任何请求,都必须关联在 Session 上;
  3. Session 终止时,关联在 Session 上的临时数据节点都会自动消失;
  4. 接受来自Server的Watcher事件通知;

Session是ZooKeeper中的会话实体,代表了一个客户端会话。其包含以下4个基本属性。

  • sessionID:会话ID,用来唯一标识一个会话,每次客户端创建新会话的时候,ZooKeeper都会为其分配一个全局唯一的sessionID。
  • TimeOut:会话超时时间。客户端在构造ZooKeeper实例的时候,会配置一个sessionTimeout参数用于指定会话的超时时间。ZooKeeper客户端向服务器发送这个超时时间后,服务器会根据自己的超时时间限制最终确定会话的超时时间。
  • TickTime:下次会话超时时间点。为了便于ZooKeeper对会话实行“分桶策略”管理,同时也是为了高效低耗地实现会话的超时检查与清理,ZooKeeper会为每个会话标记一个下次会话超时时间点。TickTime是一个13位的long型数据,其值接近于当前时间加上TimeOut,但不完全相等。
  • isClosing:该属性用于标记一个会话是否已经被关闭。通常当服务端检测到一个会话已经超时失效的时候,会将该会话的isClosing属性标记为“已关闭”,这样就能确保不再处理来自该会话的新请求了。

会话重连

当客户端和服务端之间的网络连接断开时,ZooKeeper客户端会自动进行反复的重连,直到最终成功连接上ZooKeeper集群中的一台机器。在这种情况下,再次连接上服务端的客户端有可能会处于以下两种状态之一。

  • CONNECTED:如果在会话超时时间内重新连接上了ZooKeeper集群中任意一台机器,那么被视为重连成功。
  • EXPIRED:如果是在会话超时时间以外重新连接上,那么服务端其实已经对该会话进行了会话清理操作,因此再次连接上的会话将被视为非法会话。

当客户端与服务端之间的连接断开后,用户在客户端可能主要会看到两类异常:CONNECTION_LOSS(连接断开)和SESSION_EXPIRED(会话过期)。

连接断开:CONNECTION_LOSS
有时会因为网络闪断导致客户端与服务器断开连接,或是因为客户端当前连接的服务器出现问题导致连接断开,我们统称这类问题为“客户端与服务器连接断开”现象,即CONNECTION_LOSS。在这种情况下,ZooKeeper客户端会自动从地址列表中重新逐个选取新的地址并尝试进行重新连接,直到最终成功连接上服务器。

会话失效:SESSION_EXPIRED

SESSION_EXPIRED是指会话过期,通常发生在CONNECTION_LOSS期间。客户端和服务器连接断开之后,由于重连期间耗时过长,超过了会话超时时间(sessionTimeout)限制后还没有成功连接上服务器,那么服务器认为这个会话已经结束了,就会开始进行会话清理。但是另一方面,该客户端本身不知道会话已经失效,并且其客户端状态还是DISCONNECTED。之后,如果客户端重新连接上了服务器,那么很不幸,服务器会告诉客户端该会话已经失效(SESSION_EXPIRED)。在这种情况下,用户就需要重新实例化一个ZooKeeper对象,并且看应用的复杂情况,重新恢复临时数据。

会话失效的情况

对于连接断开的场景下,Zk客户端会自动尝试重连其他节点;但是会话失效的场景就需要考虑了,毕竟涉及到临时节点和Watcher,那么影响就会很大的。比如注册中心或是分布式锁的应用场景。

会话失效的情况一般有如下几种情况:

  1. 网络原因
  2. JVM内存不足导致Full GC
  3. 磁盘内存不足
  4. 程序bug

为什么会说到JVM?其实这也是最容易忽略的问题,尤其是Java应用的监控没有上的情况下。首先Zookeeper本身就是一个Java应用,其内存管理是受到了JVM的内存设置限制的。因此,对于这一类托管在JVM上的应用程序,必须考虑到JVM内存设置的问题。

如何解决?

对于失效的场景,比较合适的就是增加了一个监听器;监听session expired事件,并且在事件发生的时候进行处理。什么处理?自然是客户端重新拉起zk连接会话。

package com.xiaoju.dqa.prometheus.client.zookeeper;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SessionConnectionListener implements ConnectionStateListener {
    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    private String path;
    private String data;

    public SessionConnectionListener(String path, String data) {
        this.path = path;
        this.data = data;
    }

    @Override
    public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState){
        if(connectionState == ConnectionState.LOST){
            logger.error("[负载均衡失败]zk session超时");
            while(true){
                try {
                    if(curatorFramework.getZookeeperClient().blockUntilConnectedOrTimedOut()){
                        curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path, data.getBytes("UTF-8"));
                        logger.info("[负载均衡修复]重连zk成功");
                        break;
                    }
                } catch (InterruptedException e) {
                    break;
                } catch (Exception e){

                }
            }
        }
    }
}

参考

Zookeeper Curator 处理会话过期 Session Expired

优化hbase JVM GC 参数,避免由于JVM内存回收引发的ZooKeeper会话超时进程退出事件

zookeeper恢复了,线上微服务却全部掉线了,怎么回事?

与聊聊Zookeeper的Session会话超时重连相似的内容:

聊聊Zookeeper的Session会话超时重连

### 概述 简单地说,ZooKeeper的连接与会话就是客户端通过实例化ZooKeeper对象来实现客户端与服务器创建并保持TCP连接的过程。本质上,Session就是一个TCP 长连接。 ### 会话 Session会话的作用: 1. ZK Server 执行任何请求之前,都需要 Client

聊聊Zookeeper技术内幕之客户端与SetData请求处理

从客户端会话创建到网络连接、请求处理,简单的叙述下流程与逻辑 ### 客户端 客户端是开发人员使用ZooKeeper最主要的途径,ZooKeeper的客户端主要由以下几个核心组件组成。 - ZooKeeper实例:客户端的入口。 - ClientWatchManager:客户端Watcher管理器。

聊聊我认为的分布式、集群实现关键点

基于常见的中间件(Mysql、ElasticSearch、Zookeeper、Kafka、Redis)等分布式集群设计的机制,自己总结了在在集群设计过程中需要考虑的通用问题。 ### 节点通信机制 主节点的增加、删除、通信机制。 ### 路由算法 即数据路由到哪个节点的策略机制。在集群内有多个节点,

聊聊GLM-4-9B开源模型的微调loss计算

概述 Github官方地址:GLM-4 网上已经有很多关于微调的文章,介绍各种方式下的使用,这里不会赘述。我个人比较关心的是微调时的loss计算逻辑,这点在很多的文章都不会有相关的描述,因为大多数人都是关心如何使用之类的应用层,而不是其具体的底层逻辑,当然咱也说不清太底层的计算。 可了解其它loss

聊聊一个差点被放弃的项目以及近期的开源计划

前言 自从 StarBlog 和 SiteDirectory 之后,我还没写新的关于开源项目的系列,最近又积累了很多想法,正好写一篇博客来总结一下。 关于差点被放弃的项目,就是最近一直在做的单点认证(IdentityServerLite) IdentityServerLite 开发这个项目的起因,是

聊聊 JSON Web Token (JWT) 和 jwcrypto 的使用

哈喽大家好,我是咸鱼。 最近写的一个 Python 项目用到了 jwcrypto 这个库,这个库是专门用来处理 JWT 的,JWT 全称是 JSON Web Token ,JSON 格式的 Token。 今天就来简单入门一下 JWT。 官方介绍:https://jwt.io/introduction

聊聊MySQL是如何处理排序的

在MySQL的查询中常常会用到 order by 和 group by 这两个关键字,它们的相同点是都会对字段进行排序,那查询语句中的排序是如何实现的呢?

聊聊 Linux iowait

哈喽大家好,我是咸鱼。 我们在使用 top 命令来查看 Linux 系统整体 CPU 使用情况的时候,往往看的是下面这一列: %Cpu(s): 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 68.0 wa, 0.0 hi, 0.0 si, 0.0 st 其中,man 手册解释 w

聊聊Mybatis框架原理

好久没有写博客了。最近工作中封装了一个类似ORM框架的东西。大概的原理就是将Excel数据初始化到本地sqlite数据库后,通过json配置文件,对数据库的数据做增删改查等操作。 其实大概的思考了下,就是半ORM框架mybatis的逻辑,只是我们自己封装的简陋蛮多。想想有现成的轮子没用,反而是自己写

聊聊Spring的工厂方法与FactoryBean

概述 工厂方法是比较常见,常用的一种设计模式。FactoryBean是Spring提供的一种Bean注入IOC容器的方式。 工厂方法 在做日常开发时,一般都会避免直接new对象,而且将new的操作丢给IOC容器,但对于第三方系统的集成,我们不太好直接丢给IOC容器,此时可以通过工厂模式, 提供一个工