redis
1、redis五种数据类型操作,重点是string类型和hash类型
Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及sorted set(有序集合)。
1、string(字符串)
Redis字符串是二进制安全的,一个Redis字符串能包含任意类型的数据。例如: 一张JPEG格式的图片或者一个序列化的Ruby对象。一个字符串类型的值最多能存储512M字节的内容。
设置字符串值 set get
SET key value [EX seconds][PX milliseconds] [NX|XX]
EX 设置过期时间,秒,等同于SETEX key seconds value
PX 设置过期时间,毫秒,等同于PSETEX key milliseconds value
NX 键不存在,才能设置,等同于SETNX key value
XX 键存在时,才能设置
设置多个键的字符串值
MSET key value [key value …]
键不存在时,设置字符串值
MSETNX key value [key value …]
注意是原子操作,对多个kv,要不成功都不成功
过期
Redis中可以给Key设置一个生存时间(秒或毫秒),当达到这个时长后,这些键值将会被自动删除
设置多少秒或者毫秒后过期
EXPIRE key seconds
set key val ex 10或者 setex key time(s) value
PEXPIRE key milliseconds
设置在指定Unix时间戳过期
EXPIREAT key timestamp
PEXPIREAT key milliseconds-timestamp
删除过期
PERSIST key
生存时间
Time To Live,Key的剩余生存时间
查看剩余生存时间
TTL key
PTTL key
key存在但没有设置TTL,返回-1
key存在,但还在生存期内,返回剩余的秒或者毫秒
key曾经存在,但已经消亡,返回-2(2.8版本之前返回-1)
key操作
查找键
KEYS pattern
pattern取值
*任意长度字符
? 任意一个字符
[] 字符集合,表示可以是集合中的任意一个
键是否存在
EXISTS key
键重命名
RENAME key newkey
RENAMENX key newkey
键删除
DEL key [key …]
value操作
获取值
GET key
获取多个给定的键的值
MGET key [key …]
返回旧值并设置新值
GETSET key value
如果键不存在,就创建并赋值
字符串长度
STRLEN key
object encoding key 获取value底层存储的数据结构类型
键类型
TYPE key
追加字符串
APPEND key value
如果键存在就追加;如果不存在就等同于SET key value
获取子字符串 索引
GETRANGE key start end
0 3 0 -1(获取所有的内容)
索引值从0开始,负数表示从字符串右边向左数起,
-1表示最右一个字符,负号减轻复杂度
覆盖字符串
SETRANGE key offset value
步长1的增减
INCR key
DECR key
字符串值会被解释成64位有符号的十进制整数来操作,结果依然转成字符串
步长增减 float
INCRBY key decrement
DECRBY key decrement
字符串值会被解释成64位有符号的十进制整数来操作,结果依然转成字符串
字符串类型的内部编码有3种:
int:8个字节的长整型。
embstr:小于等于39个字节的字符串。
raw:大于39个字节的字符串。
Redis会根据当前值的类型和长度决定使用哪种内部编码实现。
2、hash(哈希)
Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
field和value是字符串类型。
一个hash中最多包含2^32-1键值对。
Hash存储了字段和字段值的映射,但字段值只能是字符串类型,也就是说,散列类型不支持嵌套其他的数据类型。一个散列类型键至多可以包含 2的32次方减1 个字段。散列类型很适合存储对象,使用对象类别和ID组成键名,字段名来表示对象属性名,字段值来存储属性值。
命令
设置单个字段
HSET key field value
HSETNX key field value
key的filed不存在的情况下执行,key不存在直接创建
设置多个字段
HMSET key field value [field value …]
返回字段个数
HLEN key
判断字段是否存在
HEXISTS key field
key或者field不存在,返回0
返回字段值
HGET key field
返回多个字段值
HMGET key field [field …]
返回所有的键值对
HGETALL key
返回所有字段名
HKEYS key
返回所有值
HVALS key
在字段对应的值上进行整数的增量计算
HINCRBY key field increment
在字段对应的值上进行浮点数的增量计算
HINCRBYFLOAT key field increment
删除指定的字段
HDEL key field [field …]
举例
HINCRBY numbers x 100
HINCRBY numbers x -50
HINCRBYFLOAT numbers x 3.14
HDEL numbers x
节约内存空间
每创建一个键,它都会为这个键储存一些附加的管理信息(比如这个键的类型,这个键最后一次被访问的时间等等)
所以数据库里面的键越多,redis数据库服务器在储存附加管理信息方面耗费的内存就越多,花在管理数据库键上的CPU也会越多在字段对应的值上进行浮点数的增量计算
不适合hash的情况
使用二进制位操作命令:因为Redis目前支持对字符串键进行SETBIT、GETBIT、BITOP等操作,如果你想使用这些操作,那么只能使用字符串键,虽然散列也能保存二进制数据
使用过期键功能:Redis的键过期功能目前只能对键进行过期操作,而不能对散列的字段进行过期操作,因此如果你要对键值对数据使用过期功能的话,那么只能把键值对储存在字符串里面
3、list(列表)
基于Linked List实现,双向无环链表
元素是字符串类型
列表头尾增删快,中间增删慢,增删元素是常态
元素可以重复出现
最多包含2^32-1元素
列表的索引
从左至右,从0开始
从右至左,从-1开始
list:
队列:L/R R/L
栈: L/L R/R
数组:LINDEX LSET
阻塞:BL BR
命令说明
B block 块,阻塞
L left 左
R right 右
X exist 存在
左右或者头尾压入元素 string set key “abc”
LPUSH key value [value …]
LPUSHX key value
RPUSH key value [value …]
RPUSHX key value
左右或者头尾弹出元素
LPOP key
RPOP key
从一个列表尾部弹出元素压入到另一个列表的头部 string getset
RPOPLPUSH source destination
返回列表中指定范围元素
LRANGE key start stop
LRANGE key 0 -1 表示返回所有元素
获取指定位置的元素
LINDEX key index
设置指定位置元素的值
LSET key index value
列表长度,元素个数 string strlen
LLEN key LRANGE KEY 0 -1
从列表头部开始删除值等于value的元素count次,LIST 可以重复出现
LREM key count value
count > 0 : 从表头开始向表尾搜索,移除与 value 相等的元素,数量为 count
count < 0 : 从表尾开始向表头搜索,移除与 value 相等的元素,数量为 count 的绝对值
count = 0 : 移除表中所有与 value 相等的值
举例
RPUSH listkey c abc c ab 123 ab bj ab redis list
LREM listkey 2 ab
LRANGE listkey 0 -1
去除指定范围 外 元素
LTRIM key start stop
举例
RPUSH listkey c abc c ab 123 ab bj ab redis list
LTRIM listkey 0 -1
LTRIM listkey 1 -1
LTRIM listkey 1 10000
微博的评论最后500条
LTRIM u1234:forumid:comments 0 499
在列表中某个存在的值(pivot)前或后插入元素
LINSERT key BEFORE|AFTER pivot value
key和pivot不存在,不进行任何操作
举例
RPUSH lst Clojure C Lua
LINSERT lst AFTER C Python
LINSERT lst BEFORE C Ruby
阻塞
如果弹出的列表不存在或者为空,就会阻塞
超时时间设置为0,就是永久阻塞,直到有数据可以弹出
如果多个客户端阻塞在同一个列表上,使用First In First Service原则,先到先服务
左右或者头尾阻塞弹出元素
BLPOP key [key …] timeout
BRPOP key [key …] timeout
从一个列表尾部阻塞弹出元素压入到另一个列表的头部
BRPOPLPUSH source destination timeout
4、set(集合)
无序的、去重的
元素是字符串类型
最多包含2^32-1元素
命令
增加一个或多个元素
SADD key member [member …]
如果元素已经存在,则自动忽略
移除一个或者多个元素
SREM key member [member …]
元素不存在,自动忽略
返回集合包含的所有元素
SMEMBERS key
如果集合元素过多,例如百万个,需要遍历,可能会造成服务器阻塞,
生产环境应避免使用
检查给定元素是否存在于集合中
SISMEMBER key member
集合的无序性
SADD friendsnew “peter” “jack” “tom” “john” “may” “ben”
SADD anotherfriends “peter” “jack” “tom” “john” “may” “ben”
SMEMBERS friendsnew
SMEMBERS anotherfriends
注意, SMEMBERS 有可能返回不同的结果,所以,如果需要存储有序且不重复的数据使用有序集合,存储有序可重复的使用列表
随机返回集合中指定个数的,适合抽奖
SRANDMEMBER key [count]
如果 count 为正数,且小于集合基数,那么命令返回一个包含 count 个元素的数组,数组中的元素各不相同。如果 count 大于等于集合基数,那么返回整个集合 最多返回整个集合 conut>=0
如果 count 为负数,那么命令返回一个数组,数组中的元素可能会重复出现多次,而数组的长度为 count 的绝对值 count < 0 长度为count绝对值,元素可能重复
如果 count 为 0,返回空
如果 count 不指定,随机返回一个元素
举例
SADD friend “peter” “jack” “tom” “john” “may” “ben”
SRANDMEMBER friends 3
SRANDMEMBER friends -5
返回集合中元素的个数
SCARD key
键的结果会保存信息,集合长度就记录在里面,所以不需要遍历
随机从集合中移除并返回这个被移除的元素
SPOP key
把元素从源集合移动到目标集合
SMOVE source destination member
差集,具有方向性
SDIFF key [key …],从第一个key的集合中去除其他集合和自己的交集部分
SDIFFSTORE destination key [key …],将差集结果存储在目标key中
举例
SADD number1 123 456 789
SADD number2 123 456 999
SDIFF number1 number2
交集
SINTER key [key …],取所有集合交集部分
SINTERSTORE destination key [key …],将交集结果存储在目标key中
举例
SADD number1 123 456 789
SADD number2 123 456 999
SINTER number1 number2
并集
SUNION key [key …],取所有集合并集
SUNIONSTORE destination key [key …],将并集结果存储在目标key中
举例
SADD number1 123 456 789
SADD number2 123 456 999
SUNION number1 number2
5、sorted set(有序集合)
类似Set集合
有序的、去重的
元素是字符串类型
每一个元素都关联着一个浮点数分值(Score),并按照分值从小到大的顺序排列集合中的元素。分值可以相同
最多包含2^32-1元素
命令
增加一个或多个元素
ZADD key score member [score member …]
如果元素已经存在,则使用新的score
增加一个或多个元素
ZADD key score member [score member …]
如果元素已经存在,则使用新的score
移除一个或者多个元素
ZREM key member [member …]
元素不存在,自动忽略
显示分值
ZSCORE key member
增加或者减少分值
ZINCRBY key increment member
increment为负数就是减少
返回元素的排名(索引)
ZRANK key member
返回元素的逆序排名
ZREVRANK key member
返回指定索引区间元素
ZRANGE key start stop [WITHSCORES]
如果score相同,则按照字典序lexicographical order 排列
默认按照score从小到大,如果需要score从大到小排列,使用ZREVRANGE
返回指定索引区间元素
ZREVRANGE key start stop [WITHSCORES]
如果score相同,则按照字典序lexicographical order 的 逆序 排列
默认按照score从大到小,如果需要score从小到大排列,使用ZRANGE
返回指定分值区间元素
ZRANGEBYSCORE key min max [WITHSCORES][LIMIT offset count]
返回score默认属于[min,max]之间,元素按照score升序排列,score相同字典序
LIMIT中offset代表跳过多少个元素,count是返回几个。类似于Mysql
使用小括号,修改区间为开区间,例如(5、(10、5)
-inf和+inf表示负无穷和正无穷
返回指定分值区间元素
ZREVRANGEBYSCORE key min max [WITHSCORES][LIMIT offset count]
返回score默认属于[min,max]之间,元素按照score降序排列,score相同字典降序
LIMIT中offset代表跳过多少个元素,count是返回几个。类似于Mysql
使用小括号,修改区间为开区间,例如(5、(10、5)
-inf和+inf表示负无穷和正无穷
移除指定排名范围的元素
ZREMRANGEBYRANK key start stop
移除指定分值范围的元素
ZREMRANGEBYSCORE key min max
返回集合中元素个数
ZCARD key
返回指定范围中元素的个数
ZCOUNT key min max 分值score
ZCOUNT fruits 4 7
ZCOUNT fruits (4 7
并集
ZUNIONSTORE destination numkeys key [key …][WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
numkeys指定key的数量,必须
WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
AGGREGATE选项,指定并集结果的聚合方式
SUM:将所有集合中某一个元素的score值之和作为结果集中该成员的score值
MIN:将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
MAX:将所有集合中某一个元素的score值中最大值作为结果集中该成员的score值
交集
ZINTERSTORE destination numkeys key [key …][WEIGHTS weight] [AGGREGATE SUM|MIN|MAX]
numkeys指定key的数量,必须
WEIGHTS选项,与前面设定的key对应,对应key中每一个score都要乘以这个权重
AGGREGATE选项,指定并集结果的聚合方式
SUM:将所有集合中某一个元素的score值之和作为结果集中该成员的score值
MIN:将所有集合中某一个元素的score值中最小值作为结果集中该成员的score值
MAX:将所有集合中某一个元素的score值中最大值作为结果集中该成员的score
2、详述两种持久化原理
持久化
将数据从掉电易失的内存存放到能够永久存储的设备上
Redis为什么需要持久化
Redis的数据都存放在内存中,如果没有配置持久化,redis重启后数据就全丢失了,于是需要开启redis的持久化功能,将数据保存到磁盘上,当redis重启后,可以从磁盘中恢复数据。
Redis持久化方式
RDB(Redis DB) hdfs: fsimage
原理是将Reids在内存中的数据库记录定时dump到磁盘上
AOF(AppendOnlyFile) hdfs : edit logs 关闭的
原理是将Reids的操作日志以追加的方式写入文件
RDB
在默认情况下,Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中
方式:产生一个RDB:
a. 阻塞方式:
客户端中执行save命令
b. 非阻塞方式:(复杂度高?)
bgsave
策略
自动:按照配置文件中的条件满足就执行BGSAVE
save 60 1000,Redis要满足在60秒内至少有1000个键被改动,会自动保存一次
手动:客户端发起SAVE、BGSAVE命令
SAVE命令
redis > save
阻塞Redis服务,无法响应客户端请求
创建新的dump.rdb替代旧文件
BGSAVE命令(异步命令)
redis > bgsave
非阻塞,Redis服务正常接收处理客户端请求
Redis会fork()一个新的子进程来创建RDB文件,子进程处理完后会向父进程发送一个信号,通知它处理完毕
父进程用新的dump.rdb替代旧文件
SAVE 和 BGSAVE 命令
SAVE不用创建新的进程,速度略快
BGSAVE需要创建子进程,消耗额外的内存
SAVE适合停机维护,服务低谷时段
BGSAVE适合线上执行
自动执行
本质上就是BGSAVE
默认配置
save 900 1
save 300 10
save 60 10000
dbfilename dump.rdb
dir /var/lib/redis/6379
只要上面三个条件满足一个,就自动执行备份。
创建RDB文件之后,时间计数器和次数计数器会清零。所以多个条件的效果不是叠加的
优点
完全备份,不同时间的数据集备份可以做到多版本恢复
紧凑的单一文件,方便网络传输,适合灾难恢复
恢复大数据集速度较AOF快
缺点
会丢失最近写入、修改的而未能持久化的数据
fork过程非常耗时,会造成毫秒级不能响应客户端请求
生产环境
创建一个定时任务cron job,每小时或者每天将dump.rdb复制到指定目录
确保备份文件名称带有日期时间信息,便于管理和还原对应的时间点的快照版本
定时任务删除过期的备份
如果有必要,跨物理主机、跨机架、异地备份
AOF
Append only file,采用追加的方式保存
默认文件appendonly.aof
记录所有的写操作命令,在服务启动的时候使用这些命令就可以还原数据库
调整AOF持久化策略,可以在服务出现故障时,不丢失任何数据,也可以丢失一秒的数据。相对于RDB损失小得多
AOF写入机制
AOF方式不能保证绝对不丢失数据
目前常见的操作系统中,执行系统调用write函数,将一些内容写入到某个文件里面时,为了提高效率,系统通常不会直接将内容写入硬盘里面,而是先将内容放入一个内存缓冲区(buffer)里面,等到缓冲区被填满,或者用户执行fsync调用和fdatasync调用时才将储存在缓冲区里的内容真正的写入到硬盘里,未写入磁盘之前,数据可能会丢失
写入磁盘的策略
appendfsync选项,这个选项的值可以是always、everysec或者no
always:服务器每写入一个命令,就调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,也不会丢失任何已经成功执行的命令数据
everysec(默认):服务器每一秒重调用一次fdatasync,将缓冲区里面的命令写入到硬盘。这种模式下,服务器出现故障,最多只丢失一秒钟内的执行的命令数据
no:服务器不主动调用fdatasync,由操作系统决定何时将缓冲区里面的命令写入到硬盘。这种模式下,服务器遭遇意外停机时,丢失命令的数量是不确定的
运行速度:always的速度慢,everysec和no都很快
原有AOF文件 | 重写后的AOF文件 |
---|---|
SELECT 0 | SELECT 0 |
SADD fruits “apple” | SADD fruits “apple” “banana” “cherry” |
SADD fruits “banana” | SET msg “hello world again!” |
SADD fruits “cherry” | RPUSH lst 3 5 7 |
SADD fruits “apple” | |
INCR counter | |
INCR counter | |
DEL counter | |
SET msg “hello world” | |
SET msg “hello world again!” | |
RPUSH lst 1 3 5 | |
RPUSH lst 7 | |
LPOP lst |
AOF重写机制
AOF文件过大
合并重复的操作,AOF会使用尽可能少的命令来记录
重写过程
1、执行AOF重写请求
2、父进程执行fork创建子进程,开销等同于bgsave过程
3.1、主进程fork操作完成后,继续响应其他命令。所有修改命令依然写入AOF缓冲区,并根据appendfsync策略同步到磁盘,保证原有AOF机制正确性。
3.2、由于fork操作运用写时复制技术,子进程只能共享fork操作时的内存数据。由于父进程依然响应命令,redis使用“AOF重写缓冲区”保存这部分新数据,防止新AOF文件生成期间丢失这部分数据。
4、子进程根据内存快照,按照命令合并规则写入到新AOF文件。每次批量写入硬盘数据量由aof-rewrite-incremental-fsync控制,默认是32MB,防止单词刷盘数据过多造成硬盘阻塞。
5.1、新AOF文件写入完成后,子进程发送信号给父进程,父进程更新统计信息。
5.2、父进程把AOF重写缓冲区数据写入到新的AOF文件。
5.3、使用新AOF文件替换老文件,完成AOF重写。
注:如果写入操作的时候出现故障导致命令写半截,可以使用redis-check-aof工具修复
AOF重写触发
手动:客户端向服务器发送BGREWRITEAOF命令
自动:配置文件中的选项,自动执行BGREWRITEAOF命令
auto-aof-rewrite-min-size ,触发AOF重写所需的最小体积:只要在AOF文件的体积大于等于size时,才会考虑是否需要进行AOF重写,这个选项用于避免对体积过小的AOF文件进行重写死循环
auto-aof-rewrite-percentage ,指定触发重写所需的AOF文件体积百分比:当AOF文件的体积大于auto-aof-rewrite-min-size指定的体积,并且超过上一次重写之后的AOF文件体积的percent %时,就会触发AOF重写。(如果服务器刚刚启动不久,还没有进行过AOF重写,那么使用服务器启动时载入的AOF文件的体积来作为基准值)。将这个值设置为0表示关闭自动AOF重写
AOF重写配置项举例
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
appendonly no / yes
当AOF文件大于64MB时候,可以考虑重写AOF文件
只有当AOF文件的增量大于起始size的100%时(就是文件大小翻了一倍),启动重写
默认关闭,请开启
优点
写入机制,默认fysnc每秒执行,性能很好不阻塞服务,最多丢失一秒的数据
重写机制,优化AOF文件
如果误操作了(FLUSHALL等),只要AOF未被重写,停止服务移除AOF文件尾部FLUSHALL命令,重启Redis,可以将数据集恢复到 FLUSHALL 执行之前的状态
缺点
相同数据集,AOF文件体积较RDB大了很多
恢复数据库速度比RDB慢(文本,命令重演)
3、redis哨兵要解决什么问题?原理是什么?
主从复制,解决了读请求的分担,从节点下线,会使得读请求能力有所下降
Master只有一个,写请求单点问题
Sentinel会在Master下线后自动执行Failover操作,提升一台Slave为Master,并让其他Slaves重新成为新Master的Slaves
主从复制+哨兵Sentinel只解决了读性能和高可用问题,但是没有解决写性能问题,解决思路就是,使用多个节点分担,将写请求分散到不同节点处理,分片Sharding:多节点分担的思路就是关系型数据库处理大表的水平切分思路
哨兵功能
监控:哨兵节点定期检测Redis数据节点,其余哨兵节点是否可达;
通知:哨兵节点会将故障转移的结果通知给应用方;
主节点故障转移:实现从节点晋升为主节点并维护后续正确的主从关系;
配置提供者:在Redis哨兵结构中,客户端在初始化的时候连接的哨兵节点集合,从中获取主节点信息。
原理
若干个 Sentinel 节点和 Redis 数据节点,每个 Sentinel 节点会对数据节点和其余 Sentinel 节点进行监控,当它发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,它还会和其他 Sentinel 节点进行“协商”,当大多数 Sentinel 节点都认为主节点不可达时,它们会选举出一个 Sentinel 节点来完成自动故障转移的工作,同时会将这个变化实时通知给 Redis 应用方。整个过程完全是自动的,不需要人工来介入
4、redis集群搭建和使用
1、下载:
http://45.252.224.66/files/200500000CCBFA57/download.redis.io/releases/redis-3.0.0.tar.gz
2、上传,解压
tar -zxf redis.tar.gz
3、编译安装
make
make install PREFIX=/opt/redis3
4、添加REDIS_HOME
export REDIS_HOME=/opt/redis3
export PATH=
P
A
T
H
:
PATH:
PATH:REDIS_HOME/bin
5、复制redis的bin目录五分,一共六份
redis1/redis2/redis3/redis4/redis5/redis6
port 7001 7002 7003 7004 7005 7006
bind 127.0.0.1 192.16.202.101
cluster-enabled yes
daemonize yes
6、安装ruby和rubygems
yum install ruby rubygems -y
7、下载ruby的gem包
https://rubygems.org/downloads/redis-3.0.0.gem
8、安装
gem install redis-3.0.0.gem
9、拷贝~/redis-3.0.0/src/redis-trib.rb到/opt/redis3
cp ~/redis-3.0.0/src/redis-trib.rb /opt/redis3/
10、启动redis1-6
11、执行 ./redis-trib.rb create --replicas 1 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 127.0.0.1:7006
12、客户端的集群连接模式:
./redis-cli -p 7001 -c