Redis
Redis启动方法
1. redis-server和redis-cli默认启动
进入redis安装目录的src下
cd /usr/local/redis-5.0.4/src/
启动服务
→ /usr/local/redis-5.0.4/src$ ./redis-server
5693:C 10 Oct 2019 17:06:43.321 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
5693:C 10 Oct 2019 17:06:43.323 # Redis version=5.0.4, bits=64, commit=00000000, modified=0, pid=5693, just started
5693:C 10 Oct 2019 17:06:43.323 # Warning: no config file specified, using the default config. In order to specify a config file use ./redis-server /path/to/redis.conf
5693:M 10 Oct 2019 17:06:43.328 * Increased maximum number of open files to 10032 (it was originally set to 256).
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 5.0.4 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 5693
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | http://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'
5693:M 10 Oct 2019 17:06:43.334 # Server initialized
5693:M 10 Oct 2019 17:06:43.334 * Ready to accept connections
链接redis
→ /usr/local/redis-5.0.4/src$ ./redis-cli
127.0.0.1:6379> keys *
(empty list or set)
指定端口启动
# 指定6390端口启动redis服务
./redis-server --port 6390
./redis-cli -p 6390
指定某个配置文件启动
./redis-server ../redis.conf
链接远程的redis
# 6390为端口号 127.0.0.1 为本地ip, 链接远程redis直接更换为远程服务器的ip
./redis-cli -p 6390 -h 127.0.0.1
配置密码
修改redis的配置文件以设置密码
## ruiredis为密码
requirepass ruiredis
使用配置文件启动
./redis-server ../redis.conf
链接redis, 如果不输入密码或者输入错误密码, 也可以链接到redis, 但是查看keys或者做别的操作会提示
→ /usr/local/redis-5.0.4/src$ ./redis-cli
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379>
输入密码链接
→ /usr/local/redis-5.0.4/src$ ./redis-cli -a ruiredis
127.0.0.1:6379> keys *
1) "a"
127.0.0.1:6379>
Redis键命令
- 存储一个值
set key value
127.0.0.1:6379> set name lisi
OK
- 获取一个值
get key
127.0.0.1:6379> get name
"lisi"
- 获取存储列表所有的key
keys *
127.0.0.1:6379> keys *
1) "c"
2) "b"
3) "name"
4) "a"
- 判断一个key是否存在
exists key
127.0.0.1:6379> exists name
(integer) 1
127.0.0.1:6379> exists 9
(integer) 0
- 判断key的剩余生存时间
# -1代表永久有效, -2代表不存在
127.0.0.1:6379> ttl name
(integer) -1
- 给一个key设置有效期
# 给name设置20s的有效期
127.0.0.1:6379> expire name 20
(integer) 1
127.0.0.1:6379> ttl name
(integer) 18
- 获取key的类型
127.0.0.1:6379> type b
string
- 将key 重命名
# 如果rename是一个存在的key, 那么会将已有的key的value覆盖掉
127.0.0.1:6379> rename b d
OK
127.0.0.1:6379> keys *
1) "c"
2) "a"
3) "d"
# 如果renamenx一个存在的key, 那么会覆盖失败, 0为覆盖失败, 1是覆盖成功
127.0.0.1:6379> renamenx b c
(integer) 0
127.0.0.1:6379> renamenx b m
(integer) 1
Redis数据结构
1 .字符串
-
setex
: 设置有效期为秒
# 设置key为c, value为d, 有效期为100s
127.0.0.1:6379> setex c 100 d
OK
127.0.0.1:6379> get c
"d"
127.0.0.1:6379> ttl c
(integer) 91
-
psetex
: 设置有效期为毫秒
# 设置key为d, value为m, 有效期为10000ms
127.0.0.1:6379> psetex d 10000 m
OK
127.0.0.1:6379> get d
"m"
127.0.0.1:6379> ttl d
(integer) 4
-
getrange
: 获取范围内的字符串, 闭合区间, 包含边界的元素
# 获取key为word的前5个字符
127.0.0.1:6379> set word wordwordword
OK
127.0.0.1:6379> get word
"wordwordword"
127.0.0.1:6379> getrange word 0 4
"wordw"
-
getset
: 返回旧的value并设置一个新的value
127.0.0.1:6379> set rui rui
OK
127.0.0.1:6379> get rui
"rui"
127.0.0.1:6379> getset rui rui123
"rui"
127.0.0.1:6379> get rui
"rui123"
-
mset
: 同时设置多个key
127.0.0.1:6379> mset r1 1 r2 2 r3 3
OK
127.0.0.1:6379> mget r1 r2 r3
1) "1"
2) "2"
3) "3"
-
setnx
: 当key不存在的时候set成功, 返回1, 当key存在的时候set失败, 返回0
127.0.0.1:6379> keys *
1) "word"
2) "a"
3) "m"
4) "r2"
5) "r1"
6) "rui"
7) "r3"
127.0.0.1:6379> setnx rui 123
(integer) 0
127.0.0.1:6379> setnx rui123 345
(integer) 1
-
msetnx
: 当key不存在的时候set成功, 当key存在的时候set失败, 且具有事务的原子性, 要么全部成功, 要么全部失败
127.0.0.1:6379> msetnx rui 123 uuu iii
(integer) 0
127.0.0.1:6379> msetnx ruic 123 uuu iii
(integer) 1
-
incr
,decr
: integer类型增加和减少
127.0.0.1:6379> set int 1
OK
127.0.0.1:6379> incr int # 一次加1
(integer) 2
127.0.0.1:6379> incr int
(integer) 3
127.0.0.1:6379> incr int
(integer) 4
127.0.0.1:6379> get int
"4"
127.0.0.1:6379> incrby int 100 # 一次性加100
(integer) 104
127.0.0.1:6379> get int
"104"
127.0.0.1:6379> decr int
(integer) 103
127.0.0.1:6379> decr int
(integer) 102
127.0.0.1:6379> decrby int 100
(integer) 2
-
append
: 拼接字符串
127.0.0.1:6379> append int wtf
(integer) 4
127.0.0.1:6379> get int
"2wtf"
2. 哈希hash
-
hset
: 存储一个hash类型的数据
# map是key, name是map的key, lisi是map的value
127.0.0.1:6379[1]> hset map name lisi
(integer) 1
127.0.0.1:6379[1]> type map
hash
-
hexists
: 判断map内的key是否存在
127.0.0.1:6379[1]> hexists map name
(integer) 1
127.0.0.1:6379[1]> hexists map namecccc
(integer) 0
-
hget
: 获取一个hash类型的数据
127.0.0.1:6379[1]> hget map name
"lisi"
127.0.0.1:6379[1]> hget map cccc
(nil)
-
hgetall
: 获取hash的所有数据
127.0.0.1:6379[1]> hset map age 19
(integer) 1
127.0.0.1:6379[1]> hgetall map
1) "name"
2) "lisi"
3) "age"
4) "19"
-
hkeys
: 获取所有的key
127.0.0.1:6379[1]> hkeys map
1) "name"
2) "age"
-
hvals
: 获取所有的value
127.0.0.1:6379[1]> hvals map
1) "lisi"
2) "19"
-
hlen
: 获取hash类型数据的长度
127.0.0.1:6379[1]> hlen map
(integer) 2
-
hmget
: 一次性获取多个hash类型数据key的值
127.0.0.1:6379[1]> hmget map name age
1) "lisi"
2) "19"
-
hmset
: 一次性设置多个数据
127.0.0.1:6379[1]> hmset map newname zhangsan newage 28
OK
-
hdel
: 删除hash数据类型数据的值
127.0.0.1:6379[1]> hdel map newname newage
(integer) 2
3. 列表list
# 创建一个key为list的List, 先加入的在最下面
127.0.0.1:6379[2]> lpush list 1 2 3 4 5 6 7 8
(integer) 8
# 获取key
127.0.0.1:6379[2]> keys *
1) "list"
127.0.0.1:6379[2]> type list
list
# 获取key为list的数据长度
127.0.0.1:6379[2]> llen list
(integer) 8
# 获取前3个数据, 闭合区间, 包含边界的元素
127.0.0.1:6379[2]> lrange list 0 2
1) "8"
2) "7"
3) "6"
# 将最上面的数据修改为100
127.0.0.1:6379[2]> lset list 0 100
OK
127.0.0.1:6379[2]> lrange list 0 2
1) "100"
2) "7"
3) "6"
# 获取索引为5的数据
127.0.0.1:6379[2]> lindex list 5
"3"
# 删除最上面的元素
127.0.0.1:6379[2]> lpop list
"100"
# 删除最下面的元素
127.0.0.1:6379[2]> rpop list
"1"
127.0.0.1:6379[2]> lrange list 0 100
1) "7"
2) "6"
3) "5"
4) "4"
5) "3"
6) "2"
4. 集合set
# 创建一个set, key为set
127.0.0.1:6379[3]> sadd set a b c d
(integer) 4
127.0.0.1:6379[3]> keys *
1) "set"
127.0.0.1:6379[3]> type set
set
# 给set添加一个元素, 如果存在返回0, 如果不存在返回1
127.0.0.1:6379[3]> sadd set a
(integer) 0
# 返回集合内元素的数量
127.0.0.1:6379[3]> scard set
(integer) 4
127.0.0.1:6379[3]> sadd set2 c d e f
(integer) 4
127.0.0.1:6379[3]> keys *
1) "set2"
2) "set"
# 获取一个集合内的所有元素
127.0.0.1:6379[3]> smembers set
1) "c"
2) "b"
3) "a"
4) "d"
127.0.0.1:6379[3]> smembers set2
1) "c"
2) "e"
3) "d"
4) "f"
# 获取set比set2多的元素,
127.0.0.1:6379[3]> sdiff set set2
1) "b"
2) "a"
# 获取set2比set多的元素,
127.0.0.1:6379[3]> sdiff set2 set
1) "e"
2) "f"
# 获取两个集合的交集
127.0.0.1:6379[3]> sinter set set2
1) "c"
2) "d"
# 获取两个集合的并集
127.0.0.1:6379[3]> sunion set set2
1) "b"
2) "a"
3) "f"
4) "c"
5) "d"
6) "e"
# 从集合里随机获取2个元素
127.0.0.1:6379[3]> srandmember set 2
1) "b"
2) "d"
127.0.0.1:6379[3]> srandmember set 2
1) "c"
2) "d"
# 判断a是否为集合set内部的元素, 如果是返回1, 如果不是返回0
127.0.0.1:6379[3]> sismember set a
(integer) 1
127.0.0.1:6379[3]> sismember set m
(integer) 0
# 移除一个或者多个成员, 移除a和b
127.0.0.1:6379[3]> srem set a b
(integer) 2
127.0.0.1:6379[3]> smembers set
1) "c"
2) "d"
# 移除并且返回 一个随机元素
127.0.0.1:6379[3]> spop set2
"c"
127.0.0.1:6379[3]> smembers set2
1) "e"
2) "d"
3) "f"
5. 有序集合sortedset
# 创建一个有序集合, key为sortedset1 , 内部的key为a b c, value为100 200 300
127.0.0.1:6379[4]> zadd sortedset1 100 a 200 b 300 c
(integer) 3
127.0.0.1:6379[4]> keys *
1) "sortedset1"
127.0.0.1:6379[4]> type sortedset1
zset
127.0.0.1:6379[4]> rename sortedset1 sortedset
OK
# 获取sortedset的元素个数
127.0.0.1:6379[4]> zcard sortedset
(integer) 3
# 获取a的value
127.0.0.1:6379[4]> zscore sortedset a
"100"
# 获取b的value
127.0.0.1:6379[4]> zscore sortedset b
"200"
# 获取c的value
127.0.0.1:6379[4]> zscore sortedset c
"300"
# 获取d的value, 没有不存在返回nil
127.0.0.1:6379[4]> zscore sortedset d
(nil)
# 获取value在[0, 200]的元素的个数
127.0.0.1:6379[4]> zcount sortedset 0 200
(integer) 2
# 获取value在[0, 300]的元素的个数
127.0.0.1:6379[4]> zcount sortedset 0 300
(integer) 3
# 获取a的索引
127.0.0.1:6379[4]> zrank sortedset a
(integer) 0
# 获取b的索引
127.0.0.1:6379[4]> zrank sortedset b
(integer) 1
127.0.0.1:6379[4]> zrank sortedset c
(integer) 2
# 获取a的增加1000
127.0.0.1:6379[4]> zincrby sortedset 1000 a
"1000"
# 获取前101个元素的key, 闭合区间
127.0.0.1:6379[4]> zrange sortedset 0 100
1) "a"
2) "b"
3) "c"
127.0.0.1:6379[4]> zrange sortedset 0 1
1) "a"
2) "b"
127.0.0.1:6379[4]> zrange sortedset 0 1 withscores
1) "a"
2) "100"
3) "b"
4) "200"
Redis连接池
public class RedisPool {
// jedis连接词
private static JedisPool pool;
// 最大连接数
private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getProperty
("redis.max.total", "20"));
// 最大的Jedispool中最大的idle状态(空闲的)的Jedis实例的个数
private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getProperty
("redis.max.idle", "20"));
// 最小的Jedispool中最大的idle状态(空闲的)的Jedis实例的个数
private static Integer minIdle = Integer.parseInt(PropertiesUtil.getProperty
("redis.min.idle", "10"));
// 在brrow一个jedis实例的时候, 是否要进行验证, 如果赋值为true, 那么表示不需要. 从连接池获取链接
private static Boolean testOnBrrow = Boolean.parseBoolean(PropertiesUtil
.getProperty
("redis.test.testOnBrrow", "true"));
// 在return一个jedis实例的时候, 是否要进行验证, 如果赋值为true, 那么不需要, 链接归还连接池
private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil
.getProperty("redis.test.testOnReturn", "true"));
// redis的ip
private static String ip = PropertiesUtil.getProperty("redis.ip");
// redis的port
private static Integer port = Integer.parseInt(PropertiesUtil.getProperty
("redis.port"));
private static void initPool() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxTotal);
jedisPoolConfig.setMaxIdle(maxIdle);
jedisPoolConfig.setMinIdle(minIdle);
jedisPoolConfig.setTestOnBorrow(testOnBrrow);
jedisPoolConfig.setTestOnReturn(testOnReturn);
// 链接耗尽的时候 是否阻塞. false会抛出异常, true会阻塞一直到超时, 默认为true
jedisPoolConfig.setBlockWhenExhausted(true);
pool = new JedisPool(jedisPoolConfig, ip, port, 1000 * 2);
}
// 随着tomcat的启动而初始化
static {
initPool();
}
// 获取jedis实例
public static Jedis getJedis() {
return pool.getResource();
}
// 回收jedis
public static void returnResource(Jedis jedis) {
pool.returnResource(jedis);
}
// 回收坏的链接
public static void returnBrokenResource(Jedis jedis) {
pool.returnBrokenResource(jedis);
}
public static void main(String[] args) {
Jedis jedis = getJedis();
jedis.set("ruirui", "dayday");
returnResource(jedis);
pool.destroy();
}
}
Redis API工具类
public class RedisPoolUntil {
private static Logger logger = LoggerFactory.getLogger(CategoryServiceImpl
.class);
/**
* 封装set方法
* @param key
* @param value
* @return
*/
public static String set(String key, String value) {
Jedis jedis = null;
String result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.set(key, value);
} catch (Exception e) {
logger.error("set key:{} value:{} error:", key, value, e);
RedisPool.returnBrokenResource(jedis);
return result;
}
RedisPool.returnResource(jedis);
return result;
}
/**
* 重新给key设置过期时间
* @param key
* @param exTime 单位为秒
* @return
*/
public static Long expire(String key, int exTime) {
Jedis jedis = null;
Long result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.expire(key, exTime);
} catch (Exception e) {
logger.error("expire key:{} value:{} error:", key, e);
RedisPool.returnBrokenResource(jedis);
return result;
}
RedisPool.returnResource(jedis);
return result;
}
/**
* 设置过期时间
* @param key
* @param value
* @param exTime 单位是秒
* @return
*/
public static String setEx(String key, String value, int exTime) {
Jedis jedis = null;
String result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.setex(key, exTime, value);
} catch (Exception e) {
logger.error("setex key:{} value:{} error:", key, value, e);
RedisPool.returnBrokenResource(jedis);
return result;
}
RedisPool.returnResource(jedis);
return result;
}
/**
* 封装get方法
* @param key
* @return
*/
public static String get(String key) {
Jedis jedis = null;
String result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.get(key);
} catch (Exception e) {
logger.error("get key:{} error:", key, e);
RedisPool.returnBrokenResource(jedis);
return result;
}
RedisPool.returnResource(jedis);
return result;
}
/**
* 删除key
* @param key
* @return
*/
public static Long del(String key) {
Jedis jedis = null;
Long result = null;
try {
jedis = RedisPool.getJedis();
result = jedis.del(key);
} catch (Exception e) {
logger.error("del:{} error:", key, e);
RedisPool.returnBrokenResource(jedis);
return result;
}
RedisPool.returnResource(jedis);
return result;
}
}
Redis分布式
Redis分布式算法原理
传统分布式算法
例子假设有一个图片 test.jpg,我们有 3 个服务器, 服务器1 ,服务器2 ,服务器3
4 个 redis 节点
- Redis0
- Redis1
- Redis2
-
Redis3
20个数据
image
这上面 1-20 大家就可以认识是 对应数据 hash 之后的结果,然后对这些结果用 4 取模(因为这里有 4 个 Redis 节点).
1 % 4 = 1 所以将该数据放在 Redis1
2 % 4 = 2 所以将该数据放在 Redis2
3 % 4 = 3 所以将该数据放在 Redis3
4 % 4 = 0 所以将该数据放在 Redis0
同理,后面的其他数据应该这样放置,如下图
image
但是,突然我们发现Redis 的节点不够用了(需要增加节点),或者Redis负载非常低(需要删除节点)。
这里我们来增加一个节点 Redis4,增加之后的数据再节点上的分部如下图:
image
你会发现,只有 redis0 命中了值 20,redis1命中了1,redis2 命中了2,redis3命中了3,命中率为 4/20 = 20%
Consistent hashing一致性算法原理
这个算法有一个环形hash空间的概念,通常hash算法都是将value映射在一个32位的key值当中,那么把数据首尾相接就会形成一个圆形,取值范围为0 ~ 2^32-1,这个圆环就是环形hash空间。如下图:
image
将对象映射到 圆形hash空间
- 我们hash 4个 对象 obj1-obj4
-
通过hash 函数计算出hash 值的key
落在 环形 hash 空间上的情况如图
image
将cache 映射到环形 hash空间
-
将对象和 cache 都映射到同一个hash 空间,并且使用相同的hash 算法,如下图:
image
现在我们就把数据对象和cache 都映射到 hash空间上了,接下来就是要考虑如何将这个对象映射到cache 上面,看下面的图,沿着环形顺时针走,从key1开始,可将obj1 映射到keyA上,obj2 映射到keyC ,obj3映射到keyC,obj4映射到keyB上
image
下面来看看移除和添加cache 节点有什么变化
image
将cacheB移除,obj4就只能顺时针找到 cacheC了,所以移除一个cache节点,影响的是从该cache节点逆时针开始碰到第一个节点的范围对象,环状的其他区域数据节点都不会影响,如图:
image
在 obj2和obj3直接添加一个 cacheD ,如图,我们可以看到obj2 顺时针就会映射到cacheD上,同时受到影响的也是从添加的cache节点逆时针碰到第一个节点的范围
image
从上面我们可以看到,cache 的变动,对应数据对象的影响很小。
Hash倾斜性
但是呢,要知道理想和现实的差距,我们理想的环状空间是均匀分布的,如图:
image
现实却是这样的情况:
如果用上面的hash 算法,大量的数据对象会映射在 A 节点上,而BC节点很少,这样就导致A节点很忙,BC却很是清闲,这就是因为Hash 的倾斜性造成的。
image
虚拟节点
如何解决Hash 倾斜性导致的问题呢?从而引入了虚拟节点
image
比如有 obj1 和 obj 2 两个对象 对其进行 hash 计算,这里增加了 6 个虚拟节点,hash 之后分布落在了 V2,V5上,然后对虚拟节点进行 rehash ,这时 V1,V2映射在 N1上,V3,V4映射在N2上,V5,V6 映射在N3上,obj就映射在了 N1上,obj2映射在N3上。
引入了 虚拟节点,现在 环状空间是什么样子的呢?看下图
image
ABC分别都有对应的影子节点,这时候数据对象的映射就相对均匀了,但是要知道,虚拟节点也有是hash 倾斜性的,这就要在真实节点和虚拟节点之间做一个平衡,分配一个很好的比例,随着节点越来越多,数据越来越多,那么这个分布就会越来越均匀了,在删除节点和添加节点的时候也会把影响降到最小。
Consistent hashing命中率
(1-n/(n + m)) * 100%
- n为服务器台数
- m为新增服务器台数
分布式Redis连接池
public class RedisShardedPool {
private static ShardedJedisPool pool;//sharded jedis连接池
private static Integer maxTotal = Integer.parseInt(PropertiesUtil.getProperty("redis.max.total","20")); //最大连接数
private static Integer maxIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.max.idle","20"));//在jedispool中最大的idle状态(空闲的)的jedis实例的个数
private static Integer minIdle = Integer.parseInt(PropertiesUtil.getProperty("redis.min.idle","20"));//在jedispool中最小的idle状态(空闲的)的jedis实例的个数
private static Boolean testOnBorrow = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.borrow","true"));//在borrow一个jedis实例的时候,是否要进行验证操作,如果赋值true。则得到的jedis实例肯定是可以用的。
private static Boolean testOnReturn = Boolean.parseBoolean(PropertiesUtil.getProperty("redis.test.return","true"));//在return一个jedis实例的时候,是否要进行验证操作,如果赋值true。则放回jedispool的jedis实例肯定是可以用的。
private static String redis1Ip = PropertiesUtil.getProperty("redis1.ip");
private static Integer redis1Port = Integer.parseInt(PropertiesUtil.getProperty("redis1.port"));
private static String redis2Ip = PropertiesUtil.getProperty("redis2.ip");
private static Integer redis2Port = Integer.parseInt(PropertiesUtil.getProperty("redis2.port"));
private static void initPool(){
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxIdle(maxIdle);
config.setMinIdle(minIdle);
config.setTestOnBorrow(testOnBorrow);
config.setTestOnReturn(testOnReturn);
config.setBlockWhenExhausted(true);//连接耗尽的时候,是否阻塞,false会抛出异常,true阻塞直到超时。默认为true。
JedisShardInfo info1 = new JedisShardInfo(redis1Ip,redis1Port,1000*2);
JedisShardInfo info2 = new JedisShardInfo(redis2Ip,redis2Port,1000*2);
List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(2);
jedisShardInfoList.add(info1);
jedisShardInfoList.add(info2);
pool = new ShardedJedisPool(config,jedisShardInfoList, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);
}
static{
initPool();
}
public static ShardedJedis getJedis(){
return pool.getResource();
}
public static void returnBrokenResource(ShardedJedis jedis){
pool.returnBrokenResource(jedis);
}
public static void returnResource(ShardedJedis jedis){
pool.returnResource(jedis);
}
public static void main(String[] args) {
ShardedJedis jedis = pool.getResource();
for(int i =0;i<10;i++){
jedis.set("key"+i,"value"+i);
}
returnResource(jedis);
// pool.destroy();//临时调用,销毁连接池中的所有连接
System.out.println("program is end");
}
}
分布式Redis API工具类
@Slf4j
public class RedisShardedPoolUtil {
/**
* 设置key的有效期,单位是秒
* @param key
* @param exTime
* @return
*/
public static Long expire(String key,int exTime){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.expire(key,exTime);
} catch (Exception e) {
log.error("expire key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
//exTime的单位是秒
public static String setEx(String key,String value,int exTime){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.setex(key,exTime,value);
} catch (Exception e) {
log.error("setex key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static String set(String key,String value){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.set(key,value);
} catch (Exception e) {
log.error("set key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static String getSet(String key,String value){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.getSet(key,value);
} catch (Exception e) {
log.error("getset key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static String get(String key){
ShardedJedis jedis = null;
String result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.get(key);
} catch (Exception e) {
log.error("get key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static Long del(String key){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.del(key);
} catch (Exception e) {
log.error("del key:{} error",key,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static Long setnx(String key,String value){
ShardedJedis jedis = null;
Long result = null;
try {
jedis = RedisShardedPool.getJedis();
result = jedis.setnx(key,value);
} catch (Exception e) {
log.error("setnx key:{} value:{} error",key,value,e);
RedisShardedPool.returnBrokenResource(jedis);
return result;
}
RedisShardedPool.returnResource(jedis);
return result;
}
public static void main(String[] args) {
ShardedJedis jedis = RedisShardedPool.getJedis();
RedisPoolUtil.set("keyTest","value");
String value = RedisPoolUtil.get("keyTest");
RedisPoolUtil.setEx("keyex","valueex",60*10);
RedisPoolUtil.expire("keyTest",60*20);
RedisPoolUtil.del("keyTest");
String aaa = RedisPoolUtil.get(null);
System.out.println(aaa);
System.out.println("end");
}
}
集群和分布式的区别
小饭店原来只有一个厨师,切菜洗菜备料炒菜全干。后来客人多了,厨房一个厨师忙不过来,又请了个厨师,两个厨师都能炒一样的菜,这两个厨师的关系是集群。
为了让厨师专心炒菜,把菜做到极致,又请了个配菜师负责切菜,备菜,备料,厨师和配菜师的关系是分布式,一个配菜师也忙不过来了,
又请了个配菜师,两个配菜师关系是集群