Redis是一款开源的,ANSI C语言编写的,高级键值(key-value)缓存和支持永久存储NoSQL数据库产品。 Redis采用内存(In-Memory)数据集(DataSet) 。 支持多种数据类型。 运行于大多数POSIX系统,如Linux、*BSD、OS X等。 做者: Salvatore Sanfilippo
Redis.io 官网
Download/redis.io 下载
Redisdoc.com 文档
redis.cn 中文网
和Memcache的区别:支持事务、数据类型丰富、支持高可用、支持分布式分片集群node
优势python
优点: 透明性:分布式系统对用户来讲是透明的,一个分布式系统在用户面前的表现就像一个传统的单处理机分时系统,可以让用户没必要了解内部结构就能够使用。 扩展性:分布式系统的最大特色就是可扩展性,他能够根据需求的增长而扩展,能够经过横向扩展使集群的总体性能获得线性提高,也能够经过纵向扩展单台服务器的性能使服务器集群的性能获得提高。 可靠性:分布式系统不容许单点失效的问题存在,它的基本思想是:若是一台服务器坏了,其余服务器接替它的工做,具备持续服务的特性 高性能:高性能是人们设计分布式系统的一个初衷,若是创建了一个透明,灵活,可靠的分布式系统,但他运行起来像蜗牛同样慢,那这个系统就是失败的。 分布式系统的缺点: 1.在节点通讯部分的开销比较大,线程安全也变得复杂,须要保证在完整数据的同时兼顾性能。 2.过度依赖网络,网络信息的丢失或饱和将会抵消分布式的大部分优点。 3.有潜在的数据安全和网络安全问题。
Memcached:
优势:高性能读写、单一数据类型、支持客户端式分布式集群、一致性hash
多核结构、多线程读写性能高。
缺点:无持久化、节点故障可能出现缓存穿透、分布式须要客户端实现、跨机房数据同步困难、
架构扩容复杂度高
Redis:
优势:高性能读写、多数据类型支持、数据持久化、高可用架构、支持自定义虚拟内存、
支持分布式分片集群、单线程读写性能极高
缺点:多线程读写较Memcached慢
Tair:
优势:高性能读写、支持三种存储引擎(ddb、rdb、ldb)、支持高可用、支持分布式分片集群、
支撑了几乎全部淘宝业务的缓存。
缺点:单机状况下,读写性能较其余两种产品较慢
总结:mysql
对三款产品的单用户和多用户的操做的性能的对比,差别git
Memcache是多核的处理模式,能够支持更多的并发能力github
Redis支持少许的并发,而且发起屡次修改或者读取的能力web
在单台主机上装单个redis,并不具有优点!能够在单台机器上装多实例实现更高的并发!!面试
数据高速缓存
web会话缓存(Session Cache)
排行榜应用
消息队列
发布订阅
等
有两个要求:一、去官网下载;二、下载6-12月的版本redis
下载: 解压: 上传至 /data 或者你喜欢的目录 tar xzf redis-3.2.12.tar.gz mv redis-3.2.12 redis 安装: cd redis make 修改环境变量,将src加入到文件中 vim /etc/profile export PATH=/application/mysql/bin/:/data/redis/src:$PATH
使生效 source /etc/profile
启动和简易链接: redis-server & redis-cli
手动建立一个目录,建立配置文件
mkdir /data/6379 vim /data/6379/redis.conf daemonize yes port 6379 logfile /data/6379/redis.log dir /data/6379 dbfilename dump.rdb 127.0.0.1:6379> shutdown 关闭 not connected> exit [root@db01 6379]# redis-server /data/6379/redis.conf 重启,带上配置文件 [root@db03 ~]# netstat -lnp|grep 63 redis-cli shutdown 在命令行关闭 +++++++++++配置文件说明++++++++++++++ redis.conf 是否后台运行: daemonize yes 默认端口: port 6379 日志文件位置 logfile /var/log/redis.log 持久化文件存储位置 dir /data/6379 RDB持久化数据文件: dbfilename dump.rdb +++++++++++++++++++++++++ ------------------------- redis安全配置 (1)redis没有用户概念,redis只有密码 (2)redis默认工做在保护模式下。不容许远程任何用户登陆的(protected-mode) protected-mode yes/no (保护模式,是否只容许本地访问,远程能够登陆,可是没法操做) ---------------------- DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the loopback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1)Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the '--protected-mode no' option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside. ---------------------- (1)Bind :指定IP进行监听 vim /data/6379/redis.conf bind 10.0.0.52 127.0.0.1 (2)增长requirepass {password} vim /data/6379/redis.conf requirepass root 重启生效: redis-cli shutdown 关闭 redis-server /data/6379/redis.conf 带上配置文件启动 ----------验证--------- 方法一: [root@db03 ~]# redis-cli -a root 127.0.0.1:6379> set name zhangsan OK 127.0.0.1:6379> exit 方法二: [root@db03 ~]# redis-cli 127.0.0.1:6379> auth root OK 127.0.0.1:6379> set a b ------------------------ 在线查看和修改配置 CONFIG GET * 获取全部配置信息 ,两行是一个参数 在先修改,不用重启redis,下次登陆就生效,但也不是全部的参数都能在线修改 CONFIG GET requirepass CONFIG SET requirepass 123456 ------------------
RDB 持久化 能够在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
优势:速度快,适合于用作备份,主从复制也是基于RDB持久化功能实现的。
缺点:会有数据丢失 AOF 持久化 记录服务器执行的全部写操做命令,并在服务器启动时,经过从新执行这些命令来还原数据集。
AOF 文件中的命令所有以 Redis 协议的格式来保存,新命令会被追加到文件的末尾。
优势:能够最大程度保证数据不丢
缺点:日志记录量级比较大
RDB的优势算法
RDB是一种表示某个即时点的Redis数据的紧凑文件。
RDB文件适合用于备份。
例如,你可能想要每小时归档最近24小时的RDB文件,天天保存近30天的RDB快照。
这容许你很容易的恢复不一样版本的数据集以容灾。
RDB很是适合于灾难恢复,做为一个紧凑的单一文件,能够被传输到远程的数据中心。
RDB最大化了Redis的性能,由于Redis父进程持久化时惟一须要作的是启动(fork)一个子进程,
由子进程完成全部剩余工做。父进程实例不须要执行像磁盘IO这样的操做。
RDB在重启保存了大数据集的实例时比AOF要快。
RDB缺点sql
当你须要在Redis中止工做(例如停电)时最小化数据丢失,RDB可能不太好。
你能够配置不一样的保存点(save point)来保存RDB文件(例如,至少5分钟和对数据集100次写以后,
可是你能够有多个保存点)。然而,你一般每隔5分钟或更久建立一个RDB快照,
因此一旦Redis由于任何缘由没有正确关闭而中止工做,你就得作好最近几分钟数据丢失的准备了。
RDB须要常常调用fork()子进程来持久化到磁盘。
若是数据集很大的话,fork()比较耗时,
结果就是,当数据集很是大而且CPU性能不够强大的话,Redis会中止服务客户端几毫秒甚至一秒。
AOF也须要fork(),可是你能够调整多久频率重写日志而不会有损(trade-off)持久性(durability)。
RDB普通配置参数
vim /data/6379/redis.conf dir /data/6379 dbfilename dump.rdb save 900 1 save 300 10 save 60 10000 配置分别表示: 900秒(15分钟)内有1个更改 300秒(5分钟)内有10个更改 60秒内有10000个更改
若是不设置上面的条件配置,何时使用save命令,何时才会持久化
RDB持久化高级配置
stop-writes-on-bgsave-error yes rdbcompression yes rdbchecksum yes dbfilename dump.rdb dir ./
以上配置分别表示: 后台备份进程出错时,主进程停不中止写入? 主进程不中止容易形成数据不一致 导出的rdb文件是否压缩 若是rdb的大小很大的话建议这么作 导入rbd恢复时数据时,要不要检验rdb的完整性 验证版本是否是一致 导出来的rdb文件名 rdb的放置路径
AOF持久化配置
appendonly yes
appendfsync always
appendfsync everysec
appendfsync no
是否打开aof日志功能
每1个命令,都当即同步到aof
每秒写1次
写入工做交给操做系统,由操做系统判断缓冲区大小,统一写入到aof.
vim /data/6379/redis.conf
appendonly yes
appendfsync everysec
AOF持久化高级配置
no-appendfsync-on-rewrite yes/no auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb 配置分别表示: 正在导出rdb快照的过程当中,要不要中止同步aof aof文件大小比起上次重写时的大小,增加率100%时重写,缺点:业务开始的时候,会重复重写屡次。 aof文件,至少超过64M时,重写
RDB到AOF的切换
在 Redis 2.2 或以上版本,能够在不重启的状况下,从 RDB 切换到 AOF : 1、为最新的 dump.rdb 文件建立一个备份。 2、将备份放到一个安全的地方。 3、执行如下两条命令: redis-cli> CONFIG SET appendonly yes redis-cli> CONFIG SET save "" 4、确保命令执行以后,数据库的键的数量没有改变。 5、确保写命令会被正确地追加到 AOF 文件的末尾
步骤 3 执行的第一条命令开启了 AOF 功能,Redis 会阻塞直到初始 AOF 文件建立完成为止, 以后 Redis 会继续处理命令请求,并开始将写入命令追加到 AOF 文件末尾。
步骤 3 执行的第二条命令用于关闭 RDB 功能。这一步是可选的,若是你愿意的话,也能够同时使用 RDB 和 AOF 这两种持久化功能。
注意:别忘了在 redis.conf 中打开 AOF 功能! 不然的话, 服务器重启以后, 以前经过 CONFIG SET 设置的配置就会被遗忘, 程序会按原来的配置来启动服务器。
面试题
redis 持久化方式有哪些?有什么区别?
rdb:基于快照的持久化,速度更快,通常用做备份,主从复制也是依赖于rdb持久化功能
aof:以追加的方式记录redis操做日志的文件。能够最大程度的保证redis数据安全,
相似于mysql的binlog
KEYS * 查看KEY支持通配符
DEL 删除给定的一个或多个key
EXISTS 检查是否存在
TYPE 返回键所存储值的类型
EXPIRE\ PEXPIRE 以秒\毫秒设定生存时间
TTL\ PTTL 以秒\毫秒为单位返回生存时间
PERSIST 取消生存实现设置
删
flushdb 清空当前选择的数据库
del mykey mykey2 删除了两个 Keys
改
move mysetkey 1 将当前数据库中的 mysetkey 键移入到 ID 为 1 的数据库中
rename mykey mykey1 将 mykey 更名为 mykey1
renamenx oldkey newkey 若是 newkey 已经存在,则无效
expire mykey 100 将该键的超时设置为 100 秒
persist mykey 将该 Key 的超时去掉,变成持久化的键
查
keys my* 获取当前数据库中全部以my开头的key
exists mykey 若不存在,返回0;存在返回1
select 0 打开 ID 为 0 的数据库
ttl mykey 查看存货时间还剩下多少秒
type mykey 返回mykey对应的值的类型
randomkey 返回数据库中的任意键
形式比喻:name “张山”
定义:
string是redis最基本的类型,一个key对应一个value。
一个键最大能存储512MB。
String类型有以下基本操做(官网):
set
get
incr 计数+1
incrby 能够指定数量,一次性添加
decr 计数-1
decrby 指定数量
mset 同时设置多个键值对
mget
append
getset
setex
setnx
del
setrange
strlen
getrange
应用场景
基本的键值对存储
常规计数:微博数,粉丝数等
游戏应用,如血量、魔法值
增
set mykey "test" 为键设置新值,并覆盖原有值
getset mycounter 0 设置值,取值同时进行
setex mykey 10 "hello" 设置指定 Key 的过时时间为10秒,在存活时间能够获取value
setnx mykey "hello" 若该键不存在,则为键设置新值
mset key3 "zyx" key4 "xyz" 批量设置键
删
del mykey 删除已有键
改
append mykey "hello" 若该键并不存在,返回当前 Value 的长度
该键已经存在,返回追加后 Value的长度
incr mykey 值增长1,若该key不存在,建立key,初始值设为0,增长后结果为1
decrby mykey 5 值减小5
setrange mykey 20 dd 把第21和22个字节,替换为dd, 超过value长度,自动补0
查
exists mykey 判断该键是否存在,存在返回 1,不然返回0
get mykey 获取Key对应的value
strlen mykey 获取指定 Key 的字符长度
ttl mykey 查看一下指定 Key 的剩余存活时间(秒数)
getrange mykey 1 20 获取第2到第20个字节,若20超过value长度,则截取第2个和后面全部的
mget key3 key4 批量获取键
最接近MySQL表结构的数据类型
形式比喻:stu:{id:101,name:zhangsan}
定义:
咱们能够将Redis中的Hashes类型当作具备String Key和String Value的map容器。
因此该类型很是适合于存储值对象的信息。如Username、Password和Age等。
若是Hash中包含不多的字段,那么该类型的数据也将仅占用不多的磁盘空间。
每个Hash能够存储4294967295个键值对。
hash类型有以下操做:
hset
hsetnx
hmset
hdel
del
hincrby
hget
hmget
hlen
hexists
hgetall
hkeys
hvals
应用场景:
存储部分变动的数据,如用户信息等。
127.0.0.1:6379> hset zhangsan name zs 插入
(integer) 1
127.0.0.1:6379> hmset student id 101 name zs age 20 gender male 插入多个
OK
127.0.0.1:6379> hmset stu id 102 name lisi age 21 gender male
OK
127.0.0.1:6379> hmget stu id name age gender 获取指定值
1) "102"
2) "lisi"
3) "21"
4) "male"
127.0.0.1:6379> hgetall stu 获取所有键值对
1) "id"
2) "102"
3) "name"
4) "lisi"
5) "age"
6) "21"
7) "gender"
8) "male"
做业:
MySQL 中 city表中前10行数据,灌入到redis
mysql> select concat("hmset stu_",name," id ",id," name ",name) from t1;
+---------------------------------------------------+
| concat("hmset stu_",name," id ",id," name ",name) |
+---------------------------------------------------+
| hmset stu_zhang3 id 1 name zhang3 |
| hmset stu_li4 id 2 name li4 |
| hmset stu_wang5 id 3 name wang5 |
+---------------------------------------------------+
增
hset myhash field1 "s"
若字段field1不存在,建立该键及与其关联的Hashes, Hashes中,key为field1 ,并设value为s ,若存在会覆盖原value
hsetnx myhash field1 s
若字段field1不存在,建立该键及与其关联的Hashes, Hashes中,key为field1 ,并设value为s, 若字段field1存在,则无效
hmset myhash field1 "hello" field2 "world 一次性设置多个字段
删
hdel myhash field1 删除 myhash 键中字段名为 field1 的字段
del myhash 删除键
改
hincrby myhash field 1 给field的值加1
查
hget myhash field1 获取键值为 myhash,字段为 field1 的值
hlen myhash 获取myhash键的字段数量
hexists myhash field1 判断 myhash 键中是否存在字段名为 field1 的字段
hmget myhash field1 field2 field3 一次性获取多个字段
hgetall myhash 返回 myhash 键的全部字段及其值
hkeys myhash 获取myhash 键中全部字段的名字
hvals myhash 获取 myhash 键中全部字段的值
形式比喻:webchat [m1,m2,m3]
定义:
List类型是按照插入顺序排序的字符串链表。
和数据结构中的普通链表同样,咱们能够在其头部(left)和尾部(right)添加新的元素。
在插入时,若是该键并不存在,Redis将为该键建立一个新的链表。
与此相反,若是链表中全部的元素均被移除,那么该键也将会被从数据库中删除。
List中能够包含的最大元素数量是4294967295。
经常使用操做: lpush lpushx linsert rpush rpushx rpoplpush del lrem ltrim lset rpoplpush lrange lpop lindex 应用场景
微信朋友圈
首先看到的是最新的 消息队列系统 好比sina微博: 在Redis中咱们的最新微博ID使用了常驻缓存,这是一直更新的。
可是作了限制不能超过5000个ID,所以获取ID的函数会一直询问Redis。
只有在start/count参数超出了这个范围的时候,才须要去访问数据库。
系统不会像传统方式那样“刷新”缓存,Redis实例中的信息永远是一致的。
SQL数据库(或是硬盘上的其余类型数据库)只是在用户须要获取“很远”的数据时才会被触发,
而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
127.0.0.1:6379> LPUSH wechat "today is 1"
(integer) 1
127.0.0.1:6379> LPUSH wechat "today is 2"
(integer) 2
127.0.0.1:6379> LPUSH wechat "today is 3"
(integer) 3
127.0.0.1:6379> LPUSH wechat "today is 4"
(integer) 4
127.0.0.1:6379> LPUSH wechat "today is 5"
127.0.0.1:6379> LRANGE wechat 0 -1 第一个到最后一个
1) "today is 5"
2) "today is 4"
3) "today is 3"
4) "today is 2"
5) "today is 1"
增
lpush mykey a b 若key不存在,建立该键及与其关联的List,依次插入a ,b, 若List类型的key存在,则插入value中
lpushx mykey2 e 若key不存在,此命令无效, 若key存在,则插入value中
linsert mykey before a a1 在 a 的前面插入新元素 a1
linsert mykey after e e2 在e 的后面插入新元素 e2
rpush mykey a b 在链表尾部先插入b,在插入a
rpushx mykey e 若key存在,在尾部插入e, 若key不存在,则无效
rpoplpush mykey mykey2 将mykey的尾部元素弹出,再插入到mykey2 的头部(原子性的操做)
删
del mykey 删除已有键
lrem mykey 2 a 从头部开始找,按前后顺序,值为a的元素,删除数量为2个,若存在第3个,则不删除
ltrim mykey 0 2 从头开始,索引为0,1,2的3个元素,其他所有删除
改
lset mykey 1 e 从头开始, 将索引为1的元素值,设置为新值 e,若索引越界,则返回错误信息
rpoplpush mykey mykey 将 mykey 中的尾部元素移到其头部
查
lrange mykey 0 -1 取链表中的所有元素,其中0表示第一个元素,-1表示最后一个元素。
lrange mykey 0 2 从头开始,取索引为0,1,2的元素
lrange mykey 0 0 从头开始,取第一个元素,从第0个开始,到第0个结束
lpop mykey 获取头部元素,而且弹出头部元素,出栈
lindex mykey 6 从头开始,获取索引为6的元素 若下标越界,则返回nil
形式比喻:weibo (m1,m2,m3)
定义:
Set类型看做为没有排序的字符集合。
Set可包含的最大元素数量是4294967295。
若是屡次添加相同元素,Set中将仅保留该元素的一份拷贝。
经常使用操做:
sadd 建立
spop
srem
smove
sismember
smembers
scard
srandmember
sdiff 差集
sdiffstore
sinter 交集
sinterstore
sunion 并集
sunionstore
应用场景:
案例: 在微博应用中,能够将一个用户全部的关注人存在一个集合中,将其全部粉丝存在一个集合。
Redis还为集合提供了求交集、并集、差集等操做,
能够很是方便的实现如共同关注、共同喜爱、二度好友等功能,
对上面的全部集合操做,你还能够使用不一样的命令选择将结果返回给客户端仍是存集到一个新的集合中。
127.0.0.1:6379> sadd lxl pg1 pg2 baoqiang masu marong
(integer) 5
127.0.0.1:6379> sadd jnl baoqiang yufan baobeier zhouxingchi
(integer) 4
127.0.0.1:6379> SUNION lxl jnl 并集
1) "zhouxingchi"
2) "baobeier"
3) "pg2"
4) "yufan"
5) "masu"
6) "baoqiang"
7) "pg1"
8) "marong"
127.0.0.1:6379>
127.0.0.1:6379> SINTER lxl jnl 交集
1) "baoqiang"
127.0.0.1:6379> SDIFF lxl jnl 差集
1) "masu"
2) "pg1"
3) "marong"
4) "pg2"
127.0.0.1:6379> SDIFF jnl lxl 差集
1) "yufan"
2) "zhouxingchi"
3) "baobeier"
增
sadd myset a b c
若key不存在,建立该键及与其关联的set,依次插入a ,b,若key存在,则插入value中,若a 在myset中已经存在,则插入了 d 和 e 两个新成员。
删
spop myset 尾部的b被移出,事实上b并非以前插入的第一个或最后一个成员
srem myset a d f 若f不存在, 移出 a、d ,并返回2
改
smove myset myset2 a 将a从 myset 移到 myset2,
查
sismember myset a 判断 a 是否已经存在,返回值为 1 表示存在。
smembers myset 查看set中的内容
scard myset 获取Set 集合中元素的数量
srandmember myset 随机的返回某一成员
sdiff myset1 myset2 myset3 1和2获得一个结果,拿这个集合和3比较,得到每一个独有的值
sdiffstore diffkey myset myset2 myset3 3个集和比较,获取独有的元素,并存入diffkey 关联的Set中
sinter myset myset2 myset3 得到3个集合中都有的元素
sinterstore interkey myset myset2 myset3 把交集存入interkey 关联的Set中
sunion myset myset2 myset3 获取3个集合中的成员的并集
sunionstore unionkey myset myset2 myset3 把并集存入unionkey 关联的Set中
形式比喻:weibo (socre m1,score m2,score m3)
定义:
Sorted-Sets中的每个成员都会有一个分数(score)与之关联,
Redis正是经过分数来为集合中的成员进行从小到大的排序。
成员是惟一的,可是分数(score)倒是能够重复的。 经常使用操做 zadd zrem zincrby zrange zrank zcard zcount zscore zrangebyscore zremrangebyscore zremrangebyrank zrevrange zrevrangebyscore zrevrangebyscore 应用场景: 排行榜应用,
取TOP N操做 这个需求与上面需求的不一样之处在于,前面操做以时间为权重,
这个是以某个条件为权重,好比按顶的次数排序,这时候就须要咱们的sorted set出马了,
将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,
每次只须要执行一条ZADD命令便可。
127.0.0.1:6379> zadd music 0 fskl 0 fshkl 0 lzlsfs 0 tm 0 ass
(integer) 5
127.0.0.1:6379> ZINCRBY music 1000 fskl
"1000"
127.0.0.1:6379> ZINCRBY music 10000 fshkl
"10000"
127.0.0.1:6379> ZINCRBY music 100000 lzlsfs
"100000"
127.0.0.1:6379> ZINCRBY music 1000000 tm
"1000000"
127.0.0.1:6379> ZINCRBY music 100 ass
"100"
127.0.0.1:6379> ZREVRANGE music 0 -1 withscores
1) "tm"
2) "1000000"
3) "lzlsfs"
4) "100000"
5) "fshkl"
6) "10000"
7) "fskl"
8) "1000"
9) "ass"
10) "100"
127.0.0.1:6379> ZREVRANGE music 0 -1
1) "tm"
2) "lzlsfs"
3) "fshkl"
4) "fskl"
5) "ass"
增
zadd myzset 2 "two" 3 "three" 添加两个分数分别是 2 和 3 的两个成员
删
zrem myzset one two 删除多个成员变量,返回删除的数量
改
zincrby myzset 2 one 将成员 one 的分数增长 2,并返回该成员更新后的分数
查
zrange myzset 0 -1 WITHSCORES 返回全部成员和分数,不加WITHSCORES,只返回成员
zrank myzset one 获取成员one在Sorted-Set中的位置索引值。0表示第一个位置
zcard myzset 获取 myzset 键中成员的数量
zcount myzset 1 2 获取分数知足表达式 1 <= score <= 2 的成员的数量
zscore myzset three 获取成员 three 的分数
zrangebyscore myzset 1 2 获取分数知足表达式 1 < score <= 2 的成员
#-inf 表示第一个成员,+inf最后一个成员
#limit限制关键字
#2 3 是索引号
zrangebyscore myzset -inf +inf limit 2 3 返回索引是2和3的成员
zremrangebyscore myzset 1 2 删除分数 1<= score <= 2 的成员,并返回实际删除的数量
zremrangebyrank myzset 0 1 删除位置索引知足表达式 0 <= rank <= 1 的成员
zrevrange myzset 0 -1 WITHSCORES 按位置索引从高到低,获取全部成员和分数
#原始成员:位置索引从小到大
one 0
two 1
#执行顺序:把索引反转
位置索引:从大到小
one 1
two 0
#输出结果: two
one
zrevrange myzset 1 3 获取位置索引,为1,2,3的成员
#相反的顺序:从高到低的顺序
zrevrangebyscore myzset 3 0 获取分数 3>=score>=0的成员并以相反的顺序输出
zrevrangebyscore myzset 4 0 limit 1 2 获取索引是1和2的成员,并反转位置索引
Redis发布消息一般有两种模式: 队列模式(queuing) 发布-订阅模式(publish-subscribe) 任务队列的好处: 松耦合。 易于扩展。
Redis 发布--订阅
其实从Pub/Sub的机制来看,它更像是一个广播系统,多个Subscriber能够订阅多个Channel,
多个Publisher能够往多个Channel中发布消息。能够这么简单的理解:
Subscriber:收音机,能够收到多个频道,并以队列方式显示
Publisher:电台,能够往不一样的FM频道中发消息
Channel:不一样频率的FM频道
以下图所示,能够做为消息队列或者消息管道。
主要应用:通知、公告
能够将PubSub作成独立的HTTP接口,各应用程序做为Publisher向Channel中发送消息,
Subscriber端收到消息后执行相应的业务逻辑,好比写数据库,显示等等。
主要应用:排行榜、投票、计数。
故名思议,就是能够向不一样的Channel中发送消息,由不一样的Subscriber接收。
主要应用:群聊、聊天。
发布订阅实践
PUBLISH channel msg 将信息 message 发送到指定的频道 channel SUBSCRIBE channel [channel ...] 订阅频道,能够同时订阅多个频道 UNSUBSCRIBE [channel ...] 取消订阅指定的频道, 若是不指定频道,则会取消订阅全部频道 PSUBSCRIBE pattern [pattern ...] 订阅一个或多个符合给定模式的频道,每一个模式以 * 做为匹配符,
好比 it* 匹配所 有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等),
news.* 匹配全部 以 news. 开头的频道( news.it 、 news.global.today 等等),
诸如此类 PUNSUBSCRIBE [pattern [pattern ...]] 退订指定的规则, 若是没有参数则会退订全部规则 PUBSUB subcommand [argument [argument ...]] 查看订阅与发布系统状态 注意:使用发布订阅模式实现的消息队列,当有客户端订阅channel后只能收到后续发布到该频道的消息,
以前发送的不会缓存,必须Provider和Consumer同时在线。
发布订阅例子:
窗口1:
127.0.0.1:6379> SUBSCRIBE baodi
窗口2:
127.0.0.1:6379> PUBLISH baodi "jin tian zhen kaixin!"
订阅多频道:
窗口1:
127.0.0.1:6379> PSUBSCRIBE wang*
窗口2:
127.0.0.1:6379> PUBLISH wangbaoqiang "jintian zhennanshou
消息队列系统对比
客户端在执行订阅命令以后进入了订阅状态
只能接收 SUBSCRIBE 、PSUBSCRIBE、 UNSUBSCRIBE 、PUNSUBSCRIBE 四个命令。
开启的订阅客户端,没法收到该频道以前的消息,由于 Redis 不会对发布的消息进行持久化。
和不少专业的消息队列系统(例如Kafka、RocketMQ)相比,Redis的发布订阅略显粗糙,
例如:没法实现消息堆积和回溯。
但胜在足够简单,若是当前场景能够容忍的这些缺点,也不失为一个不错的选择。
redis事务管理
redis中的事务跟关系型数据库中的事务是一个类似的概念,可是有不一样之处。
关系型数据库事务执行失败后面的sql语句不在执行,而redis中的一条命令执行失败,其他的命令照常执行
redis中开启一个事务是使用multi,至关于begin\start transaction,
exec提交事务,discard取消队列命令(非回滚操做)。
事务命令
DISCARD
取消事务,放弃执行事务块内的全部命令。
EXEC
执行全部事务块内的命令。
MULTI
标记一个事务块的开始。
UNWATCH
取消 WATCH 命令对全部 key 的监视。
WATCH key [key ...] -- 乐观锁
监视一个(或多个) key ,若是在事务执行以前这个(或这些) key 被其余命令所改动,
那么事务将被打断。
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a 1
QUEUED 放入了队列中,并无执行
127.0.0.1:6379> set b 2
QUEUED
127.0.0.1:6379> set c 3
QUEUED
127.0.0.1:6379> exec 提交才回执行
1) OK
2) OK
3) OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set a 10
QUEUED
127.0.0.1:6379> set b 20
QUEUED
127.0.0.1:6379> set c 30
QUEUED
127.0.0.1:6379> DISCARD 取消后,就不执行了
OK
redis事务中的锁机制
举例:我正在买票 Ticket -1 , money -100 而票只有1张, 若是在我multi以后,和exec以前, 票被别人买了,即ticket变成0了. 我该如何观察这种情景,并再也不提交 悲观的想法: 世界充满危险,确定有人和我抢, 给ticket上锁, 只有我能操做. [悲观锁] 乐观的想法: 没有那么多人和我抢,所以,我只须要注意,有没有人更改ticket的值就能够了 [乐观锁]
redis就是乐观锁的机制
服务器管理命令
Info 数据库状态信息
重点关注Memory和Replication Clinet list Client kill ip:port config get * CONFIG GET/SET 动态修改 Dbsize 查看当前库key的个数 FLUSHALL 清空全部数据 包括已经持久化的信息 select 1 根据索引进入相应的库 redis中有16个库, FLUSHDB 清空当前库 MONITOR 监控实时指令 SHUTDOWN 关闭服务器 save将当前数据保存 SLAVEOF host port 主从配置 SLAVEOF NO ONE SYNC 主从同步 ROLE返回主从角色
使用异步复制。
一个主服务器能够有多个从服务器。
从服务器也能够有本身的从服务器。
复制功能不会阻塞主服务器。
能够经过复制功能来让主服务器免于执行持久化操做,由从服务器去执行持久化操做便可。
但仍是建议打开,防止雪崩灾难致使数据丢失
当配置Redis复制功能时,强烈建议打开主服务器的持久化功能。
不然的话,因为延迟等问题,部署的服务应该要避免自动拉起。 为了帮助理解主服务器关闭持久化时自动拉起的危险性,参考如下会致使主从服务器数据所有丢失的例子: 1. 假设节点A为主服务器,而且关闭了持久化。 而且节点B和节点C从节点A复制数据 2. 节点A崩溃,而后由自动拉起服务重启了节点A. 因为节点A的持久化被关闭了,
因此重启以后没有任何数据 3. 节点B和节点C将从节点A复制数据,可是A的数据是空的, 因而就把自身保存的数据副本删除。 在关闭主服务器上的持久化,
并同时开启自动拉起进程的状况下,即使使用Sentinel来实现Redis的高可用性,也是很是危险的。
由于主服务器可能拉起得很是快,
以致于Sentinel在配置的心跳时间间隔内没有检测到主服务器已被重启,
而后仍是会执行上面的数据丢失的流程。 不管什么时候,数据安全都是极其重要的,因此应该禁止主服务器关闭持久化的同时自动拉起。
如下是关于 Redis 复制功能的几个重要方面:
Redis 使用异步复制。 从 Redis 2.8 开始, 从服务器会以每秒一次的频率向主服务器报告复制流(replication stream)的处理进度。
一个主服务器能够有多个从服务器。
不只主服务器能够有从服务器, 从服务器也能够有本身的从服务器, 多个从服务器之间能够构成一个图状结构。
复制功能不会阻塞主服务器: 即便有一个或多个从服务器正在进行初次同步, 主服务器也能够继续处理命令请求。
复制功能也不会阻塞从服务器: 只要在 redis.conf 文件中进行了相应的设置, 即便从服务器正在进行初次同步,
服务器也能够使用旧版本的数据集来处理命令查询。
不过, 在从服务器删除旧版本数据集并载入新版本数据集的那段时间内, 链接请求会被阻塞。
你还能够配置从服务器, 让它在与主服务器之间的链接断开时, 向客户端发送一个错误。
复制功能能够单纯地用于数据冗余(data redundancy), 也能够经过让多个从服务器处理只读命令请求来提高扩展性(scalability):
好比说, 繁重的 SORT 命令能够交给附属节点去运行。
能够经过复制功能来让主服务器免于执行持久化操做: 只要关闭主服务器的持久化功能, 而后由从服务器去执行持久化操做便可。
1. 从服务器向主服务器发送 SYNC 命令。 2. 接到 SYNC 命令的主服务器会调用BGSAVE 命令,建立一个 RDB 文件,并使用缓冲区记录接下来执行的全部写命令。 3. 当主服务器执行完 BGSAVE 命令时,它会向从服务器发送 RDB 文件,而从服务器则会接收并载入这个文件。 4. 主服务器将缓冲区储存的全部写命令发送给从服务器执行。
1、在开启主从复制的时候,使用的是RDB方式的,同步主从数据的 2、同步开始以后,经过主库命令传播的方式,主动的复制方式实现 3、2.8之后实现PSYNC的机制,实现断线重连
在主从服务器完成同步以后,
主服务器每执行一个写命令,它都会将被执行的写命令发送给从服务器执行,
这个操做被称为“命令传播”(command propagate)。
命令传播是一个持续的过程:只要复制仍在继续,命令传播就会一直进行,使得主从服务器的状态能够一直保持一致。
在 Redis 2.8 版本以前,
断线以后重连的从服务器总要执行一次完整重同步(full resynchronization)操做。 从 Redis 2.8 开始,Redis 使用 PSYNC命令代替 SYNC 命令。 PSYNC 比起 SYNC 的最大改进在于 PSYNC 实现了部分重同步(partial resync)
特性:在主从服务器断线而且从新链接的时候,只要条件容许,PSYNC 可让主服务器只向从服务器同步断线期间缺失的数据,
而不用从新向从服务器同步整个数据库。
为了实现主从复制,读写分离的结构,同时,也产生了数据一致性的问题
固然,不止是redis,mysql也会有这个问题
一、在读写分离环境下,客户端向主服务器发送写命令 SET n 10086,
主服务器在执行这个写命令以后,向客户端返回回复,并将这个写命令传播给从服务器。
二、接到回复的客户端继续向从服务器发送读命令 GET n
而且因为网络状态的缘由,客户端的 GET命令比主服务器传播的 SET 命令更快到达了从服务器。 三、由于从服务器键 n 的值还未被更新,因此客户端在从服务器读取到的将是一个错误(过时)的 n值。
主服务器只在有至少 N 个从服务器的状况下,才执行写操做 从 Redis 2.8 开始, 为了保证数据的安全性, 能够经过配置, 让主服务器只在有至少 N 个当前已链接从服务器的状况下, 才执行写命令。 不过, 由于 Redis 使用异步复制, 因此主服务器发送的写数据并不必定会被从服务器接收到, 所以, 数据丢失的可能性仍然是存在的。 经过如下两个参数保证数据的安全: min-slaves-to-write <number of slaves>
最少写入的从库数量,默认没有开启,最少有几台从库完完整整的接收成功了,
不然阻塞 min-slaves-max-lag <number of seconds>
最小延迟时间,从库的网络延迟时间在范围内,才认定是执行成功的
这个特性的运做原理:
从服务器以每秒一次的频率 PING 主服务器一次, 并报告复制流的处理状况。
主服务器会记录各个从服务器最后一次向它发送 PING 的时间。
用户能够经过配置, 指定网络延迟的最大值 min-slaves-max-lag ,
以及执行写操做所需的至少从服务器数量 min-slaves-to-write 。
若是至少有 min-slaves-to-write 个从服务器, 而且这些服务器的延迟值都少于 min-slaves-max-lag秒,
那么主服务器就会执行客户端请求的写操做。
你能够将这个特性看做 CAP 理论中的 C 的条件放宽版本: 尽管不能保证写操做的持久性,
但起码丢失数据的窗口会被严格限制在指定的秒数中。
另外一方面, 若是条件达不到 min-slaves-to-write 和 min-slaves-max-lag 所指定的条件, 那么写操做就不会被执行
主服务器会向请求执行写操做的客户端返回一个错误。
1、环境: 准备两个或两个以上redis实例 mkdir /data/638{0..2} 配置文件示例: vim /data/6380/redis.conf port 6380 daemonize yes pidfile /data/6380/redis.pid loglevel notice logfile "/data/6380/redis.log" dbfilename dump.rdb dir /data/6380 protected-mode no vim /data/6381/redis.conf port 6381 daemonize yes pidfile /data/6381/redis.pid loglevel notice logfile "/data/6381/redis.log" dbfilename dump.rdb dir /data/6381 protected-mode no vim /data/6382/redis.conf port 6382 daemonize yes pidfile /data/6382/redis.pid loglevel notice logfile "/data/6382/redis.log" dbfilename dump.rdb dir /data/6382 protected-mode no 启动: redis-server /data/6380/redis.conf redis-server /data/6381/redis.conf redis-server /data/6382/redis.conf 主节点:6380 从节点:6381、6382 2、开启主从: 6381/6382命令行:
构建 redis-cli -p 6381 SLAVEOF 127.0.0.1 6380 redis-cli -p 6382 SLAVEOF 127.0.0.1 6380
主从复制状态监控: info replication 主从切换: slaveof no one
模拟主库故障
redis-cli -p 6380 shutdown
登录从库
redis-cli -p 6381
info replication 发现主库down了
选择最完整的一台从库,取消从库角色
slaveof no one
将另一台从新构建
6382链接到6381:
[root@db03 ~]# redis-cli -p 6382
127.0.0.1:6382> SLAVEOF no one
127.0.0.1:6382> SLAVEOF 127.0.0.1 6381
在以前,主库宕机以后,咱们经过一系列的手动操做完成了主从的切换
可是,在咱们手动实现的时候有不少不足的地方
一、纯手工--- 咱们不能24小时盯着全部的服务器,在使用监控软件时也会有一系列的等待和延迟
二、选主的问题---不够严谨
三、手工指定新主从后,客户端还不能知道新主,要修改APP中的配置
Redis-Sentinel是Redis官方推荐的高可用性(HA)解决方案,当用Redis作Master-slave的高可用方案时,
假如master宕机了,Redis自己(包括它的不少客户端)都没有实现自动进行主备切换,
而Redis-sentinel自己也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。
Sentinel 是一个监视器,它能够根据被监视实例的身份和状态来判断应该执行何种动做。
监控(Monitoring):
Sentinel 会不断地检查你的主服务器和从服务器是否运做正常。
提醒(Notification):
当被监控的某个 Redis 服务器出现问题时, Sentinel 能够经过 API 向管理员或者其余应用程序发送通知。
自动故障迁移(Automatic failover):
当一个主服务器不能正常工做时, Sentinel 会开始一次自动故障迁移操做,
它会将失效主服务器的其中一个从服务器升级为新的主服务器, 并让失效主服务器的其余从服务器改成复制新的主服务器;
当客户端试图链接失效的主服务器时, 集群也会向客户端返回新主服务器的地址, 使得集群能够使用新主服务器代替失效服务器。
Sentinel 经过用户给定的配置文件来发现主服务器。
Sentinel 会与被监视的主服务器建立两个网络链接:
命令链接用于向主服务器发送命令。
订阅链接用于订阅指定的频道,从而发现监视同一主服务器的其余 Sentinel (细节立刻会介绍)。
redis-sentinel sentinel.conf
############ master1 configure ##############
sentinel monitor master1 127.0.0.1 6379 2
sentinel down-after-milliseconds master1 30000
sentinel parallel-syncs master1 1
sentinel failover-timeout master1 900000
############ master2 configure ##############
sentinel monitor master2 127.0.0.1 12345 5
sentinel down-after-milliseconds master2 50000
sentinel parallel-syncs master2 5
sentinel failover-timeout master2 450000
Sentinel 经过向主服务器发送 INFO 命令来自动得到全部从服务器的地址。
跟主服务器同样,Sentinel 会与每一个被发现的从服务器建立命令链接和订阅链接。
多个sentinel保证系统的高可用,防止一个sentinel宕机
sentinel1 经过发送HELLO 信息来让sentinel2 和 sentinel3发现本身,其余两个sentinel 也会进行相似的操做。
Sentinel 会经过命令链接向被监视的主从服务器发送 “HELLO” 信息,该消息包含 Sentinel 的 IP、端口号、ID 等内容,
以此来向其余 Sentinel 宣告本身的存在。与此同时Sentinel 会经过订阅链接接收其余 Sentinel 的“HELLO” 信息,
以此来发现监视同一个主服务器的其余 Sentinel 。 一个 Sentinel 能够与其余多个 Sentinel 进行链接,
各个 Sentinel 之间能够互相检查对方的可用性, 并进行信息交换。 你无须为运行的每一个 Sentinel 分别设置其余 Sentinel 的地址,
由于 Sentinel 能够经过发布与订阅功能来自动发现正在监视相同主服务器的其余 Sentinel ,
这一功能是经过向频道 __sentinel__:hello 发送信息来实现的。 与此相似, 你也没必要手动列出主服务器属下的全部从服务器, 由于 Sentinel 能够经过询问主服务器来得到全部从服务器的信息。 每一个 Sentinel 会以每两秒一次的频率, 经过发布与订阅功能,
向被它监视的全部主服务器和从服务器的 __sentinel__:hello 频道发送一条信息,
信息中包含了 Sentinel 的 IP 地址、端口号和运行 ID (runid)。 每一个 Sentinel 都订阅了被它监视的全部主服务器和从服务器的 __sentinel__:hello 频道,
查找以前未出现过的 sentinel (looking for unknown sentinels)。
当一个 Sentinel 发现一个新的 Sentinel 时, 它会将新的 Sentinel 添加到一个列表中,
这个列表保存了 Sentinel 已知的, 监视同一个主服务器的全部其余 Sentinel 。 Sentinel 发送的信息中还包括完整的主服务器当前配置(configuration)。
若是一个 Sentinel 包含的主服务器配置比另外一个 Sentinel 发送的配置要旧, 那么这个 Sentinel 会当即升级到新配置上。 在将一个新 Sentinel 添加到监视主服务器的列表上面以前,
Sentinel 会先检查列表中是否已经包含了和要添加的 Sentinel 拥有相同运行 ID 或者相同地址(包括 IP 地址和端口号)的 Sentinel ,
若是是的话, Sentinel 会先移除列表中已有的那些拥有相同运行 ID 或者相同地址的 Sentinel , 而后再添加新 Sentinel 。
Sentinel 之间只会互相建立命令链接,用于进行通讯。由于已经有主从服务器做为发送和接收 HELLO 信息的中介,因此 Sentinel之间不会建立订阅链接。
Sentinel 使用 PING 命令来检测实例的状态:若是实例在指定的时间内没有返回回复,或者返回错误的回复,那么该实例会被 Sentinel 判断为下线。 Redis 的 Sentinel 中关于下线(down)有两个不一样的概念: 主观下线(Subjectively Down, 简称 SDOWN)指的是单个 Sentinel 实例对服务器作出的下线判断。 客观下线(Objectively Down, 简称 ODOWN)指的是多个 Sentinel 实例在对同一个服务器作出 SDOWN 判断,
而且经过 SENTINEL is-master-down-by-addr 命令互相交流以后, 得出的服务器下线判断。
(一个 Sentinel 能够经过向另外一个 Sentinel 发送 SENTINEL is-master-down-by-addr 命令来询问对方是否定为给定的服务器已下线。) 若是一个服务器没有在 master-down-after-milliseconds 选项所指定的时间内,
对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线。 服务器对 PING 命令的有效回复能够是如下三种回复的其中一种: 返回 +PONG 。 返回 -LOADING 错误。 返回 -MASTERDOWN 错误。 若是服务器返回除以上三种回复以外的其余回复, 又或者在指定时间内没有回复 Ping命令, 那么 Sentinel 认为服务器返回的回复无效(non-valid)。 注意, 一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线。 举个例子, 若是 master-down-after-milliseconds 选项的值为 30000 毫秒(30 秒),
那么只要服务器能在每 29 秒以内返回至少一次有效回复, 这个服务器就仍然会被认为是处于正常状态的。 从主观下线状态切换到客观下线状态并无使用严格的法定人数算法(strong quorum algorithm),
而是使用了流言协议: 若是 Sentinel 在给定的时间范围内, 从其余 Sentinel 那里接收到了足够数量的主服务器下线报告,
那么 Sentinel 就会将主服务器的状态从主观下线改变为客观下线。 若是以后其余 Sentinel 再也不报告主服务器已下线, 那么客观下线状态就会被移除。 客观下线条件只适用于主服务器: 对于任何其余类型的 Redis 实例, Sentinel 在将它们判断为下线前不须要进行协商,
因此从服务器或者其余 Sentinel 永远不会达到客观下线条件。 只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其余 Sentinel 推选出,
并对失效的主服务器执行自动故障迁移操做。
一次故障转移操做由如下步骤组成: 一、发现主服务器已经进入客观下线状态。 二、基于Raft leader election 协议 ,进行投票选举 三、若是当选失败,那么在设定的故障迁移超时时间的两倍以后,从新尝试当选。 若是当选成功, 那么执行如下步骤。 四、选出一个从服务器,并将它升级为主服务器。 五、向被选中的从服务器发送 SLAVEOF NO ONE 命令,让它转变为主服务器。 六、经过发布与订阅功能, 将更新后的配置传播给全部其余 Sentinel ,其余 Sentinel 对它们本身的配置进行更新。 七、向已下线主服务器的从服务器发送 SLAVEOF 命令,让它们去复制新的主服务器。 八、当全部从服务器都已经开始复制新的主服务器时, leader Sentinel 终止此次故障迁移操做。 每当一个 Redis 实例被从新配置(reconfigured)
—— 不管是被设置成主服务器、从服务器、又或者被设置成其余主服务器的从服务器
—— Sentinel 都会向被从新配置的实例发送一个 CONFIG REWRITE 命令, 从而确保这些配置会持久化在硬盘里。 Sentinel 使用如下规则来选择新的主服务器: 在失效主服务器属下的从服务器当中, 那些被标记为主观下线、已断线、或者最后一次回复 PING 命令的时间大于五秒钟的从服务器都会被淘汰。 在失效主服务器属下的从服务器当中, 那些与失效主服务器链接断开的时长超过 down-after 选项指定的时长十倍的从服务器都会被淘汰。 在经历了以上两轮淘汰以后剩下来的从服务器中, 咱们选出复制偏移量(replication offset)最大的那个从服务器做为新的主服务器;
若是复制偏移量不可用, 或者从服务器的复制偏移量相同, 那么带有最小运行 ID 的那个从服务器成为新的主服务器。 Sentinel 自动故障迁移的一致性特质 Sentinel 自动故障迁移使用 Raft 算法来选举领头(leader) Sentinel , 从而确保在一个给定的周期(epoch)里, 只有一个领头产生。 这表示在同一个周期中, 不会有两个 Sentinel 同时被选中为领头, 而且各个 Sentinel 在同一个节点中只会对一个领头进行投票。 更高的配置节点老是优于较低的节点, 所以每一个 Sentinel 都会主动使用更新的节点来代替本身的配置。 简单来讲, 咱们能够将 Sentinel 配置看做是一个带有版本号的状态。
一个状态会以最后写入者胜出(last-write-wins)的方式(也便是,最新的配置老是胜出)传播至全部其余 Sentinel 。 举个例子, 当出现网络分割(network partitions)时,
一个 Sentinel 可能会包含了较旧的配置, 而当这个 Sentinel 接到其余 Sentinel 发来的版本更新的配置时,
Sentinel 就会对本身的配置进行更新。 若是要在网络分割出现的状况下仍然保持一致性, 那么应该使用 min-slaves-to-write 选项,
让主服务器在链接的从实例少于给定数量时中止执行写操做, 与此同时, 应该在每一个运行 Redis 主服务器或从服务器的机器上运行 Redis Sentinel 进程。 Sentinel 状态的持久化 Sentinel 的状态会被持久化在 Sentinel 配置文件里面。 每当 Sentinel 接收到一个新的配置, 或者当领头 Sentinel 为主服务器建立一个新的配置时, 这个配置会与配置节点一块儿被保存到磁盘里面。 这意味着中止和重启 Sentinel 进程都是安全的。 Sentinel 在非故障迁移的状况下对实例进行从新配置 即便没有自动故障迁移操做在进行, Sentinel 总会尝试将当前的配置设置到被监视的实例上面。 特别是: 根据当前的配置, 若是一个从服务器被宣告为主服务器, 那么它会代替原有的主服务器, 成为新的主服务器,
而且成为原有主服务器的全部从服务器的复制对象。 那些链接了错误主服务器的从服务器会被从新配置, 使得这些从服务器会去复制正确的主服务器。 不过, 在以上这些条件知足以后, Sentinel 在对实例进行从新配置以前仍然会等待一段足够长的时间,
确保能够接收到其余 Sentinel 发来的配置更新, 从而避免自身由于保存了过时的配置而对实例进行了没必要要的从新配置。
mkdir /data/26380 cp /usr/local/redis/src/redis-sentinel /data/26380 cd /data/26380 Vim sentinel.conf port 26380 dir "/data/26380" sentinel monitor mymaster 127.0.0.1 6380 1 sentinel down-after-milliseconds mymaster 60000 sentinel config-epoch mymaster 0 启动 ./redis-sentinel ./sentinel.conf & 停主库测试
[root@db01 ~]# redis-cli -p 6380
shutdown
[root@db01 ~]# redis-cli -p 6381
info replication
启动原主库(6380),再看状态。
运行一个 Sentinel 所需的最少配置以下所示: sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 60000 sentinel failover-timeout mymaster 180000 sentinel parallel-syncs mymaster 1 sentinel monitor resque 192.168.1.3 6380 4 sentinel down-after-milliseconds resque 10000 sentinel failover-timeout resque 180000 sentinel parallel-syncs resque 5 第一行配置指示 Sentinel 去监视一个名为 mymaster 的主服务器,
这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6379 ,
而将这个主服务器判断为失效至少须要 2 个 Sentinel 赞成 (只要赞成 Sentinel 的数量不达标,自动故障迁移就不会执行)。 不过要注意, 不管你设置要多少个 Sentinel 赞成才能判断一个服务器失效,
一个 Sentinel 都须要得到系统中多数(majority) Sentinel 的支持, 才能发起一次自动故障迁移,
并预留一个给定的配置节点 (configuration Epoch ,一个配置节点就是一个新主服务器配置的版本号)。 换句话说, 在只有少数(minority) Sentinel 进程正常运做的状况下, Sentinel 是不能执行自动故障迁移的。 其余选项的基本格式以下: sentinel <选项的名字> <主服务器的名字> <选项的值> 各个选项的功能以下: down-after-milliseconds 选项指定了 Sentinel 认为服务器已经断线所需的毫秒数。 若是服务器在给定的毫秒数以内, 没有返回 Sentinel 发送的 Ping 命令的回复, 或者返回一个错误,
那么 Sentinel 将这个服务器标记为主观下线(subjectively down,简称 SDOWN )。 不过只有一个 Sentinel 将服务器标记为主观下线并不必定会引发服务器的自动故障迁移:
只有在足够数量的 Sentinel 都将一个服务器标记为主观下线以后, 服务器才会被标记为客观下线(objectively down, 简称 ODOWN ),
这时自动故障迁移才会执行。将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。 parallel-syncs 选项指定了在执行故障转移时, 最多能够有多少个从服务器同时对新的主服务器进行同步,
这个数字越小, 完成故障转移所需的时间就越长。 若是从服务器被设置为容许使用过时数据集(参见对 redis.conf 文件中对 slave-serve-stale-data 选项的说明),
那么你可能不但愿全部从服务器都在同一时间向新的主服务器发送同步请求,
由于尽管复制过程的绝大部分步骤都不会阻塞从服务器, 但从服务器在载入主服务器发来的 RDB 文件时,
仍然会形成从服务器在一段时间内不能处理命令请求: 若是所有从服务器一块儿对新的主服务器进行同步,
那么就可能会形成全部从服务器在短期内所有不可用的状况出现。
你能够经过将这个值设为 1 来保证每次只有一个从服务器处于不能处理命令请求的状态。
配置文件
指定监控master {2表示多少个sentinel赞成} sentinel monitor mymaster 127.0.0.1 6370 2 安全信息 sentinel auth-pass mymaster root 超过15000毫秒后认为主机宕机 sentinel down-after-milliseconds mymaster 15000 当主从切换多久后认为主从切换失败 sentinel failover-timeout mymaster 900000 这两个配置后面的数量主从机须要同样,epoch为master的版本 sentinel leader-epoch mymaster 1 sentinel config-epoch mymaster 1
PING :返回 PONG 。 SENTINEL masters :列出全部被监视的主服务器 SENTINEL slaves <master name> SENTINEL get-master-addr-by-name <master name> : 返回给定名字的主服务器的 IP 地址和端口号。 SENTINEL reset <pattern> : 重置全部名字和给定模式 pattern 相匹配的主服务器。 SENTINEL failover <master name> : 当主服务器失效时, 在不询问其余 Sentinel 意见的状况下, 强制开始一次自动故障迁移。
redis集群
Redis 集群是一个能够在多个 Redis 节点之间进行数据共享的设施(installation)。 Redis 集群不支持那些须要同时处理多个键的 Redis 命令,
由于执行这些命令须要在多个 Redis 节点之间移动数据, 而且在高负载的状况下,
这些命令将下降 Redis 集群的性能, 并致使不可预测的行为。 Redis 集群经过分区(partition)来提供必定程度的可用性(availability):
即便集群中有一部分节点失效或者没法进行通信, 集群也能够继续处理命令请求。 将数据自动切分(split)到多个节点的能力。 当集群中的一部分节点失效或者没法进行通信时, 仍然能够继续处理命令请求的能力。
高性能
基于KEY进行数据拆分 1、在多分片节点中,将16384个槽位,均匀分布到多个分片节点中 2、存数据时,将key作crc16(key),而后和16384进行取模,得出槽位值(0-16383之间) 3、根据计算得出的槽位值,找到相对应的分片节点的主节点,存储到相应槽位上 4、若是客户端当时链接的节点不是未来要存储的分片节点,分片集群会将客户端链接切换至真正存储节点进行数据存储
高可用
在搭建集群时,会为每个分片的主节点,对应一个从节点,实现slaveof的功能,同时当主节点down,实现相似于sentinel的自动failover的功能。
集群数据共享
Redis 集群使用数据分片(sharding)而非一致性哈希(consistency hashing)来实现:
一个 Redis 集群包含 16384 个哈希槽(hash slot),
数据库中的每一个键都属于这 16384 个哈希槽的其中一个,
集群使用公式 CRC16(key) % 16384 来计算键 key 属于哪一个槽,
其中 CRC16(key) 语句用于计算键 key 的 CRC16 校验和 。 节点 A 负责处理 0 号至 5500 号哈希槽。 节点 B 负责处理 5501 号至 11000 号哈希槽。 节点 C 负责处理 11001 号至 16384 号哈希槽。
Redis Cluster
运行机制
全部的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽. 节点的fail是经过集群中超过半数的master节点检测失效时才生效. 客户端与redis节点直连,不须要中间proxy层.客户端不须要链接集群全部节点,链接集群中任何一个可用节点便可 把全部的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->key
集群的复制
为了使得集群在一部分节点下线或者没法与集群的大多数(majority)节点进行通信的状况下, 仍然能够正常运做,
Redis 集群对节点使用了主从复制功能:
集群中的每一个节点都有 1 个至 N 个复制品(replica),
其中一个复制品为主节点(master),
而其他的 N-1 个复制品为从节点(slave)。 在以前列举的节点 A 、B 、C 的例子中, 若是节点 B 下线了, 那么集群将没法正常运行,
由于集群找不到节点来处理 5501 号至 11000 号的哈希槽。 假如在建立集群的时候(或者至少在节点 B 下线以前), 咱们为主节点 B 添加了从节点 B1 ,
那么当主节点 B 下线的时候, 集群就会将 B1 设置为新的主节点, 并让它代替下线的主节点 B ,
继续处理 5501 号至 11000 号的哈希槽, 这样集群就不会由于主节点 B 的下线而没法正常运做了。 不过若是节点 B 和 B1 都下线的话, Redis 集群仍是会中止运做。 集群的复制特性重用了 SLAVEOF 命令的代码,因此集群节点的复制行为和 SLAVEOF 命令的复制行为彻底相同。
集群的故障转移
在集群里面,节点会对其余节点进行下线检测。
当一个主节点下线时,集群里面的其余主节点负责对下线主节点进行故障移。
换句话说,集群的节点集成了下线检测和故障转移等相似 Sentinel 的功能。
由于 Sentinel 是一个独立运行的监控程序,而集群的下线检测和故障转移等功能是集成在节点里面的,
它们的运行模式很是地不一样,因此尽管这二者的功能很类似,但集群的实现没有重用 Sentinel 的代码。
在集群里面执行命令的另种状况
命令发送到了正确的节点:命令要处理的键所在的槽正好是由接收命令的节点负责,那么该节点执行命令,
就像单机 Redis 服务器同样。
命令发送到了错误的节点:接收到命令的节点并不是处理键所在槽的节点,那么节点将向客户端返回一个转向(redirection)错误,
告知客户端应该到哪一个节点去执行这个命令,客户端会根据错误提示的信息,从新向正确的节点发送命令。
转向错误的实现
一、集群中的节点会互相告知对方,本身负责处理哪些槽。
二、集群中的每一个节点都会记录 16384 个槽分别由哪一个节点负责,从而造成一个“槽表”(slot table)。
节点在接收到命令请求时,会经过槽表检查键所在的槽是否由本节点处理:
- 若是是的话,那么节点直接执行命令;
- 若是不是的话,那么节点就从槽表里面提取出正确节点的地址信息,而后返回转向错误
EPEL源安装ruby支持 yum install ruby rubygems -y 使用国内源 gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/ gem install redis -v 3.3.3 gem sources -l 若是没法使用,能够使用aliyun gem sources -a http://mirrors.aliyun.com/rubygems/ gem sources --remove http://rubygems.org/
配置文件
Redis 集群由多个运行在集群模式(cluster mode)下的 Redis 实例组成, 实例的集群模式须要经过配置来开启, 开启集群模式的实例将能够使用集群特有的功能和命令。 如下是一个包含了最少选项的集群配置文件示例: port 7000 cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes 文件中的 cluster-enabled 选项用于开实例的集群模式,
而 cluster-conf-file 选项则设定了保存节点配置文件的路径, 默认值为 nodes.conf 。 节点配置文件无须人为修改, 它由 Redis 集群在启动时建立, 并在有须要时自动进行更新。 要让集群正常运做至少须要三个主节点, 不过在刚开始试用集群功能时,
强烈建议使用六个节点: 其中三个为主节点, 而其他三个则是各个主节点的从节点。 cd /data mkdir cluster-test cd cluster-test mkdir 7000 7001 7002 7003 7004 7005
建立应用
mkdir cluster-test cd cluster-test mkdir 7000 7001 7002 7003 7004 7005 拷贝应用 cp redis.conf redis-server ./7000 启动应用 cd 7000 ./redis-server ./redis.conf
建立集群
{redis_src_home}/src/redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \ 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 给定 redis-trib.rb 程序的命令是 create , 这表示咱们但愿建立一个新的集群。 选项 --replicas 1 表示咱们但愿为集群中的每一个主节点建立一个从节点。
集群客户端
redis-cli -c -p 7000 set foo bar get foo 从新分片 ./redis-trib.rb reshard 127.0.0.1:7000
集群管理
集群主节点状态 redis-cli -p 7000 cluster nodes | grep master 集群从节点状态 redis-cli -p 7000 cluster nodes | grep slave 增长新的节点 ./redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000 删除一个节点 redis-trib del-node ip:port '<node-id>' 删除master节点以前首先要使用reshard移除master的所有slot,而后再删除当前节点 添加一个从节点 ./redis-trib.rb add-node --slave --master-id $[nodeid] 127.0.0.1:7008 127.0.0.1:7000
6个redis实例,通常会放到3台硬件服务器 注:在企业规划中,一个分片的两个节点,分到不一样的物理机,防止硬件主机宕机形成的整个分片数据丢失。 端口号:7000-7005 1、安装集群插件 EPEL源安装ruby支持 yum install ruby rubygems -y 使用国内源 gem sources -l gem sources -a http://mirrors.aliyun.com/rubygems/ gem sources --remove http://rubygems.org/ gem install redis -v 3.3.3 gem sources -l 或者: gem sources -a http://mirrors.aliyun.com/rubygems/ --remove http://rubygems.org/ --- 2、集群节点准备 mkdir /data/700{0..5} vim /data/7000/redis.conf port 7000 daemonize yes pidfile /data/7000/redis.pid loglevel notice logfile "/data/7000/redis.log" dbfilename dump.rdb dir /data/7000 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes vim /data/7001/redis.conf port 7001 daemonize yes pidfile /data/7001/redis.pid loglevel notice logfile "/data/7001/redis.log" dbfilename dump.rdb dir /data/7001 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes vim /data/7002/redis.conf port 7002 daemonize yes pidfile /data/7002/redis.pid loglevel notice logfile "/data/7002/redis.log" dbfilename dump.rdb dir /data/7002 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes vim /data/7003/redis.conf port 7003 daemonize yes pidfile /data/7003/redis.pid loglevel notice logfile "/data/7003/redis.log" dbfilename dump.rdb dir /data/7003 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes vim /data/7004/redis.conf port 7004 daemonize yes pidfile /data/7004/redis.pid loglevel notice logfile "/data/7004/redis.log" dbfilename dump.rdb dir /data/7004 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes vim /data/7005/redis.conf port 7005 daemonize yes pidfile /data/7005/redis.pid loglevel notice logfile "/data/7005/redis.log" dbfilename dump.rdb dir /data/7005 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes 启动节点: redis-server /data/7000/redis.conf redis-server /data/7001/redis.conf redis-server /data/7002/redis.conf redis-server /data/7003/redis.conf redis-server /data/7004/redis.conf redis-server /data/7005/redis.conf [root@db01 ~]# ps -ef |grep redis root 8854 1 0 03:56 ? 00:00:00 redis-server *:7000 [cluster] root 8858 1 0 03:56 ? 00:00:00 redis-server *:7001 [cluster] root 8860 1 0 03:56 ? 00:00:00 redis-server *:7002 [cluster] root 8864 1 0 03:56 ? 00:00:00 redis-server *:7003 [cluster] root 8866 1 0 03:56 ? 00:00:00 redis-server *:7004 [cluster] root 8874 1 0 03:56 ? 00:00:00 redis-server *:7005 [cluster] 3、将节点加入集群管理 redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \ 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 4、集群状态查看 集群主节点状态 redis-cli -p 7000 cluster nodes | grep master 集群从节点状态 redis-cli -p 7000 cluster nodes | grep slave 5、集群节点管理 5.1 增长新的节点 mkdir /data/7006 mkdir /data/7007 vim /data/7006/redis.conf port 7006 daemonize yes pidfile /data/7006/redis.pid loglevel notice logfile "/data/7006/redis.log" dbfilename dump.rdb dir /data/7006 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes vim /data/7007/redis.conf port 7007 daemonize yes pidfile /data/7007/redis.pid loglevel notice logfile "/data/7007/redis.log" dbfilename dump.rdb dir /data/7007 protected-mode no cluster-enabled yes cluster-config-file nodes.conf cluster-node-timeout 5000 appendonly yes redis-server /data/7006/redis.conf redis-server /data/7007/redis.conf 5.2 添加主节点: redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000 5.3 转移slot(从新分片) redis-trib.rb reshard 127.0.0.1:7000
执行以后,会交互提示,输入想移动的槽位:经过本身从新计算得到数值,而后输入
提示输入nodeID (惟一的):
输入从哪些节点上分配:输入all 5.4 添加从节点 redis-trib.rb add-node --slave --master-id bff7d6e603578033f53865de3e55fb2b8c526b60 127.0.0.1:7007 127.0.0.1:7000 6.删除节点 6.1 将须要删除节点slot移动走 redis-trib.rb reshard 127.0.0.1:7000 交互提示输入
一、数量
二、接收者node
三、源节点node
四、输入done,结束 删除一个节点 删除master节点以前首先要使用reshard移除master的所有slot,而后再删除当前节点 主节点删除: redis-trib.rb del-node 127.0.0.1:7006 bff7d6e603578033f53865de3e55fb2b8c526b60 从节点删除: redis-trib.rb del-node 127.0.0.1:7007 2af3da4252ad1a7334d476e1b56498b85a1b488c
注:不一样的架构须要不一样的API支持,因此要先了解使用的是哪一种架构
Redis提供了各种开发语言的API,方便开发语言链接使用Redis。 https://redis.io/clients 官方网站提供了不一样开发语言的API程序。
https://redis.io/clients#python 官网中,给咱们提供了不少种Python链接redis的API,咱们一般选择有“笑脸”而且带有“星号”的使用 这里咱们推荐使用redis-py.
redis-py提供的,python 链接及操做redis方式:
redis-py提供两个类Redis和StrictRedis用于实现Redis的命令。
StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令(好比,SET命令对应与StrictRedis.set方法)。
Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
简单说,官方推荐使用StrictRedis方法。不推荐Redis类,缘由是他和我们在redis-cli操做有些不同,主要不同是下面这三个方面。
安装python3
tar xf Python-3.5.2.tar.xz cd Python-3.5.2 ./configure make && make install https://redis.io/clients 下载redis-py-master.zip unzip redis-py-master.zip cd redis-py-master python3 setup.py install 安装redis-cluser的客户端程序 cd redis-py-cluster-unstable python3 setup.py install
python3 >>>import redis >>>r = redis.StrictRedis(host='localhost', port=6379, db=0,password='root') >>>r.set('lufei', 'guojialei') True >>>r.get('lufei') 'bar'
[root@db01 ~]# redis-server /data/6380/redis.conf [root@db01 ~]# redis-server /data/6381/redis.conf [root@db01 ~]# redis-server /data/6382/redis.conf [root@db01 ~]# redis-sentinel /data/26380/sentinel.conf & -------------------------------- ## 导入redis sentinel包 >>> from redis.sentinel import Sentinel ##指定sentinel的地址和端口号 >>> sentinel = Sentinel([('localhost', 26380)], socket_timeout=0.1) ##测试,获取如下主库和从库的信息
## mymaster 是咱们在配置文件中指定的名字
>>> sentinel.discover_master('mymaster')
>>> sentinel.discover_slaves('mymaster')
##配置读写分离
#写节点
>>> master = sentinel.master_for('mymaster', socket_timeout=0.1)
#读节点
>>> slave = sentinel.slave_for('mymaster', socket_timeout=0.1)
###读写分离测试 key
>>> master.set('oldboy', '123')
>>> slave.get('oldboy')
'123'
(1) redis-py并无提供redis-cluster的支持,去github找了一下,有个叫redis-py-cluster的源码, 可是和redis-py不是一个做者,地址为:https://github.com/Grokzen/redis-py-cluster watch,star,fork还算能够。 (2) 安装 Latest stable release from pypi $ pip install redis-py-cluster or from source $ python setup.py install (3) 使用 >>> from rediscluster import StrictRedisCluster >>> startup_nodes = [{"host": "127.0.0.1", "port": "7000"}] >>> # Note: decode_responses must be set to True when used with python3 >>> rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True) >>> rc.set("foo", "bar") True >>> print(rc.get("foo")) 'bar' 官方的建立redis的时候,均可以添加什么参数。 class redis.StrictRedis(host=‘localhost‘, port=6379, db=0, password=None, socket_timeout=None, connection_pool=None, charset=‘utf-8‘, errors=‘strict‘, decode_responses=False, unix_socket_path=None) connection pool方式 使用connection pool来管理对一个redis server的全部链接,避免每次创建、释放链接的开销。 默认,每一个Redis实例都会维护一个本身的链接池。 能够直接创建一个链接池,而后做为参数 Redis,这样就能够实现多个Redis实例共享一个链接池 StrictRedis Pipeline 是 StrictRedis 类的子类,支持在一个请求里发送缓冲的多个命令。 经过减小客户端和服务器之间往来的数据包,能够大大提升命令组的性能
一、实现Redis Cluseter并实现Python连接集群
实现Redis Cluseter并实现Python连接集群 要求:画出实验拓扑图,标准清楚IP/hostname/做用 (1)实现redis Cluseter高可用分片集群 (2)实现python连接redis Cluster