前言

Jedis

JedisRedis 官方推荐的 Java 连接开发工具,要在Java开发中使用好 Redis中间件,必须对Jedis十分了解才行。

基本使用

Jedis 的使用非常简单,只需要创建 Jedis 对象的时候指定 host,port,password 即可。

Jedis jedis = new Jedis("ip",post);
......
jedis.close();

创建完 Jedis 对象,Jedis底层会打开一条 Socket 通道和 Redis 进行连接,所以在使用完 Jedis 对象后,需要 jedis.close() 关闭连接,不然会占用系统资源。如果每次使用都手动创建和销毁 Jedis 对象,对应用的性能有很大影响,毕竟创建 socket 的过程是很耗时的。所以我们使用连接池的方式减少 socket 对象的创建和销毁过程。

连接池使用

Jedis连接池是 org.apache.commons.pool2实现的,在构建连接池对象时,需要提供连接池对象的配置对象,我们可以通过这个配置对象对连接池进行相关参数的配置,比如:最大空闲连接数,最大连接总数。

JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(8);
jedisPoolConfig.setMaxTotal(18);
JedisPool jedisPool = new JedisPool(jedisPoolConfig, "ip", 6379, 2000);
Jedis jedis = jedisPool.getResource();
......
jedis.close();
jedisPool.close();

使用 Jedis连接池后,每次用完连接对象都会把连接归还给连接池。Jedisclose()getResource() 方法的实现。

//Jedis的close方法
@Override
public void close() { if (dataSource != null) {if (client.isBroken()) {this.dataSource.returnBrokenResource(this);} else {this.dataSource.returnResource(this);}} else {client.close();}
}// JedisPool.getResource()方法
// 从对象池中获取Jedis连接时,将会对dataSource进行设置
public Jedis getResource() {Jedis jedis = super.getResource();   jedis.setDataSource(this);return jedis;
}

高可用连接

我们知道,连接池可以大大提高应用访问Reids服务的性能,减去大量的 Socket 的创建和销毁过程。但是 Redis 为了保障高可用,服务一般都是 Sentinel部署方式。当 Redis 服务中的主服务挂掉之后,会仲裁出另外一台 Slaves 服务充当 Master。这个时候,我们的应用即使使用了Jedis连接池,Master服务挂了,还是无法连接新的 Master服务。为了解决这个问题,Jedis也提供了相应的 Sentinel 实现,能够在 Redis Sentinel 主从切换时候,通知我们的应用,把我们的应用连接到新的 Master 服务。

Set<String> sentinels = new HashSet<>();
sentinels.add("ip1");
sentinels.add("ip2");
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxIdle(8);
jedisPoolConfig.setMaxTotal(18);
JedisSentinelPool jedisPool = new JedisSentinelPool("mymaster", sentinels, jedisPoolConfig);
Jedis jedis = jedisPool.getResource();
......
jedis.close();
jedisPool.close();

JedisSentinelPool 的使用很简单,添加了设置服务器ip的 set 集合和 masterName参数,Jedis Sentinel底层基于 Redis订阅实现 Redis主从服务的切换通知,当 Redis发生主从切换时,Sentinel 会发送通知主动通知 Jedis 进行连接的切换。JedisSentinelPool 在每次从连接池中获取连接对象的时候,都要对连接对象进行检测,如果此链接和 SentinelMaster 服务连接参数不一致,则会关闭此连接,重新获取新的 Jedis 连接对象。

@Override
public Jedis getResource() {while (true) {Jedis jedis = super.getResource();jedis.setDataSource(this);// get a reference because it can change concurrentlyfinal HostAndPort master = currentHostMaster;final HostAndPort connection = new HostAndPort(jedis.getClient().getHost(), jedis.getClient().getPort());if (master.equals(connection)) {// connected to the correct masterreturn jedis;} else {returnBrokenResource(jedis);}}
}

使用 Spring 时可以引入 spring-data-redis 包,使用 SpringBoot 时可以直接引用 spring-boot-starter-redis包,其内部都整合了 Jedis

当然,也可以单独引用 Jedis 包。

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId>
</dependency>

Lettuce

Lettuce 是基于 Netty框架(NIO)的事件驱动的通信,支持同步和异步调用的,可扩展的 redis client,多个线程可以共享一个 RedisConnection,线程安全。

基本使用

1、引 lettuce 依赖

<dependency><groupId>io.lettuce</groupId><artifactId>lettuce-core</artifactId>
</dependency>

2、lettuce操作Redis

// 同步操作
@Test
public void test() {RedisURI redisURI = RedisURI.builder().withHost(“ip”).withPort(6379).withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisCommands<String, String> syncCommands = connection.sync();
String set = syncCommands.set(“k1”, “v1”);
System.out.println(set);
connection.close();
redisClient.shutdown();
}// 异步操作
@Test
public void testAsync(){RedisURI redisURI = RedisURI.builder().withHost(“ip”).withPort(6379).withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisAsyncCommands<String, String> asyncCommands = connection.async();
RedisFuture<String> set = asyncCommands.set(“k2”, “v2”);
System.out.println(set);
connection.close();
redisClient.shutdown();
}// 响应式API
@Test
public void testReactive() {RedisURI redisURI = RedisURI.builder().withHost(“192.168.96.173”).withPort(6379).withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();
RedisClient redisClient = RedisClient.create(redisURI);
StatefulRedisConnection<String, String> connection = redisClient.connect();
RedisReactiveCommands<String, String> reactiveCommands = connection.reactive();
Mono<String> set = reactiveCommands.set(“name”, “feiyangyang”);
System.out.println(set.block());

高可用连接

@Test
public void masterSlave() {RedisURI redisURI = RedisURI.builder().withHost("ip").withPort(6379).withTimeout(Duration.of(10, ChronoUnit.SECONDS)).build();RedisClient client = RedisClient.create(redisURI);StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, redisURI);// 从节点读主节点数据connection.setReadFrom(ReadFrom.REPLICA);RedisCommands<String, String> commands = connection.sync();commands.set("name", "feiyangyang");System.out.println(commands.get("name"));connection.close();client.shutdown();
}// 哨兵
@Test
public void sentinel() {List<RedisURI> uris = new ArrayList();uris.add(RedisURI.builder().withSentinel("ip1", 26379).withSentinelMasterId("mymaster").withPassword("123456").build());uris.add(RedisURI.builder().withSentinel("ip2", 26379).withSentinelMasterId("mymaster").withPassword("123456").build());uris.add(RedisURI.builder().withSentinel("ip3", 26379).withSentinelMasterId("mymaster").withPassword("123456").build());RedisClient client = RedisClient.create();StatefulRedisMasterReplicaConnection<String, String> connection = MasterReplica.connect(client, StringCodec.UTF8, uris);connection.setReadFrom(ReadFrom.REPLICA);RedisCommands<String, String> commands = connection.sync();commands.set("name", "feiyangyang");System.out.println(commands.get("name"));connection.close();client.shutdown();
}// 集群
@Test
public void cluster() {Set<RedisURI> uris = new HashSet<>();uris.add(RedisURI.builder().withHost("ip1").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("ip2").withPort(7001).withPassword("123456").build());uris.add(RedisURI.builder().withHost("ip3").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("ip4").withPort(7001).withPassword("123456").build());uris.add(RedisURI.builder().withHost("ip5").withPort(7000).withPassword("123456").build());uris.add(RedisURI.builder().withHost("ip6").withPort(7001).withPassword("123456").build());RedisClusterClient client = RedisClusterClient.create(uris);StatefulRedisClusterConnection<String, String> connection = client.connect();RedisAdvancedClusterCommands<String, String> commands = connection.sync();commands.set("name", "feiyangyang");System.out.println(commands.get("name"));//选择从节点,只读NodeSelection<String, String> replicas = commands.replicas();NodeSelectionCommands<String, String> nodeSelectionCommands = replicas.commands();Executions<List<String>> keys = nodeSelectionCommands.keys("*");keys.forEach(key -> System.out.println(key));connection.close();client.shutdown();
}

总结

Jedis 是直连 redis server,会有线程安全问题。除非使用连接池,为每个 Jedis实例增加物理连接。

优点:

  • 简单易理解
  • 全面的Redis操作API

缺点:

  • 同步阻塞IO
  • 不支持异步
  • 线程不安全

Lettuce是基于Netty的,连接实例可以在多个线程间并发访问,Lettuce还支持异步连接方式,提高网络等待和磁盘IO效率。

优点:

  • 线程安全
  • 基于Netty框架的事件驱动通信,可异步调用
  • 适用于分布式缓存

缺点:

  • 学习成本高,上手相对复杂

Redis Client 之 Jedis与Lettuce相关推荐

  1. SpringBoot配置redis集群(Jedis and lettuce)

    SpringBoot2.x版本配置redis集群(Jedis and lettuce) 在SpringBoot1.x版本中,springboot默认使用集成jedis,在SpringBoot2.x版本 ...

  2. redis java客户端配置,Java的Redis客户端选择-jedis与Lettuce

    Lettuce 和 Jedis 的定位都是Redis的client,所以他们当然可以直接连接redis server. Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线 ...

  3. springboot项目中redis客户端(Jedis、Lettuce、Redisson)

    一.redis客户端的对比 1).Jedis Jedis作为Redis官方推荐的一款客户端,也算是简单好用,基础功能齐全,在中小型项目中还是很好用的,但是Jedis是直连模式,在多个线程间共享一个Je ...

  4. Redis Java Client选型-Jedis Lettuce Redisson

    目录 1. 目标 2. 选型过程 2.1. 待选集合 2.2. 对比列表 2.3. 确定选型的考虑角度 1. 目标 针对redis java client,从多角度进行选型对比,以便选择符合业务要求的 ...

  5. Redis - Spring Data Redis 操作 Jedis 、Lettuce 、 Redisson

    文章目录 官网 Jedis VS Lettuce Jedis Code POM依赖 配置文件 配置类 单元测试 Lettuce Code Redisson Code POM依赖 配置文件 配置类 单元 ...

  6. Redis客户端 Jedis 与 Lettuce

    Lettuce 和 Jedis 的定位都是 Redis 的 client,所以它们可以直接连接redis server. Jedis 在实现上是直接连接的 redis server,如果在多线程环境下 ...

  7. Redis Client Lettuce 5 GA发布

    经过13个月的开发阶段和208张已解决的故障单,我很高兴宣布Lettuce 5.0全面上市. 这是一个主要发行版,带有一些重大更改,新的有趣功能以及Java 9兼容性. 从Maven Central获 ...

  8. Jedis和Lettuce

    Lettuce 和 Jedis 都是Redis的client,所以他们都可以连接 Redis Server. Jedis在实现上是直接连接的Redis Server,如果在多线程环境下是非线程安全的. ...

  9. redis -Spring与Jedis集群 Sentinel

    2019独角兽企业重金招聘Python工程师标准>>> redis -Spring与Jedis集群 Sentinel 博客分类: 缓存 首先不得不服Spring这个宇宙无敌的开源框架 ...

  10. redis client 2.0.0 pipeline 的list的rpop bug

    描写叙述: redis client 2.0.0 pipeline 的list的rpop 存在严重bug,rpop list的时候,假设list已经为空的时候,rpop出来的Response依旧不为n ...

最新文章

  1. HibernateTemplate 查询
  2. 推荐7款好用的cmd命令行终端工具
  3. B-tree结构菜单的递归查询
  4. 一个基于Node.js的本地快速测试服务器
  5. ubunut 下关闭apache服务自动启动
  6. 推荐一个牛逼的 GitHub 项目+支付宝、微信支付项目实战!快来获取!
  7. reverse() 几种操作
  8. 思源EMLOG文章页网址跳转插件V1.1
  9. oracle 删除行记录,使用实体框架从oracle数据库中删除记录
  10. 剑灵灵动区服务器位置,盘点国服剑灵灵动内测4大玩家人气玩法(2)
  11. Nginx+Tomcat实现单IP、多域名、多站点的访问
  12. 测量程序运行时间;getTickCount()与getTickFrequency()
  13. 毕设题目:Matlab图像检索
  14. 居于U2000手机管理光猫,小区运营商FTTH光猫注册神器,MA5680T手机管理,自动添加光猫...
  15. excel交互式图表
  16. VR全景,带您“飞临”探秘北京2022年冬奥会
  17. 上传到docker hub_在容器上构建持续部署及最佳实践初探
  18. html设置返回首页,html页面添加返回顶部按钮
  19. 人事管理系统是什么?HR系统有什么用?
  20. 免费且不丢失数据的MBR转GPT软件!

热门文章

  1. php的表达爱意的一句代码,表达爱意的诗句(精选50句)
  2. dah计算机原理,计算机原理
  3. android配置wifi,详解Android通过修改配置文件设置wifi密码
  4. android ro.boot.mac,Android Verified Boot浅知分享
  5. 物联网竞赛-LoRa和NB-IOT模块学习知识汇总
  6. Qdata模块-python获取关键词百度指数
  7. Gap Statistic算法详解
  8. java http put请求方式_HttpClient HTTP PUT请求方法示例
  9. Android Studio实现百度地图定位(显示经纬度和地址)
  10. 计算机网络技术组装与维护,计算机组装与维护计算机网络技术2010(组网)课程标准.doc...