Redis学习笔记

Posted by Think different. on January 25, 2020

1.Redis的安装

step1:在官网上下载Redis的安装包Redis

step2:上传到Linux服务器上并解压

[root@VM_0_6_centos software] tar -zxvf Redis-5.0.7.tar.gz

step3:进入到解压缩后的文件夹,检查是否安装gcc,执行make命令

[root@VM_0_6_centos web]# gcc -v
Using built-in specs.
...
Thread model: posix
gcc version 4.8.5 20150623 (Red Hat 4.8.5-36) (GCC) 

[root@VM_0_6_centos software]# cd Redis-5.0.7/

[root@VM_0_6_centos software]# make

step4:跳过Redis test继续执行make install,安装成功

[root@VM_0_6_centos software] make install #默认路径安装
[root@VM_0_6_centos software] make install PREFIX=/app/web/software/Redis #指定目录安装

step5:查看默认安装目录:

[root@VM_0_6_centos software]#cd /usr/local/bin
[root@VM_0_6_centos software]#ll
-rwxr-xr-x 1 root root 4366872 Jan  5 23:33 Redis-benchmark #性能测试工具,检查服务器性能如何(服务启动起来后执行)
-rwxr-xr-x 1 root root 8125264 Jan  5 23:33 Redis-check-aof #修复有问题的AOF文件
-rwxr-xr-x 1 root root 8125264 Jan  5 23:33 Redis-check-rdb #修复有问题的dump.rdb文件
-rwxr-xr-x 1 root root 4807952 Jan  5 23:33 Redis-cli #客户端,操作入口
lrwxrwxrwx 1 root root      12 Jan  5 23:33 Redis-sentinel -> Redis-server #Redis集群使用
-rwxr-xr-x 1 root root 8125264 Jan  5 23:33 Redis-server #Redis服务器启动命令

ps:安装问题

1.gcc命令未找到:

能上网:

yum install gcc
yum install gcc-c++

不能上网:

CentOS离线安装gcc

2.未检查gcc直接安装编译失败

Jemalloc/jemalloc.h 没有那个文件,先执行make distclean再 make

make distclean
make

2.启动Redis

1.启动Redis-server

cd /usr/local/bin
Redis-server #默认启动Redis
Redis-server /app/web/Redis.conf #以配置文件启动

2.启动Redis-cli

[root@VM_0_6_centos bin]# Redis-cli 
127.0.0.1:6379> ping
PONG #代表Redis已经正常启动

3.关闭Redis-cli

127.0.0.1:6379> shutdown #在终端中关闭
127.0.0.1:6379> quit 
Redis-cli shutdown #单实例关闭
Redis-cli -p 6379 shutdown #多实例关闭

3.Redis安装相关知识

1.Redis默认有16个数据库,类似数组下标从0开始,默认使用0号库,使用命令 select 切换数据库

127.0.0.1:6379> select 8
OK
127.0.0.1:6379[8]> 

2.统一密码管理,所有库都是同样密码,要么OK,要么一个也连不上

3.Redis为什么快

//1.基于内存
//2.单线程,模型简单(队列)
//3.多路IO复用技术
/*多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用select和poll(Linux2.6前)和epoll(Linux 2.6后)函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)。*/

4.BIO,AIO,NIO的区别

BIO:一次连接一个线程

NIO:一次请求一个线程

AIO:一次有效请求一个线程

4.Redis五大数据类型

keys * #查询当前库的所有键
keys ? #查询当前库长度为1的所有键 ?的个数随意,相当于占位符,2个问号查出长度是2的所有键
keys *[1-2] #查询当前库键中含1,2的所有键

127.0.0.1:6379> exists k1 k2 #判断k1,k2是否存在,返回整数
(integer) 2

127.0.0.1:6379> type k1 #查看键的类型
string

127.0.0.1:6379> del k1 #删除键
(integer) 1

expire <key> <seconds> #为键值设置过期时间,单位:秒,如果在过期前重新set这个键的值,key会变为永不过期

ttl <key> #查看还有多少秒过期,-1表示永不过期,-2表示已过期

dbsize #查看当前库key的数量,最多有2^32个key,单个key最大有512MB

flushdb #清空当前库

flushall #通杀全部库

1.String

1.String是Redis最基本的类型,可以理解成与Memcached一模一样的类型,一个key对应一个value。

2.String类型是二进制安全的。意味着Redis的string对象可以包含任何数据。比如jpg图片或者序列化图象。

3.String类型是Redis最基本的数据类型,一个Redis中字符串的value最多可以是512MB

set <key> <value> [Ex 秒] [Px 微秒] #添加键值对。可以选择填写过期时间。
get <key> #查询对应键的值
append <key> <value> #将给定的<value>追加到原值的末尾,返回拼接后字符串的长度
strlen <key> #获得值的长度
setnx <key> <value> #只有在key不存在时,添加键值对
incr <key> #将key中储存的数字值增1。(只能对数字值操作,如果为空,新增值为1)
decr <key> #将key中储存的数字值减1。(只能对数字值操作,如果为空,新增值为-1)
incrby/decrby <key> <步长> #将key中储存的数字值增减,自定义步长

mset <key1> <value1> <key2> <value2>... #同时设置一个或多个键值对,如果少写一个value,所有的键值对都放不进去
mget <key1> <key2> <key3> #同时获取一个或多个value,如果key不存在,显示nil
msetnx <key1> <value1> <key2> <value2>... #同时设置一个或多个键值对,当且仅当所有key都不存在

getrange <key> <起始位置> <end> #截取value 包左包右 如果是负数,代表从后往前倒着数。类似Java中的substring(),区别是substring包左不包右
setrange <key> <起始位置> <value> #用<value>覆写<key>所储存的字符串值,从<起始位置>开始

setex <key> <过期时间> <value> #设置键值的同时,设置过期时间,单位:秒
setget <key> <value> #以新换旧,设置了新值同时获得旧值。类似HashMap.put()
原子性

所谓原子操作就是指不会被线程调度机制打断的操作;这种操作一旦开始,一直运行到结束,中间不会有任何context switch(切换到另一个线程)

(1)在单线程中,能够在单条指令中完成的操作都可以认为是“原子操作”,因为终端只能发生于指令之间。

(2)在多线程中,不能被其他进程(线程)打断的操作就叫原子操作。

Redis单命令的原子性主要得益于Redis的单线程。

Q&A:java中的i++是否是原子操作

不是原子性操作,因为底层操作中分为好几个步骤,可能被其他线程打断。

1)同步(重量锁)

2)volatile(轻量锁)可以解决内存可见性的问题,不能解决原子性操作的问题。不可取

3)JUC AtomicInteger (CAS(compareAndSqapInt)算法)

除了long和double,赋值操作都是原子的。 (64位,计算机先分32位,再分32位)

2.list

1.单键多值

2.Redis列表是简单的字符串列表,按照插入顺序排序,可以添加一个元素到列表的头部或者尾部

3.底层是双向链表,对两端的操作性能很高,通过索引下标操作中间的节点性能会较差

lpush/rpush <key> <value1> <value2> <value3> ... #从左边/右边插入一个/多个值
lpop/rpop <key> #从左边/右边吐出一个值。值在键在,值亡键亡
rpoplpush <key1> <key2> #从<key1>列表右边吐出一个值,插到<key2>的列表左边

lrange <key> <start> <stop># 按照索引下标获得元素(从左到右)。输出顺序从右向左。负号就是从反方向取。 lrange l1 0 -1 从左往右遍历l1
lindex <key> <index> # 按照索引下标获得元素(从左到右)
llen <key> #获得列表长度
linsert <key> before/after <value> <newvalue> #在<value>的前面/后面插入<newvalue>插入值
lrem <key> <n> <value> #n为正数,从左边删除n个值为value的元素(从左往右)。n为负数时,从右边删除(从右到左)。n=0时,将列表中符合value的值全部删除。

3.set

1.Redis set对外提供的功能与list类似是一个列表的功能,特殊之处set可以自动排重(与Java中的set类似),当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

2.Redis的set是string类型的无需集合。底层是一个value为null的hash表,所以添加,删除,查找的复杂度都是O(1)。

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个值,但值不会从集合中删除
sinter <key1> <key2> #返回两个集合的交集元素
sunion <key1> <key2> #返回两个集合的并集元素
sdiff <key1> <key2> #返回两个集合的差集元素,取<key1>中<key2>没有的元素。

4.hash

1.Redis hash 是一个键值对集合

2.Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象

3.类似Java里面的 Map<String ,Object>

key -> Hash(field -> value)

hset <key> <field> <value> #给<key>集合中的<field>键赋值<value>
hget <key> <field> #从<key>集合<field>取出value
hmset <key> <field1> <value1> <field2> <value2> ...#批量设置hash的值
hexisets <key> <field> #查看哈希表key中,给定域field是否存在
hkeys <key> #列出该hash集合的所有field
hvals <key> #列出该hash集合的所有value
hincrby <key> <field> <increment> #为哈希表key中的域field的值加上增量increment
hsetnx <key> <field> <value> #给<key>集合中的<field>键赋值<value>,当且仅当域field不存在

5.zset(sorted set)

1.Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分是可以重复的。

2.因为元素是有序的,所以可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合的中间元素也是非常快的,因此可以使用有序集合作为一个没有重复发成员的智能列表。

zadd <key> <score1> <value1> <score> <value2>... #将一个或多个member元素及其score值加入到有序集合key当中
zrange <key> <start> <stop> [WITHSCORES] #返回有序集key中,下标在<start> <stop> 之间的元素。带WITHSCORES,可以让分数一起和值返回到结果集
zrangebyscore key min max [WITHSCORES] [limit offset count] #返回有序集key中,所有score值介于min和max之间的(包括min和max)的成员。有序集成员按score值递增(从小到大)次序排列。
zrevrangebyscore key max min [WITHSCORES] [limit offset count] #同上,改为从大到小排列
zincrby <key> <increment> <value> #为元素的score加上增量
zrem <key> <value> #删除该集合下,指定值的元素
zcount <key> <min> <max> #统计该集合,分数区间内的元素个数
zrank <key> <value> #返回该值在集合中的排名,从0开始

5.Redis相关配置

Redis配置

6.Redis的Java客户端Jedis

1.连接服务器中的redis的注意事项:

#禁用Linux的防火墙:(CentOS7)
systemctl stop firewalld.service
#redis.conf中注释掉bind 127.0.0.1,protect-mode 设置为no
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
</dependency>

7.Redis事务

1.事务简介

1.Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序的执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

2.Redis事务的主要作用就是串联多个命令防止被别的命令插队。

2.Multi、Exec、discard

1.从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,知直到输入exec后,Redis会将之前的命令队列中的命令依次执行。

2.组队的过程中可以通过discard来放弃组队。

3.事务的错误处理

1.组队中某个命令出现了错误,执行时整个队列都会被取消。(有原子性概念)。

2.如果执行阶段某个命令报错,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚。

4.锁

1.悲观锁(Pessimistic Lock)

select * from t_user for update;

幻读

悲观锁:顾名思义就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block知道它拿到锁。传统的关系型数据库里面就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。

2.乐观锁(Optimistic Lock)

乐观锁:顾名思义,就是很乐观,每次去拿数据的时候都会认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这用check-and-set机制实现事务的。

WATCH key[key ...]
#在执行multi之前,先执watch key1[key2],可以监视一个(或多个)key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断。执行exec返回nil
unwatch
#取消watch命令对所有key的监视。 慎用!!!
#如果在执行watch命令之后,exec命令或discard命令先被执行了的话,那么就不需要再执行unwatch了

5.事务三特性

1.单独的隔离操作

事务中的所有命令都会序列化,按顺序的执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

2.没有隔离级别的概念

队列中的命令没有提交之前都不会实际的执行,因为事务提交前的任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务的更新,在事务外查询不能看到”这儿让人头痛的问题

3.不保证原子性

Redis同一个事务中如果有一条命令执行失败,其后的命令仍然会被执行,没有回滚。

6.链接池(视频中有遗漏)

优点:

1.节省每次连接redis服务带来的损耗,把连接好的实例反复利用。

2.通过参数管理连接的行为。

参数:

MaxTotal:控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了MaxTotal个jedis实例,则此时pool的状态为exhausted
MaxIdle:控制一个pool最多有多少个状态为idle(空闲)的jedis实例;
MaxWaitMillis:表示当borrow一个jedis实例时,最大的等待毫秒数,如果超过等待时间,则直接抛JedisConnectionException;
testOnBorrow:获得一个jedis实例的时候是否检查连接可用性(ping();如果为true,则得到的jedis实例均是可用的;

7.LUA脚本

Lua简介:lua是一个小巧的脚本语言,Lua脚本可以很容易的被C/C++代码调用,也可以反过来调用C/C++的函数,Lua并没有提供强大的库,一个完整的Lua解释器不过200k,所以Lua不适合作为开发独立应用程序的语言使用,而是作为嵌入式脚本语言。

Lua脚本在Redis中的优势

1.将复杂的或者多步的redis操作,写为一个脚本,一次提交给redis执行,减少反复连接的redis的次数,提升性能。

2.Lua脚本是类似redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis事务性的操作。

3.注意redis的Lua脚本功能,只有2.6以上版本的才可以使用。

8.Redis持久化

Redis提供了两个不同形式的持久化方式

1.RDB(Redis DataBase)

1.简介:在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话将的Snapshot快照,它恢复时是将快照文件直接读到内存里。

2.备份是如何执行的

Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的搞笑。RDB的缺点是最后一次持久化的数据可能丢失。

3.关于fork

在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,Linux中引入了“写时复制技术”,一般情况父进程和子进程会公用同一段物理内存,只有进程空间的各段的内容要发生变化时,才会将父进程的内容复制一份给子进程。

4.rdb的保存的文件

在redis.conf中配置文件名称,默认为dump.rdb

# The filename where to dump the DB
dbfilename dump.rdb

rdb文件的保存路径,也可以修改。默认为Redis启动时命令行所在的目录下

# The working directory.
#
# The DB will be written inside this directory, with the filename specified
# above using the 'dbfilename' configuration directive.
#
# The Append Only File will also be created inside this directory.
#
# Note that you must specify a directory here, not a file name.
dir ./

5.rdb的保存策略

#   after 900 sec (15 min) if at least 1 key changed
#   after 300 sec (5 min) if at least 10 keys changed
#   after 60 sec if at least 10000 keys changed

save 900 1
save 300 10
save 60 10000

6.手动保存快照

命令save:只管保存,其他不管,全部阻塞
save vs bgsave
stop-writes-on-bgsave-error yes #当Redis无法写入磁盘的话,直接关掉Redis的写操作
rdbcompression yes #进行rdb保存时,将文件压缩
rdbchecksum yes #在存储快照后,还可以让Redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能

7.rdb的备份和恢复

备份

config get dir 
#1.查询rdb文件的目录
#2.将*.rdb的文件拷贝到别的地方

恢复

#1.关闭Redis
#2.先把备份的文件拷贝到工作目录下
#3.启动Redis,备份数据会直接加载

8.rdb的优缺点

优点:
1.节省磁盘空间
2.恢复速度快

缺点:
1.虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较小号性能
2.在备份周期在一定的间隔时间做一次备份,所以如果Redis意外宕掉的话,就会丢失最后一次快照后的所有修改。

2.AOF(Append Of File)

1.简介

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只许追加文件但不可以改写文件,Redis启动之初会读取该文件重新构建数据,换言之,Redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。

2.参数

appendonly no #AOF默认不开启,需要手动在配置文件中配置
appendfilename "appendonly.aof" #可以在redis.conf中配置文件名称,默认为appendonly.aof

3.AOF文件故障备份

AOF的备份机制和性能虽然和RDB不同,但是备份和恢复的操作同RDB一样,都是拷贝备份文件,需要恢复时再拷贝到Redis工作目录下,启动系统即加载。

如果AOF和RDB同时开启,恢复数据会恢复AOF的数据。

4.AOF文件故障恢复

AOF文件的保存路径同RDB的路径一致。

如果遇到AOF文件损坏,通过以下命令修复

redis-check-aof --fix appendonly.aof

5.AOF同步频率的设置

# If unsure, use "everysec".

# appendfsync always 始终同步,每次Redis的写入都会立刻记入日志
appendfsync everysec #每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失
# appendfsync no #不主动进行同步,把同步时机交给操作系统

6.Rewrite

AOF采用文件追加方式,文件会越来越大,为避免出现此种情况,新增了重写机制当AOF文件的大小超过所设定的阈值时,Redis就是启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令bgrewriteaof

7.Redis如何实现重写?

AOF文件持续增长而过大时,会fork出一条新进程来将文件重写(也是先写临时文件最后在rename),遍历新进程的内存中数据,每条记录有一条set语句。重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似。

8.何时重写

重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担,因此设定Redis要满足一定条件才会进行重写。

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

系统载入时或者上次重写完毕时,Redis会记录此事AOF大小,设为base_size,如果Redis的AOF当前大小>=base_size+base_size*100%(默认)且当前大小>=64mb(默认)的情况下,Redis会对AOF进行重写

9.AOF的优缺点

优点:

备份机制更稳健,丢失数据概率更低。

可读的日志文本,通过操作AOF文件,可以处理误操作

缺点:

比起RDB占用更多的磁盘空间。

恢复备份的速度更慢。

每次读写都同步的话,有一定的性能压力。

存在个别bug,搞成恢复不能。

3.RDB和AOF哪个好

1.官方推荐两个都启用。

2.如果对数据不敏感,可以单独选RDB。

3.不建议单独使用AOF,因为可能出现bug

4.如果只是做纯内存缓存,可以都不用。

9.Redis主从复制

1.主从复制简介

就是主机数据更新后根据配置和策略,自动同步到备机的master/slave机制,Master以写为主,slave以读为主。

2.用处

读写分离,性能拓展。容灾快速恢复。

3.配从(服务器)不配主(服务器)

1.拷贝多个redis.conf文件 include
2.开启daemonize yes
3.Pid文件名字pidfile
4.指定端口port
5.log文件名字
6.Dump.rdb名字dbfilename
7.Appendonly 关掉或者换名字

从服务器配置文件信息:

include /redis/conf/redis.conf
pidfile /var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb

slaveof localhost 6379
info replication #打印主从复制的相关信息
salveof <ip> <port> #成为某个实例的从服务器

4.一主二仆模式演示

1.切入点问题?slave1,slave2是从头开始复制还是从切入点开始复制?比如从k4进来,那之前的123是否也可以复制?(可以)

2.从机是否可以写?set可否?(可以)

3.主机shutdown后情况如何?从机是上位还是原地待命?关系是不变的。原地待命。

4.主机又回来了后,主机新增记录,从机还能否顺利复制? 可以

5.其中一台从机down后情况如何?依照原有他能跟上大部队吗?从机重启后默认是master模式,需要手动设置为slave。可以

5.复制原理

1.每次从机联通后,都会给主机发送sync指令。

2.主机立刻进行存盘操作,发送RDB文件给从机

3.从机收到RDB文件后,进行全盘加载

4.之后每次主机的写操作,都会立刻发送给从机,从机执行相同的指令。

6.薪火相传

主机->从机->从机

1.上一个slave可以是下一个salve的Master,slave同样可以接受其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻master的写压力,去中心化降低风险。

2.用slaveof

3.中途变更转向:会清除之前的数据,重新建立拷贝最新的

4.风险是一旦某个slave宕机,后面的slave都没法备份

7.反客为主

1.当一个master宕机后,后面的slave可以立刻升为master,其后面的slave不用做任何修改。

slaveof no one #将从机变为主机

8.哨兵模式(sentinel)

1.简介

反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。

每一个从机都会有一个哨兵监听主机,如果发现ping不通,另一个哨兵也去ping,如果都ping不通就认为主机挂掉了。

2.配置哨兵

1.调整为一主二仆模式

2.自定义的/myredis目录下新建sentinel.conf文件

3.在配置文件中填写内容

sentinel monitor mymaster 127.0.0.1 6379 1
#哨兵     监控    服务器名称  IP       端口  哨兵同意数量   

4.其中mymaster为监控对象起的服务器名称,1为至少有多少个哨兵同意迁移的数量。

3.启动哨兵
redis-sentinel /myredis/sentinel.conf
5.故障恢复

1.新主登基

从下线的主服务的所有服务里面挑选一个从服务,将其转成主服务。选择的条件依次为:①选择优先级靠前的;②选择偏移量最大的;③选择runid最小的从服务

2.群仆俯首

挑选出新的主服务之后,sentinel向原主服务的从服务发送slaveof新主服务的命令,复制新的master

3.旧主俯首

当已下线的服务重新上线时,sentinel会向其发送slaveof命令,让其成为新主的从

PS:优先级在redis.conf中slave-priority 100

偏移量是指获得原主数据最多的

每个redis实例启动后都会随机生成一个40位的runid

10.Redis集群

1.问题

1.容量不够,redis如何进行扩容

2.并发写操作,redis如何分摊

2.集群简介

1.Redis集群实现了对Redis的水平扩容,即启动N个redis节点,将整个数据库分布存储在这N个节点中,每个节点存储总数据的1/N。

2.Redis集群通过分区(partition)来提供一定程度的可用性(availability):即使集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。

3.安装ruby环境

#能上网
yum install ruby
yum install rubygems
#2.拷贝redis-3.2.0.gem到/opt目录下
#3.执行在opt目录下执行 
gem install --local redis-3.2.0.gem

4.制作6个实例

6379、6380、6381、6389、6390、6391

Redis集群至少有6台服务,3个master,三个slave

5.安装redis cluster配置修改

cluster-enabled yes #打开集群模式
cluster-config-fiel nodes-6379.conf #设定节点配置文件名
cluster-node-timeout 15000 #设定节点失联时间,超过该时间(毫秒),集群自动进行主从切换

6.将6个节点合成一个集群

1.组合之前,请确保所有redis实例启动后,nodes-xxxx.conf文件都生成正常

2.合体:

cd /opt/redis-3.2.5/src
./redis-trib.rb create --replicas 1 ip1:port1....#此处不要用127.0.0.1,请用真实IP地址

3.通过cluster nodes命令查看集群信息

cluster nodes

7.redis cluster如何分配这6个节点

1.一个集群至少要有三个主节点(master)。

2.选项 –replicas 1表示我们希望为集群中的每个主节点创建一个从节点。

3.分配原则尽量保证每个主数据库运行在不同的IP地址,每个从库和主库不在一个IP地址上。

8.slots

1.一个Redis集群包含16384(16*1024)个插槽(hash slot),数据库中的每个键都属于这16384个插槽的其中一个,集群使用公式CRC16(key)%16384来计算键key属于哪个槽,其中CRC16(key)语句用于计算key的CRC16校验和。

2.集群中的每个节点负责处理一部分插槽。举个例子,如果一个集群可以有主节点,其中:

节点A负责处理0到5500号插槽

节点B负责处理5501到11000号插槽

节点C负责处理11001到16383号插槽

9.在集群中录入值

1.在redis-cli每次录入,查询键值,redis都会计算出该key应该送往的插槽,如果不是该客户端对应服务器的插槽,redis会报错,并告知应前往的redis实例地址和端口。

2.redis-cli客户端提供了-c参数实现自动重定向。

redis-cli -c -p 6379 #登入后,再录入,查询键值对可以自动重定向

3.不在一个slot下的键值,是不能使用mget,mset等多键操作的

4.可以通过{}来定义组的概念,从而使key中{}内相同内容的键值对放到一个slot中去。相当于给key起了一个别名。

10.查询集群中的值

CLUSTER KEYSLOT <key> #计算键key应该被放置在哪个槽上
CLUSTER COUNTKEYSINSLOT <slot> #返回槽slot目前包含的键值对数量
CLUSTER GETKEYSINSLOT <slot> <count> #返回count个slot槽中的键

11.故障恢复

1.如果主节点下线,从节点能否自动升为主节点?

在集群中,会自动升为主节点,

2.主节点恢复后,主从关系会如何

会发生转换,原主节点会变为从节点

3.如果所有某一段插槽的主从节点都宕掉,redis服务是否还能继续?

redis.conf中的参数 cluster-require-full-coverage

如果数据必须全有,则redis服务就不能用了。

如果对数据要求不敏感,可以继续用。

12.集群的Jedis开发

public static void main(String[] args) {
    Set<HostAndPort> set = new HashSet<HostAndPort>();
    set.add(new HostAndPort("122.51.219.65",6379));
    JedisCluster jedisCluster = new JedisCluster(set);

    jedisCluster.set("k1","v1");
    System.out.println(jedisCluster.get("k1"));
}

13.Redis集群优缺点

优点:

1.实现扩容

2.分摊压力

3.无中心配置相对简单

缺点:

1.多件操作是不被支持的

2.多键的Redis事务是不被支持的。Lua脚本不被支持。

3.由于集群方案出现较晚,很多公司采用了其他的集群方案,而代理或者客户端分片的方案想要迁移至redis cluster,需要整体迁移而不是逐步过渡,复杂度较大