本文主要研究一下lettuce的sentinel连接

RedisClient.connectSentinel

lettuce-core-5.0.4.RELEASE-sources.jar!/io/lettuce/core/RedisClient.java

    private <K, V> StatefulRedisSentinelConnection<K, V> connectSentinel(RedisCodec<K, V> codec, RedisURI redisURI,Duration timeout) {assertNotNull(codec);checkValidRedisURI(redisURI);ConnectionBuilder connectionBuilder = ConnectionBuilder.connectionBuilder();connectionBuilder.clientOptions(ClientOptions.copyOf(getOptions()));connectionBuilder.clientResources(clientResources);DefaultEndpoint endpoint = new DefaultEndpoint(clientOptions);StatefulRedisSentinelConnectionImpl<K, V> connection = newStatefulRedisSentinelConnection(endpoint, codec, timeout);logger.debug("Trying to get a Redis Sentinel connection for one of: " + redisURI.getSentinels());connectionBuilder.endpoint(endpoint).commandHandler(() -> new CommandHandler(clientOptions, clientResources, endpoint)).connection(connection);connectionBuilder(getSocketAddressSupplier(redisURI), connectionBuilder, redisURI);if (clientOptions.isPingBeforeActivateConnection()) {connectionBuilder.enablePingBeforeConnect();}if (redisURI.getSentinels().isEmpty() && (isNotEmpty(redisURI.getHost()) || !isEmpty(redisURI.getSocket()))) {channelType(connectionBuilder, redisURI);try {getConnection(initializeChannelAsync(connectionBuilder));} catch (RuntimeException e) {connection.close();throw e;}} else {boolean connected = false;boolean first = true;Exception causingException = null;validateUrisAreOfSameConnectionType(redisURI.getSentinels());for (RedisURI uri : redisURI.getSentinels()) {if (first) {channelType(connectionBuilder, uri);first = false;}connectionBuilder.socketAddressSupplier(getSocketAddressSupplier(uri));if (logger.isDebugEnabled()) {SocketAddress socketAddress = SocketAddressResolver.resolve(uri, clientResources.dnsResolver());logger.debug("Connecting to Redis Sentinel, address: " + socketAddress);}try {getConnection(initializeChannelAsync(connectionBuilder));connected = true;break;} catch (Exception e) {logger.warn("Cannot connect Redis Sentinel at " + uri + ": " + e.toString());causingException = e;}}if (!connected) {connection.close();throw new RedisConnectionException("Cannot connect to a Redis Sentinel: " + redisURI.getSentinels(),causingException);}}if (LettuceStrings.isNotEmpty(redisURI.getClientName())) {connection.setClientName(redisURI.getClientName());}return connection;}
  • connectSentinel方法,会遍历sentinel,挨个取master获取连接,如果连接不上或抛异常则继续用下一个sentinel获取
  • 如果遍历完sentinel都抛异常,则最后抛出RedisConnectionException("Cannot connect to a Redis Sentinel: " + redisURI.getSentinels(),causingException)
  • 这里会调用AbstractRedisClient的initializeChannelAsync方法

AbstractRedisClient.initializeChannelAsync

lettuce-core-5.0.4.RELEASE-sources.jar!/io/lettuce/core/AbstractRedisClient.java

    /*** Connect and initialize a channel from {@link ConnectionBuilder}.** @param connectionBuilder must not be {@literal null}.* @return the {@link ConnectionFuture} to synchronize the connection process.* @since 4.4*/@SuppressWarnings("unchecked")protected <K, V, T extends RedisChannelHandler<K, V>> ConnectionFuture<T> initializeChannelAsync(ConnectionBuilder connectionBuilder) {SocketAddress redisAddress = connectionBuilder.socketAddress();if (clientResources.eventExecutorGroup().isShuttingDown()) {throw new IllegalStateException("Cannot connect, Event executor group is terminated.");}logger.debug("Connecting to Redis at {}", redisAddress);CompletableFuture<Channel> channelReadyFuture = new CompletableFuture<>();Bootstrap redisBootstrap = connectionBuilder.bootstrap();RedisChannelInitializer initializer = connectionBuilder.build();redisBootstrap.handler(initializer);clientResources.nettyCustomizer().afterBootstrapInitialized(redisBootstrap);CompletableFuture<Boolean> initFuture = initializer.channelInitialized();ChannelFuture connectFuture = redisBootstrap.connect(redisAddress);connectFuture.addListener(future -> {if (!future.isSuccess()) {logger.debug("Connecting to Redis at {}: {}", redisAddress, future.cause());connectionBuilder.endpoint().initialState();channelReadyFuture.completeExceptionally(future.cause());return;}initFuture.whenComplete((success, throwable) -> {if (throwable == null) {logger.debug("Connecting to Redis at {}: Success", redisAddress);RedisChannelHandler<?, ?> connection = connectionBuilder.connection();connection.registerCloseables(closeableResources, connection);channelReadyFuture.complete(connectFuture.channel());return;}logger.debug("Connecting to Redis at {}, initialization: {}", redisAddress, throwable);connectionBuilder.endpoint().initialState();Throwable failure;if (throwable instanceof RedisConnectionException) {failure = throwable;} else if (throwable instanceof TimeoutException) {failure = new RedisConnectionException("Could not initialize channel within "+ connectionBuilder.getTimeout(), throwable);} else {failure = throwable;}channelReadyFuture.completeExceptionally(failure);CompletableFuture<Boolean> response = new CompletableFuture<>();response.completeExceptionally(failure);});});return new DefaultConnectionFuture<T>(redisAddress, channelReadyFuture.thenApply(channel -> (T) connectionBuilder.connection()));}
  • 这里initializeChannelAsync的时候,会调用connectionBuilder.socketAddress()方法,进而调用RedisClient的getSocketAddress方法

RedisClient.getSocketAddress

lettuce-core-5.0.4.RELEASE-sources.jar!/io/lettuce/core/RedisClient.java

    protected SocketAddress getSocketAddress(RedisURI redisURI) throws InterruptedException, TimeoutException,ExecutionException {SocketAddress redisAddress;if (redisURI.getSentinelMasterId() != null && !redisURI.getSentinels().isEmpty()) {logger.debug("Connecting to Redis using Sentinels {}, MasterId {}", redisURI.getSentinels(),redisURI.getSentinelMasterId());redisAddress = lookupRedis(redisURI);if (redisAddress == null) {throw new RedisConnectionException("Cannot provide redisAddress using sentinel for masterId "+ redisURI.getSentinelMasterId());}} else {redisAddress = SocketAddressResolver.resolve(redisURI, clientResources.dnsResolver());}return redisAddress;}private SocketAddress lookupRedis(RedisURI sentinelUri) throws InterruptedException, TimeoutException, ExecutionException {try (StatefulRedisSentinelConnection<String, String> connection = connectSentinel(sentinelUri)) {return connection.async().getMasterAddrByName(sentinelUri.getSentinelMasterId()).get(timeout.toNanos(), TimeUnit.NANOSECONDS);}}
  • getSocketAddress方法会调用lookupRedis方法,而lookupRedis方法则调用getMasterAddrByName方法,通过sentinel来获取master的ip地址

小结

  • redis的sentinel类似于一个master的服务发现中心,假设master有故障,则通过sentinel获取新的master实现failover。
  • 而sentinel部署多个来实现高可用,假设一个sentinel挂了,则client端使用下一个sentinel来获取master地址

doc

  • lettuce Redis-Sentinel

聊聊lettuce的sentinel连接 1相关推荐

  1. 聊聊lettuce的sentinel连接

    为什么80%的码农都做不了架构师?>>>    序 本文主要研究一下lettuce的sentinel连接 RedisClient.connectSentinel lettuce-co ...

  2. Sentinel 连接数据源

    若要载入 Azure Sentinel,首先需要连接到数据源. Azure Sentinel 随附许多适用于 Microsoft 解决方案的现成可用的连接器,提供实时集成(包括 Microsoft 威 ...

  3. Redis Lettuce客户端异步连接池详解

    前言 异步/非阻塞编程模型需要非阻塞API才能获得Redis连接.阻塞的连接池很容易导致阻塞事件循环并阻止您的应用程序进行处理的状态.Lettuce带有异步,非阻塞池实现,可与Lettuces异步连接 ...

  4. Redis中的Sentinel 连接使用

    Jedis 连接Sentinel(JedisSentinelTest.java) master name 来自于sentinel.conf 的配置. private static JedisSenti ...

  5. 聊聊lettuce的shareNativeConnection参数

    序 本文主要研究一下lettuce的shareNativeConnection参数 LettuceConnectionFactory spring-data-redis-2.0.10.RELEASE- ...

  6. Sentinel连接 Azure 活动日志中的数据

    只需要单击一次即可将日志从Azure 活动日志流式传输到 azure Sentinel. 活动日志是一种订阅日志,可用于深入了解 Azure 中发生的订阅级别事件. 这包括从 Azure 资源管理器操 ...

  7. python连接redis sentinel集群

    安装 python redis 客户端 pip install redis #!/usr/bin/env python # -*- coding:utf-8 -*-#!/usr/bin/env pyt ...

  8. python连接redis哨兵_python连接redis sentinel集群

    #!/usr/bin/env python # -*- coding:utf-8 -*- #!/usr/bin/env python import redis from redis.sentinel ...

  9. 解决Redisson无法连接Sentinel, Netty查找DNS失败

    前言 这里 redisson 的版本为 3.11.2, 对应 netty-all 的版本为 4.1.38.Final 如果这篇描述的方法不能解决问题,可以参考另外一篇 Redisson-3.8 查找D ...

  10. Lettuce连接池

    Lettuce 连接被设计为线程安全,所以一个连接可以被多个线程共享,同时lettuce连接默认是自动重连.虽然连接池在大多数情况下是不必要的,但在某些用例中可能是有用的.lettuce提供通用的连接 ...

最新文章

  1. 产生所有排列---旋转法------2013年1月22日
  2. 大型网站技术架构(二)架构模式
  3. 操作系统三: 地址空间与地址生成
  4. 编码(encode)问题
  5. [POJ2155] Matrix(二维线段树,树套树)
  6. C4C Product Price List的模型中和有效期相关的两个字段
  7. C++基础07-类之静态成员变量和成员函数
  8. 为基于spring-boot的应用添加根据运行时操作系统环境来提示用户选择active profile的功能...
  9. 表单内如何直接贴图而不用上传图片_重磅更新|偷偷告诉你,表单大师官网改版啦啦啦啦...
  10. nvidia TX2 CUDA yolov5环境搭建
  11. winxp一键锁定计算机,WinXP下锁定计算机的3种方法
  12. [置顶]       JQUERY一些注意事项
  13. pytorch convLSTM实现
  14. jdbc sql拼接字符串
  15. linux cups网络打印机,基于CUPS的网络打印服务器
  16. 一帮一 分数 15作者 陈越单位 浙江大学
  17. [Other]B树 B+树 B*树 - 三大名树的基础简介
  18. xml文件格式化脚本
  19. 微信小程序简易音频播放器(wx.getBackgroundAudioManager())
  20. 微信公众号点击列表进入详情页

热门文章

  1. 获取GridView的BoundField值
  2. android-Handler
  3. 大量字段表单在PHP便捷处理分享
  4. php版给UEditor的图片在线管理栏目增加图片删除功能
  5. There has been an error processing your request[magento1.6]
  6. 一封程序员的苦逼辞职信
  7. ASP.NET 2.0中直接将Access数据库导入到Excel文件中
  8. mac电池损耗百分比怎么查看
  9. 苹果Mac上如何使用预览反转图片?
  10. docker-compose 学习:部署 ThinkPHP 5 网站