转载请注明出处哈:http://carlosfu.iteye.com/blog/2240426
通过jedis来连接操作redis总体来说比较简单,按照redis单机、redis-sentinel、redis-cluster略有不同。
一、Jedis相关依赖
1. jedis依赖(选择最新的稳定版本,支持redis-cluster)
<jedis.version>2.7.2</jedis.version> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>${jedis.version}</version> </dependency>
2. logback和junit依赖
<logback.version>1.0.13</logback.version> <junit.version>4.11</junit.version> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> </dependency>
二、Jedis单机测试:
1. Jedis-简单Kv
Jedis jedis = new Jedis("127.0.0.1"); jedis.set("foo", "bar"); String value = jedis.get("foo");
建议所有的jedis都放在try catch finally(jedis.close操作)中
package com.sohu.tv.test.jedis; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; /** * 第一个jedis测试 * * @author leifu * @Date 2015年8月24日 * @Time 下午1:35:26 */ public class JedisFirstTest { private Logger logger = LoggerFactory.getLogger(JedisFirstTest.class); /** * redis单机host */ private final static String JEDIS_HOST = "127.0.0.1"; /** * redis单机port */ private final static int JEDIS_PORT = 6379; /** * 超时时间(毫秒) */ private final static int JEDIS_TIME_OUT = 300; @Test public void testJedis() { Jedis jedis = null; try { jedis = new Jedis(JEDIS_HOST, JEDIS_PORT, JEDIS_TIME_OUT); String key = "sohuKey"; jedis.set(key, "sohuValue"); String value = jedis.get(key); logger.info("get key {} from redis, value is {}", key, value); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { if (jedis != null) { jedis.close(); } } } }
2. Jedis-序列化Kv:
我们使用protostuff(Protostuff是基于大名鼎鼎的Google protobuff技术的Java版本)作为序列化工具:
(1)pom依赖:
<protostuff.version>1.0.8</protostuff.version> <dependency> <groupId>com.dyuproject.protostuff</groupId> <artifactId>protostuff-runtime</artifactId> <version>${protostuff.version}</version> </dependency> <dependency> <groupId>com.dyuproject.protostuff</groupId> <artifactId>protostuff-core</artifactId> <version>${protostuff.version}</version> </dependency>
(2)Club实体类:
package com.sohu.tv.bean; import java.io.Serializable; import java.util.Date; /** * 俱乐部 * * @author leifu * @Date 2015年7月28日 * @Time 下午1:43:53 */ public class Club implements Serializable { /** * 俱乐部id */ private int id; /** * 俱乐部名 */ private String clubName; /** * 俱乐部描述 */ private String clubInfo; /** * 创建日期 */ private Date createDate; /** * 排名 */ private int rank; public Club(int id, String clubName, String clubInfo, Date createDate, int rank) { super(); this.id = id; this.clubName = clubName; this.clubInfo = clubInfo; this.createDate = createDate; this.rank = rank; } public Club() { super(); } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getClubName() { return clubName; } public void setClubName(String clubName) { this.clubName = clubName; } public String getClubInfo() { return clubInfo; } public void setClubInfo(String clubInfo) { this.clubInfo = clubInfo; } public Date getCreateDate() { return createDate; } public void setCreateDate(Date createDate) { this.createDate = createDate; } public int getRank() { return rank; } public void setRank(int rank) { this.rank = rank; } @Override public String toString() { return "Club [id=" + id + ", clubName=" + clubName + ", clubInfo=" + clubInfo + ", createDate=" + createDate + ", rank=" + rank + "]"; } }
(3)序列化工具:
package com.sohu.tv.serializer; import com.dyuproject.protostuff.LinkedBuffer; import com.dyuproject.protostuff.ProtostuffIOUtil; import com.dyuproject.protostuff.Schema; import com.dyuproject.protostuff.runtime.RuntimeSchema; import java.util.concurrent.ConcurrentHashMap; /** * protostuff序列化工具 * * @author leifu * @Date 2015-8-22 * @Time 上午10:05:20 */ public class ProtostuffSerializer { private static ConcurrentHashMap<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap<Class<?>, Schema<?>>(); public <T> byte[] serialize(final T source) { VO<T> vo = new VO<T>(source); final LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE); try { final Schema<VO> schema = getSchema(VO.class); return serializeInternal(vo, schema, buffer); } catch (final Exception e) { throw new IllegalStateException(e.getMessage(), e); } finally { buffer.clear(); } } public <T> T deserialize(final byte[] bytes) { try { Schema<VO> schema = getSchema(VO.class); VO vo = deserializeInternal(bytes, schema.newMessage(), schema); if (vo != null && vo.getValue() != null) { return (T) vo.getValue(); } } catch (final Exception e) { throw new IllegalStateException(e.getMessage(), e); } return null; } private <T> byte[] serializeInternal(final T source, final Schema<T> schema, final LinkedBuffer buffer) { return ProtostuffIOUtil.toByteArray(source, schema, buffer); } private <T> T deserializeInternal(final byte[] bytes, final T result, final Schema<T> schema) { ProtostuffIOUtil.mergeFrom(bytes, result, schema); return result; } private static <T> Schema<T> getSchema(Class<T> clazz) { @SuppressWarnings("unchecked") Schema<T> schema = (Schema<T>) cachedSchema.get(clazz); if (schema == null) { schema = RuntimeSchema.createFrom(clazz); cachedSchema.put(clazz, schema); } return schema; } }
package com.sohu.tv.serializer; import java.io.Serializable; /** * @author leifu * @Date 2015-8-22 * @Time 上午10:05:44 * @param <T> */ public class VO<T> implements Serializable { private T value; public VO(T value) { this.value = value; } public VO() { } public T getValue() { return value; } @Override public String toString() { return "VO{" + "value=" + value + '}'; } }
(4)测试代码:
@Test public void testJedisSerializable() { ProtostuffSerializer protostuffSerializer = new ProtostuffSerializer(); Jedis jedis = null; try { jedis = new Jedis(JEDIS_HOST, JEDIS_PORT, JEDIS_TIME_OUT); String key = "sohuKeySerializable"; // 序列化 Club club = new Club(1, "AC", "米兰", new Date(), 1); byte[] clubBtyes = protostuffSerializer.serialize(club); jedis.set(key.getBytes(), clubBtyes); // 反序列化 byte[] resultBtyes = jedis.get(key.getBytes()); Club resultClub = protostuffSerializer.deserialize(resultBtyes); logger.info("get key {} from redis, value is {}", key, resultClub); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { if (jedis != null) { jedis.close(); } } }
(5)测试结果:
3. 连接池(推荐使用方式):一般线上系统的连接资源都是通过资源池的形式进行管理的。
package com.sohu.tv.test.jedis; import java.util.Date; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.sohu.tv.serializer.ProtostuffSerializer; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; /** * 第一个jedisPool测试 * * @author leifu * @Date 2015年8月24日 * @Time 下午1:35:26 */ public class JedisPoolTest { private Logger logger = LoggerFactory.getLogger(JedisPoolTest.class); private static JedisPool jedisPool; /** * redis单机host */ private final static String REDIS_HOST = "127.0.0.1"; /** * redis单机port */ private final static int REDIS_PORT = 6379; /** * 超时时间(毫秒) */ private final static int JEDIS_POOL_TIME_OUT = 1000; @BeforeClass public static void testBeforeClass() { GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig(); poolConfig.setMaxTotal(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL * 5); poolConfig.setMaxIdle(GenericObjectPoolConfig.DEFAULT_MAX_IDLE * 3); poolConfig.setMinIdle(GenericObjectPoolConfig.DEFAULT_MIN_IDLE * 2); poolConfig.setJmxEnabled(true); poolConfig.setMaxWaitMillis(3000); jedisPool = new JedisPool(poolConfig, REDIS_HOST, REDIS_PORT, JEDIS_POOL_TIME_OUT); } @AfterClass public static void testAfterClass() { if (jedisPool != null) { jedisPool.destroy(); } } @Test public void testJedisPool() { Jedis jedis = null; try { jedis = jedisPool.getResource(); String key = "sohuKeyPool"; jedis.set(key, "sohuValue"); String value = jedis.get(key); logger.info("get key {} from redis, value is {}", key, value); } catch (Exception e) { logger.error(e.getMessage(), e); } finally { if (jedis != null) { // 如果使用JedisPool,close操作不是关闭连接,代表归还资源池 jedis.close(); } } } }
(3.1) 注意:jedis.close的实现:
(2) dataSource=null代表直连,jedis.close代表关闭连接
(3) jedis.close放到finally里面做
Jedis源码中:
@Override public void close() { if (dataSource != null) { if (client.isBroken()) { this.dataSource.returnBrokenResource(this); } else { this.dataSource.returnResource(this); } } else { client.close(); } }
(3.2) GenericObjectPoolConfig参数说明如下:
- maxActive: 链接池中最大连接数,默认为8. (并非越大越好,具体原因可以参考GenericObjectPool的实现)
- maxIdle: 链接池中最大空闲的连接数,默认为8.
- minIdle: 连接池中最少空闲的连接数,默认为0.
- maxWait: 当连接池资源耗尽时,调用者最大阻塞的时间,超时将跑出异常。单位,毫秒数;默认为-1.表示永不超时.
- jmxEnabled: 当设置为true, 且服务开启的jmx服务时,使用jconsole, jvisualvm等工具将看到如下关于连接池的很全面的统计,这些统计结果有助于优化自己的配置。
其余配置如下:
- minEvictableIdleTimeMillis: 连接空闲的最小时间,达到此值后空闲连接将可能会被移除。负值(-1)表示不移除。默认-1
#借资源时候是否要验证,比如jedis对象验证是ip:port是否发生改变,且执行一个ping命令
#还资源时候是否要验证,同上。
6. timeBetweenEvictionRunsMillis: “空闲链接”检测线程,检测的周期,毫秒数。如果为负值,表示不运行“检测线程”。默认为-1.
-> 0 : 抛出异常,
-> 1 : 阻塞,直到有可用链接资源
-> 2 : 强制创建新的链接资源
四、Redis-Sentinel
JedisSentinelPool sentinelPool = new JedisSentinelPool(masterName, sentinelSet, poolConfig, timeout); //获取jedis的方法和JedisPool一样的,不在赘述
sentinelSet: sentinel实例列表
poolConfig: common-pool包中的GenericObjectPoolConfig
timeout: 超时
有一点需要注意的是:sentinelSet: sentinel实例列表,而不是具体的redis实例列表,这是因为为了实现高可用,jedis屏蔽了redis实例信息,所有实例信息(主从信息)都是通过sentinel获取。
五、Redis-Cluster
Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>(); jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379)); .... PipelineCluster pipelineCluster = new PipelineCluster(jedisPoolConfig, nodeList, timeout); //获取jedis的方法和JedisPool一样的,不在赘述
jedisPoolConfig: common-pool包中的GenericObjectPoolConfig
timeout: 超时时间
有一点需要注意的是:nodeList尽可能写入所有的redis实例信息(虽然jedis可以从任一redis实例获取到集群的信息。)
有兴趣的可以一下jedis源码中JedisClusterConnectionHandler这个类的initializeSlotsCache方法:
private void initializeSlotsCache(Set<HostAndPort> startNodes, GenericObjectPoolConfig poolConfig) { for (HostAndPort hostAndPort : startNodes) { Jedis jedis = new Jedis(hostAndPort.getHost(), hostAndPort.getPort()); try { cache.discoverClusterNodesAndSlots(jedis); break; } catch (JedisConnectionException e) { // try next nodes } finally { if (jedis != null) { jedis.close(); } } } for (HostAndPort node : startNodes) { cache.setNodeIfNotExist(node); } }附一个redis-cluster工厂类:
相关推荐
### Redis 学习与实战应用 #### 一、Redis 概述 Redis 是一款非常流行的非关系型(NoSQL)数据库。它不仅提供了快速的数据访问速度,还支持数据的持久化,使其成为许多应用场景下的首选。 ##### 1.1 NoSQL 数据库...
Redis从入门到精通2024版 视频教程 下载 ├─第 01 章 开篇 │ 001.Redis 录制计划.mp4 │ 002.Redis 介绍.mp4 │ 003.Redis 安装.mp4 ...│ 01....│ 02....│ 03....│ 04....│ 05....│ 20.RedisCluster
Redis从入门到高可用 分布式实战教程,共140多节课程、 掌握redis主从、哨兵、集群 ,参数调优 目录: 9-9 原生安装-1.准备节点.mp4 9-8 原生安装.mp4 9-7 基本架构.mp4 9-6 虚拟槽哈希分布.mp4 9-5 一致性...
Redis从入门到精通2024版 视频教程 下载 ├─第 01 章 开篇 │ 001.Redis 录制计划.mp4 │ 002.Redis 介绍.mp4 │ 003.Redis 安装.mp4 ...│ 01....│ 02....│ 03....│ 04....│ 05....│ 20.RedisCluster
Redis从入门到精通2024版 视频教程 下载 ├─第 01 章 开篇 │ 001.Redis 录制计划.mp4 │ 002.Redis 介绍.mp4 │ 003.Redis 安装.mp4 ...│ 01....│ 02....│ 03....│ 04....│ 05....│ 20.RedisCluster
Redis从入门到精通2024版 视频教程 下载 ├─第 01 章 开篇 │ 001.Redis 录制计划.mp4 │ 002.Redis 介绍.mp4 │ 003.Redis 安装.mp4 ...│ 01....│ 02....│ 03....│ 04....│ 05....│ 20.RedisCluster
Redis数据结构、原理分析、应用实战 什么是Redis Redis的作用 Redis的存储结构 Redis的安装 Redis的数据类型 字符串类型 列表类型 hash类型 集合类型 有序集合 Redis原理分析 过期时间设置 过期删除的原理 发布订阅 ...
Redis数据结构、原理分析、应用实战 什么是Redis Redis的作用 Redis的存储结构 Redis的安装 Redis的数据类型 字符串类型 列表类型 hash类型 集合类型 有序集合 Redis原理分析 过期时间设置 过期删除的原理 发布订阅 ...
3. 编写代码:使用Redis客户端(如Jedis、Redisson等)连接Redis,实现数据的增删改查操作。 4. 考虑扩展性:随着数据量的增长,可能需要考虑主从复制、Sentinel集群或Cluster集群来提高系统的可扩展性和容错性。 ...
《Redis in Action: Redis 实战 Java 版》是一本深入探讨如何在 Java 开发环境中有效利用 Redis 进行数据存储和处理的专业书籍。Redis 是一个高性能的键值数据库,广泛应用于缓存、消息队列、计数器等多种场景。本书...
- Spring Data Redis还支持Lettuce和Jedis两种客户端库。 5. Spring Boot实战Redis: - 缓存:利用Redis缓存数据,提高响应速度,减少数据库压力。例如,使用`@Cacheable`、`@CacheEvict`注解进行缓存管理。 - ...
《Redis in Action:Java+Python》是一本深入探讨Redis数据库使用的书籍,结合了两种主流编程语言——Java和Python,提供了丰富的实战案例和源代码。Redis是一个高性能的键值存储系统,广泛应用于缓存、消息队列、...
8. **集群**:Redis Cluster提供了一种分布式解决方案,可以将数据分布到多个节点上,自动处理节点间的通信和数据迁移。 9. **内存管理**:Redis默认将所有数据存储在内存中,但可以通过配置进行部分数据的持久化...
进一步地,Redis Cluster提供了分布式存储解决方案,通过分片技术将数据分散在多个节点上,实现水平扩展。 六、Redis缓存策略 在Web应用中,Redis常用于缓存数据,减少对后端数据库的压力。常见的缓存策略包括LFU...
6. **实战应用** - 缓存:SpringBoot可以配合Spring Cache或者自定义缓存管理器实现缓存功能。 - 消息队列:Redis的发布订阅功能可以作为简单的消息队列使用,Spring Data Redis提供了`JedisConnectionFactory`和`...
内容可能包括但不限于Redis的数据类型(如字符串、哈希、列表、集合、有序集合)、持久化策略(RDB和AOF)、主从复制、Sentinel哨兵系统和Cluster集群的构建与管理。此外,它还可能涉及Redis与其他服务的集成,例如...
Redis高可用集群实战与优化是构建稳定高效数据存储的关键步骤。相比哨兵模式,Redis集群模式在性能和可用性上有着显著优势。哨兵模式主要依赖于哨兵系统监控主节点状态,当主节点出现问题时,自动进行主从切换。然而...
### Redis开发实战:基于Redis的实时排行榜系统的实验心得与案例解析 #### 一、引言 Redis是一款基于内存的键值存储系统,以其卓越的性能和丰富的数据类型,在多个领域得到了广泛的应用,如缓存、消息队列以及实时...