jediscluster 关闭 连接池_Redis——JedisCluster

jediscluster 关闭 连接池_Redis——JedisClustersmart客户端实现原理(追求性能,不使用代理)从集群中选一个可运行节点,使用clusterslots初始化槽和节点映射。将clusterslots的结果映射到本地,为每个节点创建JedisPool。执行命令执行命令执行命令的过程简单来说,就是通过CRC16计算出key的槽,根据节点映射直接访问目标节点,如果出错,就随机挑选一个节点,通过moved重定向访问目标节点,并且重新初始化节点映射。好…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE稳定放心使用

smart客户端

实现原理(追求性能,不使用代理)

从集群中选一个可运行节点,使用cluster slots初始化槽和节点映射。

将cluster slots的结果映射到本地,为每个节点创建JedisPool。

执行命令

jediscluster 关闭 连接池_Redis——JedisCluster

执行命令

执行命令的过程简单来说,就是通过CRC16计算出key的槽,根据节点映射直接访问目标节点,如果出错,就随机挑选一个节点,通过moved重定向访问目标节点,并且重新初始化节点映射。

好吧,直接上源码

JedisClusterCommand.java

//命令的执行过程

public T run(String key) {

if (key == null) {

throw new JedisClusterException(“No way to dispatch this command to Redis Cluster.”);

}

//这里是真正的执行函数,参数分别为UTF-8编码的key二进制数组,重定向的次数,是否尝试连接随机节点,是否ask重定向

return runWithRetries(SafeEncoder.encode(key), this.redirections, false, false);

}

private T runWithRetries(byte[] key, int redirections, boolean tryRandomNode, boolean asking) {

if (redirections <= 0) {

//对尝试连接目标节点的次数做判断,超过预设次数抛出异常

throw new JedisClusterMaxRedirectionsException(“Too many Cluster redirections?”);

}

Jedis connection = null;

try {

if (asking) {

//是否ask重定向

// TODO: Pipeline asking with the original command to make it

// faster….

connection = askConnection.get();

connection.asking();

// if asking success, reset asking flag

asking = false;

} else {

if (tryRandomNode) {

//是否尝试连接随机节点

connection = connectionHandler.getConnection();

} else {

//计算出key的槽位置,然后从本地缓存中获取目标主机的信息

connection = connectionHandler.getConnectionFromSlot(JedisClusterCRC16.getSlot(key));

}

}

//执行命令

return execute(connection);

} catch (JedisConnectionException jce) {

//连接出错,是否尝试随机节点

if (tryRandomNode) {

// maybe all connection is down

throw jce;

}

// release current connection before recursion释放当前连接

releaseConnection(connection);

connection = null;

//重新尝试连接,redirections -1

// retry with random connection

return runWithRetries(key, redirections – 1, true, asking);

} catch (JedisRedirectionException jre) {

// if MOVED redirection occurred,

if (jre instanceof JedisMovedDataException) {

// it rebuilds cluster’s slot cache

// recommended by Redis cluster specification

this.connectionHandler.renewSlotCache(connection);

}

// release current connection before recursion or renewing

releaseConnection(connection);

connection = null;

if (jre instanceof JedisAskDataException) {

asking = true;

askConnection.set(this.connectionHandler.getConnectionFromNode(jre.getTargetNode()));

} else if (jre instanceof JedisMovedDataException) {

} else {

throw new JedisClusterException(jre);

}

return runWithRetries(key, redirections – 1, false, asking);

} finally {

releaseConnection(connection);

}

}

JedisClusterConnectionHandler:连接持有者,实际上Handler内部维护了一个JedisClusterInfoCache ,也就是节点和槽信息映射,通过这些信息来获取连接池,换句话说,内置了所有节点的连接池

JedisClusterInfoCache .java

//集群节点信息转换器

public static final ClusterNodeInformationParser nodeInfoParser = new ClusterNodeInformationParser();

//节点–连接池映射 每个节点都分配了一个连接池

private Map nodes = new HashMap();

//槽–连接池映射 每个槽也分配了一个连接池

private Map slots = new HashMap();

//通过读写锁来分离对两个映射Map的访问,保证了集群信息的正确性

private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();

private final Lock r = rwl.readLock();

private final Lock w = rwl.writeLock();

自己动手写一个客户端连接工具测试一下,有个小bug,使用jedis2.8的时候会报host转换的异常,所以使用了2.9:

public final class ClusterUtil {

private ClusterUtil() {

}

public static JedisCluster getJedisCluster() {

return RedisClusterPoolHolder.getInstance();

}

private static final class RedisClusterPoolHolder {

//使用pool单例

private static final ClusterPool CLUSTER_POOL = new ClusterPool();

private RedisClusterPoolHolder() {

}

private static JedisCluster getInstance() {

return CLUSTER_POOL.getJedisCluster();

}

}

private static class ClusterPool {

/**

* redis-Cluster节点地址

*/

private static final HostAndPort CLUSTER_NODE_1 = new HostAndPort(“120..151.31”, 6379);

private static final HostAndPort CLUSTER_NODE_2 = new HostAndPort(“120..151.31”, 6380);

private static final HostAndPort CLUSTER_NODE_3 = new HostAndPort(“120..151.31”, 6381);

private static final HostAndPort CLUSTER_NODE_4 = new HostAndPort(“122..201.233”, 6379);

private static final HostAndPort CLUSTER_NODE_5 = new HostAndPort(“122..233”, 6380);

private static final HostAndPort CLUSTER_NODE_6 = new HostAndPort(“122..201.233”, 6381);

//Cluster节点地址集合

private static final Set NODES = new HashSet() {

{

add(CLUSTER_NODE_1);

add(CLUSTER_NODE_2);

add(CLUSTER_NODE_3);

add(CLUSTER_NODE_4);

add(CLUSTER_NODE_5);

add(CLUSTER_NODE_6);

}

};

/**

* 访问密码

*/

private static final String AUTH = “woshishei”;

private static final String HOST = “120.79.151.31”;

/**

* 可用连接实例的最大数目,默认值为8; 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。

*/

private static final int MAX_ACTIVE = 1024;

/**

* 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。

*/

private static final int MAX_IDLE = 200;

/**

* 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;

*/

private static final int MAX_WAIT = 10000;

private static final int TIMEOUT = 10000;

/**

* 在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;

*/

private static final boolean TEST_ON_BORROW = true;

/**

* JedisCluster

*/

private static JedisCluster JEDIS_CLUSTER = null;

ClusterPool() {

/**

* 初始化Redis-Cluster连接池.

*/

try {

// maxActive ==> maxTotal

// maxWait ==> maxWaitMillisl

/*

* 配置JedisPool*/

JedisPoolConfig CONFIG = new JedisPoolConfig();

CONFIG.setMaxTotal(MAX_ACTIVE);

CONFIG.setMaxIdle(MAX_IDLE);

CONFIG.setMaxWaitMillis(MAX_WAIT);

CONFIG.setTestOnBorrow(TEST_ON_BORROW);

JEDIS_CLUSTER = new JedisCluster(NODES, TIMEOUT, CONFIG);

} catch (Exception e) {

e.getMessage();

e.printStackTrace();

}

}

private JedisCluster getJedisCluster() {

return JEDIS_CLUSTER;

}

}

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/183350.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 树莓派3b入门指南「建议收藏」

    树莓派3b入门指南「建议收藏」近日,入手了树莓派3b,准备把它当一台防火墙用,配置如下:我买的套装是最简版的,只有一个电源线、一个塑料外壳,一个8GSD卡,几个散热片。捣鼓了几天,网上搜索了一些资料,在此记录下详细的过程,方便之后入手的朋友。一.烧写树莓派镜像(需要一个SD卡读写器)1.进入官网https://www.raspberrypi.org/downloads/下载页面,选择“RASP…

    2022年6月25日
    48
  • C# 连接SQL Sever 数据库与数据查询实例 数据仓库

    C# 连接SQL Sever 数据库与数据查询实例 数据仓库大数据时代在编程可能需要用到一些文本内容,不可能全部写到代码里,不好更改,用户也不方便使用所以需要用到我们的数据库来保存这些数据,直接更改数据SQL:下载地址:https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads1.现在后打开选择登录:Windows身份验证2.创建登录的账号和密码(右键创建)3.创建数据库表右键新建…

    2022年6月7日
    27
  • vmware15虚拟机激活码【最新永久激活】

    (vmware15虚拟机激活码)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html1STL5S9V8F-eyJsaWNlbnNlSWQi…

    2022年3月27日
    362
  • 一篇读懂无线充电技术(附方案选型及原理分析)「建议收藏」

    一篇读懂无线充电技术(附方案选型及原理分析)「建议收藏」一文读懂无线充电技术(附方案选型及原理分析)0.背景1.无线供电特点2.无线供电原理及实现方式3.现有解决方案分析4.FAQ及相关测试5.参考资料0.背景现今几乎所有的电子设备,如手机,MP3和笔记本电脑等,进行充电的方式主要是有线电能传输,既一端连接交流电源,另一端连接便携式电子设备充电电池的。这种方式有很多不利的地方,首先频繁的插拔很容易损坏主板接口,另外不…

    2022年5月7日
    48
  • Ags 9.3 文档逐步上线

    Ags 9.3 文档逐步上线

    2021年7月27日
    46
  • ubuntu安装nginx教程(php网站开发环境)

    一、说明正在尝试基于nginx+php搭建web服务器,中途遇到不少问题。挣扎了三四个小时终于完成了,这里分享下经验。实验环境操作系统:Ubuntu18.0464位nginx:1.14.0php:7.2.17-0php-fram:php7.2-fpm二、实验步骤1、安装必要程序以及依赖#安装程序包sudoapt-getinstallphp7.2…

    2022年4月10日
    63

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号