Redis Client 之 Jedis与Lettuce
前言
Jedis
Jedis
是 Redis
官方推荐的 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
连接池后,每次用完连接对象都会把连接归还给连接池。Jedis
对 close()
和 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
在每次从连接池中获取连接对象的时候,都要对连接对象进行检测,如果此链接和 Sentinel
的 Master
服务连接参数不一致,则会关闭此连接,重新获取新的 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相关推荐
- SpringBoot配置redis集群(Jedis and lettuce)
SpringBoot2.x版本配置redis集群(Jedis and lettuce) 在SpringBoot1.x版本中,springboot默认使用集成jedis,在SpringBoot2.x版本 ...
- redis java客户端配置,Java的Redis客户端选择-jedis与Lettuce
Lettuce 和 Jedis 的定位都是Redis的client,所以他们当然可以直接连接redis server. Jedis在实现上是直接连接的redis server,如果在多线程环境下是非线 ...
- springboot项目中redis客户端(Jedis、Lettuce、Redisson)
一.redis客户端的对比 1).Jedis Jedis作为Redis官方推荐的一款客户端,也算是简单好用,基础功能齐全,在中小型项目中还是很好用的,但是Jedis是直连模式,在多个线程间共享一个Je ...
- Redis Java Client选型-Jedis Lettuce Redisson
目录 1. 目标 2. 选型过程 2.1. 待选集合 2.2. 对比列表 2.3. 确定选型的考虑角度 1. 目标 针对redis java client,从多角度进行选型对比,以便选择符合业务要求的 ...
- Redis - Spring Data Redis 操作 Jedis 、Lettuce 、 Redisson
文章目录 官网 Jedis VS Lettuce Jedis Code POM依赖 配置文件 配置类 单元测试 Lettuce Code Redisson Code POM依赖 配置文件 配置类 单元 ...
- Redis客户端 Jedis 与 Lettuce
Lettuce 和 Jedis 的定位都是 Redis 的 client,所以它们可以直接连接redis server. Jedis 在实现上是直接连接的 redis server,如果在多线程环境下 ...
- Redis Client Lettuce 5 GA发布
经过13个月的开发阶段和208张已解决的故障单,我很高兴宣布Lettuce 5.0全面上市. 这是一个主要发行版,带有一些重大更改,新的有趣功能以及Java 9兼容性. 从Maven Central获 ...
- Jedis和Lettuce
Lettuce 和 Jedis 都是Redis的client,所以他们都可以连接 Redis Server. Jedis在实现上是直接连接的Redis Server,如果在多线程环境下是非线程安全的. ...
- redis -Spring与Jedis集群 Sentinel
2019独角兽企业重金招聘Python工程师标准>>> redis -Spring与Jedis集群 Sentinel 博客分类: 缓存 首先不得不服Spring这个宇宙无敌的开源框架 ...
- redis client 2.0.0 pipeline 的list的rpop bug
描写叙述: redis client 2.0.0 pipeline 的list的rpop 存在严重bug,rpop list的时候,假设list已经为空的时候,rpop出来的Response依旧不为n ...
最新文章
- HibernateTemplate 查询
- 推荐7款好用的cmd命令行终端工具
- B-tree结构菜单的递归查询
- 一个基于Node.js的本地快速测试服务器
- ubunut 下关闭apache服务自动启动
- 推荐一个牛逼的 GitHub 项目+支付宝、微信支付项目实战!快来获取!
- reverse() 几种操作
- 思源EMLOG文章页网址跳转插件V1.1
- oracle 删除行记录,使用实体框架从oracle数据库中删除记录
- 剑灵灵动区服务器位置,盘点国服剑灵灵动内测4大玩家人气玩法(2)
- Nginx+Tomcat实现单IP、多域名、多站点的访问
- 测量程序运行时间;getTickCount()与getTickFrequency()
- 毕设题目:Matlab图像检索
- 居于U2000手机管理光猫,小区运营商FTTH光猫注册神器,MA5680T手机管理,自动添加光猫...
- excel交互式图表
- VR全景,带您“飞临”探秘北京2022年冬奥会
- 上传到docker hub_在容器上构建持续部署及最佳实践初探
- html设置返回首页,html页面添加返回顶部按钮
- 人事管理系统是什么?HR系统有什么用?
- 免费且不丢失数据的MBR转GPT软件!
热门文章
- php的表达爱意的一句代码,表达爱意的诗句(精选50句)
- dah计算机原理,计算机原理
- android配置wifi,详解Android通过修改配置文件设置wifi密码
- android ro.boot.mac,Android Verified Boot浅知分享
- 物联网竞赛-LoRa和NB-IOT模块学习知识汇总
- Qdata模块-python获取关键词百度指数
- Gap Statistic算法详解
- java http put请求方式_HttpClient HTTP PUT请求方法示例
- Android Studio实现百度地图定位(显示经纬度和地址)
- 计算机网络技术组装与维护,计算机组装与维护计算机网络技术2010(组网)课程标准.doc...