文章目录
1.Redis简介
Remote Dictionary Server(远程字典服务器),是一个用C语言编写的、开源的、基于内存运行并支持持久化的、高性能的NoSQL数据库.也是当前热门的NoSQL数据库之一。
2.Redis的特点
支持数据持久化
。Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。支持多种数据结构
。Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。支持数据备份
。Redis支持数据的备份,即master-slave模式的数据备份。
3.redis的启动和关闭方式
- 开启
- 前台启动:
redis-server
关闭此窗口,redis服务关闭 - 后台启动:
redis-server &
- 根据配置文件启动 启动命令 配置文件 &:redis-server & 配置文件
- 关闭
- 任意目录下执行 指令
redis-cli shutdown
(推荐) - kill pid 或者 kill -9 pid
4.Key相关操作
命令 | 说明 |
---|---|
keys * | 查看当前库所有 key |
exists key | 判断某个 key 是否存在 |
type key | 查看key对应的类型 |
del key | 删除指定的 key 数据 |
unlink key | 根据 value 选择非阻塞删除(异步删除) |
expire key seconds | 为给定的 key 设置过期时间.(单位:秒) |
ttl key | 查看还有多少秒过期,-1 表示永不过期,-2 表示已过期 |
select | 切换数据库(一共16个数据库,select+数字) |
dbsize | 查看当前数据库的 key 的数量 |
flushdb | 清空当前库 |
5.redis字符串(String)操作
命令 | 说明 |
---|---|
set key value | 设置键值对 |
mset k1 v1 k2 v2… | 同时设置一个或多个 key-value对 |
setnx key value | 只有在 key 不存在时设置 key 的值 |
msetnx k1 v1 k2 v2… | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在 |
setex key 过期时间 value | 设置键值的同时,设置过期时间,单位秒 |
strlen key | 获取值的长度 |
append key value | 将给定的value追加到原值的末尾, |
incr key | 将 key 中储存的数字值增 1,只能对数字值操作,如果为空,新增值为 1 |
decr key | 将 key 中储存的数字值减 1,只能对数字值操作,如果为空,新增值为-1 |
incrby / decrby key step | 将 key 将 key 中储存的数字值增减。自定义步长 |
get key | 查询对应键值 |
mget k1 k2 k3… | 同时获取一个或多个 value |
getrange key 起始位置 结束位置 | 获得值的范围,类似 java 中的 substring,前包,后包 |
get key value | 以新换旧,设置了新值同时获得旧值 |
6.redis列表(List)操作
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。它的底层实际是个双向链表,对两端的操作性能很高通过索引下标的操作中间的节点性能会较差
命令 | 说明 |
---|---|
lpush key v1 v2 v3 … | 从左边/右边插入一个或多个值 |
lpop/rpop key | 从左边/右边吐出一个值(值在键在,值光键亡 ) |
rpoplpush key1 key2 | 从key1列表右边吐出一个值,插到key2列表左边 |
lrange key start stop | 按照索引下标获得元素(从左到右) |
lindex key index | 按照索引下标获得元素(从左到右) |
llen key | 获得列表长度 |
linsert key before/after value newvalue | 在value的前面/后面插入newvalue插入值 |
lrem key n value | 从左边删除n个 value(从左到右) |
lset key ndex value | 将列表 key 下标为 index的值替换成 value |
7. redis集合(set)操作
Redis set对外提供的功能与 1ist 类似是一个列表的功能,特殊之处在于 set 是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set 是一个很好的选择,并且 set 提供了判断某个成员是否在一个 set集合内的重要接口,这个也是 1ist所不能提供的。
指令 | 说明 |
---|---|
sadd key value1 value2 | 将一个或多个 member 元素加入到集合 key 中,已经存在的 member 元素将被忽略 |
smembers key | 取出该集合的所有值 |
sismember key value | 判断集合key是否为含有该value值,有1,没有 0. |
scard key | 返回该集合的元素个数 |
srem key value1 value2 | 删除集合中的某个元素 |
spop key | 随机从该集合中吐出一个值 |
srandmember key n | 随机从该集合中取出n个值。不会从集合中删除 |
smove <source> <destination> value | 把集合中一个值从一个集合移动到另一个集合 |
sinter key1 key2 | 返回两个集合的交集 元素 |
sunion key1 key2 | 返回两个集合的并集 元素 |
sdiff key1 key2 | 返回两个集合的差集 元素(key1 中的,不包含 key2 中的) |
8.redis哈希(hash)操作
Redis hash 是一个键值对集合,Redis hash 是一个 strimng类型的 field 和 value 的映射表,hash 特别适合用于存储对象,。类似 Java 里面的 Map<String.object>,用户 ID 为查找的 key,存储的 value用户对象包含姓名,年龄,生日等信息,如果用普通的 key/value 结构来存储。
指令 | 说明 |
---|---|
hset key filed value | 给key集合中的field键赋value |
hget key field | 从key1集合field取出 value |
hmset key field1 valuel field2 value2 | 批量设置 hash 的值 |
hexists key field | 査看哈希表 key 中,给定域 field 是否存在 |
hkeys key | 列出该 hash 集合的所有 field |
hvals key | 列出该 hash 集合的所有 value |
hincrby key field increment | 为哈希表 key 中的域 field 的值加上增量 1 -1 |
hsetnx key field value | 将哈希表 key 中的域 field 的值设置为 value,当且仅当域field 不存在 |
9.redis有序集合(zset)操作
Redis 有序集合 zset 与普通集合 set 非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(spore),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复的,因为元素是有序的,所以你也可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。.
指令 | 说明 |
---|---|
zadd key score1 value1 score2 value2… | 将一个或多个 member 元素及其 score 值加入到有序集 key 当中 |
zrange key start stop [withscores] | 返回有序集 key 中,下标在start stop之间的元素,带 WITHSCORES,可以让分数一起和值返回到结果集 |
zrangebyscore key min max [withscores] | 返回有序集 key 中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员.有序集成员按 score 值递增(从小到大)次序排列 |
zrev rangebyscore key max min [withscores] | 同上,改为从大到小排列 |
zincrby key increment value | 为元素的 score 加上增量 |
zrem key value | 删除该集合下,指定值的元素 |
zcount key min max | 统计该集合,分数区间内的元素个数 |
zrank key value | 返回该值在集合中的排名,从0开始 |
10.redis发布订阅
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道。
- 客户端订阅信息
- 服务端发布消息
- redis订阅信息:
SUBSCRIBE channe1 [channel2 channel2...]
- redis发布信息:
publish channe message
11.redis新增的数据类型
10.1Bitmaps
- Bitmaps 本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作
- Bitmaps 单独提供了一套命令, 所以在 Redis 中使用 Bitmaps 和使用字符串的方法不太相同。 可以把 Bitmaps 想象成一个以位为单位的数组, 数组的每个单元只能存储 0 和 1, 数组的下标在 Bitmaps 中叫做偏移量。
setbit key offset value
设置Bitmaps中某个偏移量的值(0或1),offset从0开始
getbit key offset
获取Bitmaps中某个偏移量的值
bitcount key [start end]
统计字符串从 start 字节到 end 字节比特值为 1的数量
10.2HyperLogLog
在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站 PV(PageView 页面访问量),可以使用 Redis 的 incr、incrby 轻松实现。但像 UV(UniqueVisitor 独立访客)、独立 IP 数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题。解决基数问题有很多种方案:
- 数据存储在 MySQL 表中,使用 distinct count 计算不重复个数
- 使用 Redis 提供的 hash、set、bitmaps 等数据结构来处理。
以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的。能否能够降低一定的精度来平衡存储空间?Redis 推出了 HyperLogLog。
什么是基数?
比如数据集 {1, 3, 5, 7, 5, 7, 8},那么这个数据集的基数集为 {1, 3, 5 ,7, 8},基数 (不重复元素) 为 5。 基数估计就是在误差可接受的范围内,快速计算基数。
pfadd key element [element...]
添加指定元系到 HyperLogLog 中pfcount key [key...]
计算 HLL 的近似基数,可以计算多个 HLL,比如用 HLL 存储每天的 UV,计算一周的 UV 可以使用7天的 UV 合并计算即可
pfmerge destkey sourcekey [sourcekey...]
将一个或多个 HLL 合并后的结果存储在另一个 HLL中,比如每月活跃用户可以使用每天的活跃用户来合并计算可得。
10.3Geospatial
Redis 3.2 中增加了对 GEO 类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的 2 维坐标,在地图上就是经纬度。redis 基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度 Hash 等常见操作。
geoadd key longitde latitude member
添加地理位置(经度,纬度,名称)
geopos key member [member...]
获得指定地区的坐标值
geodist key member1 member2 [m|km|ft|mi]
获取两个位置之间的直线距离
- m 表示单位为米[默认值]
- km 表示单位为千米
- mi 表示单位为英里
- t 表示单位为英尺
georadius key longitude latiitude raduis m|km|ft|mi
以给定的经纬度为中心找出某一半径内的元素
11.Jedis
Jedis是使用java来操作redis数据库,与jdbc类似
java操作redis是使用Jedis对象进行操作的:
使用Jedis在项目中引入依赖库:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
通过对象方法操作redis:
public class JedisTest {
public static void main(String[] args) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
//测试是否成功连接redis
String ping = jedis.ping();
System.out.println(ping);//PONG:已连接成功
}
@Test
public void testHash() {
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.hset("user", "age", "20");
String age = jedis.hget("user", "age");
System.out.println(age);//20
}
@Test
public void testZset() {
Jedis jedis = new Jedis("127.0.0.1", 6379);
jedis.zadd("program", 100, "java");
jedis.zadd("program", 300, "php");
jedis.zadd("program", 150, "mysql");
Set<String> programs = jedis.zrange("program", 0, -1);
System.out.println(programs);//[java, mysql, php]
}
}
案例:模拟发送手机验证码:
- 输入手机号,点击发送后随机生成6位数字码,2 分钟有效
- 输入验证码,点击验证,返回成功或失败。
- 每个手机号每天只能输入3次。I
package com.zhxd.test;
import redis.clients.jedis.Jedis;
import java.util.Random;
import java.util.Scanner;
public class TestVerfiCode {
public static void main(String[] args) {
System.out.println("请输入您的手机号:");
Scanner scanner = new Scanner(System.in);
String phoneNum = scanner.next();
codeNormal(phoneNum);
System.out.println("请输入六位验证码");
String code = scanner.next();
verfiCode(phoneNum, code);
}
//随机生成六位数的验证码
public static String randomCode() {
Random random = new Random();
String code ="";
for (int i = 0; i < 6; i++) {
int rand = random.nextInt(9);
code += rand;
}
return code;
}
//设置验证码规则
public static void codeNormal(String phoneNum) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
//设置每个手机每天只能发送3次验证码
String phoneCountKey = phoneNum + ":count";
String count = jedis.get(phoneCountKey);
if(count == null) {
jedis.setex(phoneCountKey, 24*60*60, "1");
}else if(Integer.parseInt(count) <= 2) {
jedis.incr(phoneCountKey);
}else if(Integer.parseInt(count) >=3) {
System.out.println("您的手机号今天已经发送三次验证码,不能再进行验证码发送");
jedis.close();
return;
}
//设置验证码在2分钟有效
String codeKey = "CodeKey:" + phoneNum;
String code = randomCode();
System.out.println(code);
jedis.setex(codeKey, 120, code);
}
//验证验证码
public static void verfiCode(String phoneNum, String code) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
String jcode = jedis.get("CodeKey:"+phoneNum);
System.out.println(jcode);
if(code.equals(jcode)) {
System.out.println("登录成功");
}else {
System.out.println("验证码输入错误,请重新输入");
}
}
}
12.Redis事务
Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。Redis 事务的主要作用就是串联多个命令防止别的命令插队。
12.1Multi、Exec、discard
Redis 事务中有 Multi、Exec 和 discard 三个指令,在 Redis 中,从输入 Multi 命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入 Exec 后,Redis 会将之前的命令队列中的命令依次执行。而组队的过程中可以通过 discard 来放弃组队。
- 案例:
组队成功,成功提交
放弃组队
12.2事务的错误处理
- 组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消
- 如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚
12.3事务冲突的问题
-
一个请求想给金额减 8000
-
一个请求想给金额减 5000
-
一个请求想给金额减 1000
最终我们可以发现,总共金额是 10000,如果请求全部执行,那最后的金额变为 - 4000,很明显不合理
-
悲观锁:悲观锁 (Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 block 直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
-
乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis 就是利用这种 check-and-set 机制实现事务的。
-
WATCH key [key …]
:在执行 multi 之前,先执行 watch key1 [key2],可以监视一个 (或多个) key ,如果在事务执行之前这个 (或这些) key 被其他命令所改动,那么事务将被打断
unwatch
:取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后,EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。 -
redis事务的三大特性:
单独的隔离操作
:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。没有隔离级别的概念
:队列中的命令没有提交之前都不会实际被执行,因为事务提交前任何指令都不会被实际执行。不保证原子性
:事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚 。
12.4商品秒杀案例
- 关键代码:
package com.zhxd.test;
import redis.clients.jedis.Jedis;
public class TestMS {
public static boolean doSecKill(String uid, String prodid) {
//1. 用户id和商品库存id非空判断
if (uid == null || prodid == null) return false;
//2. 连接redis
Jedis jedis = new Jedis("127.0.0.1", 6379);
//3. 拼接key
//3.1库存key
String kcKey = "sk:" + prodid + ":qt";
//3.2秒杀成功的用户key
String userKey = "sk:" + prodid + ":user";
//4. 获取库存 ,如果库存null,秒杀还没开始
if (jedis.get(kcKey) == null) {
System.out.println("秒杀12:00开始,请稍候再试");
jedis.close();
return false;
}
// 5. 判断如果商品数量库存 < 1,则秒杀结束
if (Integer.parseInt(jedis.get(kcKey)) < 1) {
System.out.println("抱歉,商品已被抢光咯~");
jedis.close();
return false;
}
// 6. 判断用户是否重复秒杀
if(jedis.sismember(userKey, uid)) {
System.out.println("不能重复秒杀");
jedis.close();
return false;
}
// 7. 秒杀过程
// 7.1 库存-1
jedis.decr(kcKey);
// 7.2 把秒杀成功用户添加到清单里面
jedis.sadd(userKey, uid);
System.out.println("恭喜!秒杀成功~");
jedis.close();
return true;
}
}
上述代码在并发的条件下会发生超时和超卖
的问题
- 解决超时问题,使用数据库连接池:
- 编写jedis数据库连接池工具类
public class JedisPoolUtil {
private static volatile JedisPool jedisPool = null;
public static JedisPool getJedisPool() {
if(jedisPool == null) {
synchronized (JedisPoolUtil.class) {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(-1);//制一个 pool 可分配多少个 jedis 实例,通过 pool.getResource () 来获取;如果赋值为 - 1,则表示不限制;如果 pool 已经分配了 MaxTotal 个 jedis 实例,则此时 pool 的状态为 exhausted。
jedisPoolConfig.setMaxIdle(32);//控制一个 pool 最多有多少个状态为 idle (空闲) 的 jedis 实例
jedisPoolConfig.setMaxWaitMillis(10*1000);//表示当 borrow 一个 jedis 实例时,最大的等待毫秒数,如果超过等待时间,则直接抛 JedisConnectionException;
jedisPoolConfig.setBlockWhenExhausted(true);
jedisPoolConfig.setTestOnBorrow(true);//获得一个 jedis 实例的时候是否检查连接可用性(ping ());如果为 true,则得到的 jedis 实例均是可用的。
jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379);
}
}
return jedisPool;
}
}
- 修改jedis实例的获取
//通过连接池获得jedis实例
JedisPool jedisPool = JedisPoolUtil.getJedisPool();
Jedis jedis = jedisPool.getResource();
- 使用乐观锁解决超卖的问题
// 7. 秒杀过程
Transaction multi = jedis.multi();
//组队操作
multi.decr(kcKey);
multi.sadd(userKey, uid);
//执行
List<Object> results = multi.exec();
if (results == null || results.size() == 0) {
System.out.println("sorry,秒杀失败了,请重新尝试噢~");
jedis.close();
return false;
}
System.out.println("恭喜!秒杀成功~");
jedis.close();
return true;
13.数据持久化
Redis 提供了 2 个不同形式的持久化方式:
- RDB(Redis DataBase)
- AOF(Append Of File)
- RDB模式
默认方式,不需要进行配置,默认就使用这种机制,在一定的间隔时间中,检测key的变化情况,然后持久化数据
编辑redis配置文件
会自动生成dump.rdb
,发生宕机后,重新启动将会自动从备份文件中加载数据
- AOF模式
可以在 redis.conf 中配置文件名称默认为 appendonly.aof 文件中开启,AOF 文件的保存路径,同 RDB 的路径一致。AOF 和 RDB 同时开启,系统默认取 AOF 的数据(数据不会存在丢失)。AOF 缓冲区根据 AOF 持久化策略 [always,everysec,no] 将操作 sync 同步到磁盘的 AOF 文件中,Redis 服务重启时,会重新 load 加载 AOF 文件中的写操作达到数据恢复的目的。
- AOF 同步频率设置
- appendfsync always:始终同步,每次 Redis 的写入都会立刻记入日志;性能较差但数据完整性比较好。
- . appendfsync everysec:每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
- appendfsync no:redis 不主动进行同步,把同步时机交给操作系统。
14.redis主从复制
主机数据更新后根据配置和策略, 自动同步到备机的 master/slaver 机制,
Master
以写
为主,Slave
以`读``为主,主从复制节点间数据是全量的。
作用:
- 读写分离,性能扩展
- 容灾快速恢复
- 配置一主两从
- 复制两份配置文件
- 修改配置文件的端口号,把6379改为6380,6381等
- 使用三个配置文件启动三个redis服务(
redis-server redis6379.conf redis-server redis6380.conf redis-server redis6381.conf
) - 使用
redis-cli -h 主机号 -p 端口号
连接三个redis服务 - 配置主从关系
- 查看主从关系(
info replication
)
主机宕机
后,重新启动依然是主机从机宕机
后,重新启动角色是主机,需要重新配置主从关系,配置后,会同步主机数据- 主机宕机后,从机可以执行
slaveof no one
上位成为主机
14.1哨兵模式
反客为主:当一个 master 宕机后,后面的 slave 可以立刻升为 master,其后面的 slave 不用做任何修改。用 slaveof no one 指令将从机变为主机。而哨兵模式是反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
哨兵配置:
- 配置好主从关系
- 配置好哨兵服务器的配置文件,只需要一句话
sentinel monitor mymaster(主机名字,随意起一个) 127.0.0.1 6379 1(优先级)
- 启动主机以及从机
- 使用
redis-sentinel 哨兵配置文件(sentinel.conf)
启动哨兵服务器
主机宕机后重新启动会成为从机,而不会重新成为主机
15.redis集群
Redis 集群(包括很多小集群)实现了对 Redis 的水平扩容,即启动 N 个 redis 节点,将整个数据库分布存储在这 N 个节点中,每个节点存储总数据的 1/N,即一个小集群存储 1/N 的数据,每个小集群里面维护好自己的 1/N 的数据。Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。该模式的 redis 集群特点是:分治、分片。
15.1 redis搭建集群(模拟搭建)
- 创建一个三主三从的集群服务器,在linux创建6个redis配置文件,端口号分别是:6379、6380、6381、6389、6390、6391
include /temp/myredis/redis.conf
port 6379
pidfile "/var/run/redis_6379.pid"
dbfilename "dump6379.rdb"
cluster-enabled yes
cluster-config-file nodes-6379.conf
cluster-node-timeout 15000
daemonize yes
- 开启六个redis服务
- 组合六个redis服务,需要进入到redis安装包目录
redis-cli --cluster create --cluster-replicas 1 192.168.11.101:6379 192.168.11.101:6380 192.168.11.101:6381 192.168.11.101:6389 192.168.11.101:6390 192.168.11.101:6391
- 此处不要使用
127.0.0.1
,请使用真实的ip地址 --replicas 1
:采用最简单的方式配置集群,一台主机,一台从机,正好三组
- 使用
redis-cli -c -p 端口号
连接redis服务器 cluster nodes
查看集群信息
- redis cluster 如何分配这六个节点?
- 一个集群至少要有三个主节点
- 选项 –cluster-replicas 1 :表示我们希望为集群中的每个主节点创建一个从节点
- 配原则尽量保证每个主数据库运行在不同的 IP 地址,每个从库和主库不在一个 IP 地址上
15.2什么是 slots
一个 Redis 集群包含 16384 个插槽(hash slot),数据库中的每个键都属于这 16384 个插槽的其中一个。集群使用公式 CRC16 (key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16 (key) 语句用于计算键 key 的 CRC16 校验和 。
集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:节点 A 负责处理 0 号至 5460 号插槽,节点 A 负责处理 0 号至 5460 号插槽,节点 C 负责处理 10923 号至 16383 号插槽。
- 插入单个值:
- 插入多个值
集群对用的命令:
cluster keyslot [key]
:计算当前key属于哪个插槽cluster countkeysinslot [插槽值]
:计算当前插槽有多少个key
15.3 故障恢复
- 如果主节点下线?从节点能否自动升为主节点?注意:15 秒超时
- 主节点恢复后,主从关系会如何?主节点回来变成从机
- 如果所有某一段插槽的主从节点都宕掉,redis 服务是否还能继续?
- 如果某一段插槽的主从都挂掉,而 cluster-require-full-coverage 为 yes ,那么整个集群都挂掉
- 如果某一段插槽的主从都挂掉,而 cluster-require-full-coverage 为 no ,那么,该插槽数据全都不能使用,也无法存储
15.4 jedis操作redis集群
package com.zhxd.test;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
public class TestJedisCluster {
public static void main(String[] args) {
//添加主机以及端口号
HostAndPort hostAndPort = new HostAndPort("168.192.0.122", 6379);
//创建jedis集群对象
JedisCluster jedisCluster = new JedisCluster(hostAndPort);
//操作
jedisCluster.set("k1", "111");
System.out.println(jedisCluster.get("k1"));
//关闭资源
jedisCluster.close();
}
}
15.5 redis集群优缺点
- 优点:
- 实现扩容
- 分摊压力
- 无中心配置相对简单
- 缺点:
- 多键操作是不被支持的
- 多键的 Redis 事务是不被支持的,lua 脚本不被支持
- 由于集群方案出现较晚,很多公司已经采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至 redis cluster,需要整体迁移而不是逐步过渡,复杂度较大