redis
redis(remote directory server)是一个key-value存储系统,和memcached类似,它支持存储的value类型相对较多,支持string,list,hash,set,sorted set,bitmaps,hyperloglogs,与memcached一样,为了保证效率,数据都是缓存在内存中,区别在于redis会周期性的把数据写入磁盘或把修改写入追加记录文件,并且在此基础上可以实现master-slave同步。
redis与memcached相比:
redis的优势:
- 丰富的(资料形态)操作
hash,list,set,sorted set,bitmaps,haperloglogs - 内建replication及cluster
- 就地更新(in-place update)操作
- 支持持久化(磁盘)
避免雪崩效应
memcached的优势:
- 多线程
善用多核cpu
更少的阻塞操作 - 更少的内存开销
- 更少的内存分配压力
- 可能有更少的内存碎片
Nosql
我们都知道redis属于Nosql体系,而redis还属于redis中的KV Nosql体系,常见的Nosql体系:
- KV NoSQL:redis memcached
- Column Family NoSQL:HBase
- Documentation NoSQL:MongoDB
- Graph NoSQL:Neo4j
redis基本应用
- redis-server:redis server主程序
- redis-cli:redis client
- redis-benchmark:redis 压力测试
- redis-check-dump & redis-check-aof:redis rdb与aof检测工具
redis安装
redis官网:https://redis.io/download
1 | ~]# tar xf redis-3.2.9.tar.gz |
2 | ~]# cd redis-3.2.9 |
3 | ~]# make |
4 | ~]# cd src |
5 | ~]# make install |
6 | ~]# cp ../redis.conf /etc/redis.conf |
redis基本配置:
1 | ~]# vim /etc/redis.conf |
2 | bind 127.0.0.1 |
3 | protected-mode yes |
4 | port 6379 |
5 | tcp-backlog 511 |
6 | timeout 0 |
7 | tcp-keepalive 300 |
8 | daemonize yes |
9 | supervised no |
10 | pidfile "/var/run/redis_6379.pid" |
11 | loglevel notice |
12 | logfile "/var/log/redis/redis.log" |
13 | databases 16 |
14 | ~]# redis-server /etc/redis.conf |
redis操作命令
key pattern查询相应的key
1 | 1)redis允许模糊查询key 有3个通配符 *、?、[] |
2 | 2)randomkey:返回随机key |
3 | 3)type key:返回key存储的类型 |
4 | 4)exists key:判断某个key是否存在 |
5 | 5)del key:删除key |
6 | 6)rename key newkey:改名 |
7 | 7)renamenx key newkey:如果newkey不存在则修改成功 |
8 | 8)move key 1:将key移动到1数据库 |
9 | 9)ttl key:查询key的生命周期(秒) |
10 | 10)expire key 整数值:设置key的生命周期以秒为单位 |
11 | 11)pexpire key 整数值:设置key的生命周期以毫秒为单位 |
12 | 12)pttl key:查询key 的生命周期(毫秒) |
13 | 13)perisist key:把指定key设置为永久有效 |
字符串类型的操作
1 | 1)set key value [ex 秒数] [px 毫秒数] [nx/xx] |
2 | 如果ex和px同时写,则以后面的有效期为准 |
3 | nx:如果key不存在则建立 |
4 | xx:如果key存在则修改其值 |
5 | 2)get key:取值 |
6 | 3)mset key1 value1 key2 value2 一次设置多个值 |
7 | 4)mget key1 key2 :一次获取多个值 |
8 | 5)setrange key offset value:把字符串的offset偏移字节改成value |
9 | 如果偏移量 > 字符串长度,该字符自动补0x00 |
10 | 6)append key value :把value追加到key 的原值上 |
11 | 7)getrange key start stop:获取字符串中[start, stop]范围的值 |
12 | 对于字符串的下标,左数从0开始,右数从-1开始 |
13 | 注意:当start>length,则返回空字符串 |
14 | 当stop>=length,则截取至字符串尾 |
15 | 如果start所处位置在stop右边,则返回空字符串 |
16 | 8)getset key nrevalue:获取并返回旧值,在设置新值 |
17 | 9)incr key:自增,返回新值,如果incr一个不是int的value则返回错误,incr一个不存在的key,则设置key为1 |
18 | 10)incrby key 2:跳2自增 |
19 | 11)incrbyfloat by 0.7: 自增浮点数 |
20 | 12)setbit key offset value:设置offset对应二进制上的值,返回该位上的旧值 |
21 | 注意:如果offset过大,则会在中间填充0 |
22 | offset最大到多少 |
23 | 2^32-1,即可推出最大的字符串为512M |
24 | 13)bitop operation destkey key1 [key2..] |
25 | 对key1 key2做opecation并将结果保存在destkey上 |
26 | opecation可以是AND OR NOT XOR |
27 | 14)strlen key:取指定key的value值的长度 |
28 | 15)setex key time value:设置key对应的值value,并设置有效期为time秒 |
链表操作
redis的list类型其实就是每一个子元素都是string类型的双向链表,链表的最大的长度是2^32,list既可以做栈,也可以做队列。
1 | 1)lpush key value:把值插入到链表头部 |
2 | 2)rpush key value:把值插入到链表尾部 |
3 | 3)lpop key :返回并删除链表头部元素 |
4 | 4)rpop key: 返回并删除链表尾部元素 |
5 | 5)lrange key start stop:返回链表中[start, stop]中的元素 |
6 | 6)lrem key count value:从链表中删除value值,删除count的绝对值个value后结束 |
7 | count > 0 从表头删除 count < 0 从表尾删除 count=0 全部删除 |
8 | 7)ltrim key start stop:剪切key对应的链接,切[start, stop]一段并把改制重新赋给key |
9 | 8)lindex key index:返回index索引上的值 |
10 | 9)llen key:计算链表的元素个数 |
11 | 10)linsert key after|before search value:在key 链表中寻找search,并在search值之前|之后插入value |
12 | 11)rpoplpush source dest:把source 的末尾拿出,放到dest头部,并返回单元值 |
13 | 12)brpop,blpop key timeout:等待弹出key的尾/头元素 |
14 | timeout为等待超时时间,如果timeout为0则一直等待下去 |
hashes类型操作
hash是string类型的field和value的映射表,hash特别适合于存储对象,将一个对象存储在hash类型会占用更少的内存,并且方便的存取整个对象。
配置:
hash_max_zipmap_entries 64 #配置字段最多64个
hash_max_zipmap_value 512 #配置value最大为512字节
1 | 1)hset myhash field value:设置myhash的field为value |
2 | 2)hsetnx myhash field value:不存在的情况下设置myhash的field为value |
3 | 3)hmset myhash field1 value1 field2 value2:同时设置多个field |
4 | 4)hget myhash field:获取指定的hash field |
5 | 5)hmget myhash field1 field2:一次获取多个field |
6 | 6)hincrby myhash field 5:指定的hash field加上给定的值 |
7 | 7)hexists myhash field:测试指定的field是否存在 |
8 | 8)hlen myhash:返回hash的field数量 |
9 | 9)hdel myhash field:删除指定的field |
10 | 10)hkeys myhash:返回hash所有的field |
11 | 11)hvals myhash:返回hash所有的value |
12 | 12)hgetall myhash:获取某个hash中全部的field及value |
集合结构操作
特点:无序性、确定性、唯一性
1 | 1)sadd key value1 value2:往集合里面添加元素 |
2 | 2)smembers key:获取集合所有的元素 |
3 | 3)srem key value:删除集合某个元素 |
4 | 4)spop key:返回并删除集合中1个随机元素(可以坐抽奖,不会重复抽到某人) |
5 | 5)srandmember key:随机取一个元素 |
6 | 6)sismember key value:判断集合是否有某个值 |
7 | 7)scard key:返回集合元素的个数 |
8 | 8)smove source dest value:把source的value移动到dest集合中 |
9 | 9)sinter key1 key2 key3:求key1 key2 key3的交集 |
10 | 10)sunion key1 key2:求key1 key2 的并集 |
11 | 11)sdiff key1 key2:求key1 key2的差集 |
12 | 12)sinterstore res key1 key2:求key1 key2的交集并存在res里 |
有序集合操作
1 | 1)zadd key score1 value1:添加元素 |
2 | 2)zrange key start stop [withscore]:把集合排序后,返回名次[start,stop]的元素 默认是升续排列 withscores 是把score也打印出来 |
3 | 3)zrank key member:查询member的排名(升序0名开始) |
4 | 4)zrangebyscore key min max [withscores] limit offset N:集合(升序)排序后取score在[min, max]内的元素,并跳过offset个,取出N个 |
5 | 5)zrevrank key member:查询member排名(降序 0名开始) |
6 | 6)zremrangebyscore key min max:按照score来删除元素,删除score在[min, max]之间 |
7 | 7)zrem key value1 value2:删除集合中的元素 |
8 | 8)zremrangebyrank key start end:按排名删除元素,删除名次在[start, end]之间的 |
9 | 9)zcard key:返回集合元素的个数 |
10 | 10)zcount key min max:返回[min, max]区间内元素数量 |
11 | 11)zinterstore dest numkeys key1[key2..] [WEIGHTS weight1 [weight2...]] [AGGREGATE SUM|MIN|MAX] |
12 | 求key1,key2的交集,key1,key2的权值分别是weight1,weight2 |
13 | 聚合方法用 sum|min|max |
14 | 聚合结果 保存子dest集合内 |
15 | 注意:weights,aggregate如何理解? |
16 | |
17 | 答:如果有交集,交集元素又有score,score怎么处理?aggregate num->score相加,min最小score,max最大score,另外可以通过weights设置不同的key的权重,交集时 score*weight |
服务器相关命令
1 | 1)ping:测定连接是否存活 |
2 | 2)echo:在命令行打印一些内容 |
3 | 3)select:选择数据库 |
4 | 4)quit:退出连接 |
5 | 5)dbsize:返回当前数据库中key的数目 |
6 | 6)info:获取服务器的信息和统计 |
7 | 7)monitor:实时转储收到的请求 |
8 | 8)config get 配置项:获取服务器配置的信息 |
9 | config set 配置项 值:设置配置项信息 |
10 | 9)flushdb:删除当前选择数据库中所有的key |
11 | 10)flushall:删除所有数据库中的所有的key |
12 | 11)time:显示服务器时间,时间戳(秒),微秒数 |
13 | 12)bgrewriteaof:后台重写aof文件 |
14 | 13)bgsave:后台保存rdb快照 |
15 | 14)save:保存rdb快照 |
16 | 15)lastsave:上次保存时间 |
17 | 16)shutdown [save/nosave] |
18 | 注意:如果不小心运行了flushall,立即shutdown nosave,关闭服务器,然后手工编辑aof文件,去掉文件中的flushall相关行,然后开启服务器,就可以倒回原来是数据。如果flushall之后,系统恰好bgwriteaof了,那么aof就清空了,数据丢失。 |
19 | 17)showlog:显示慢查询 |
20 | 问:多慢才叫慢? |
21 | 答:由slowlog-log-slower-than 10000,来指定(单位为微秒) |
22 | 问:服务器存储多少条慢查询记录 |
23 | 答:由slowlog-max-len 128,来做限制 |
redis认证
1 | ~]# vim /etc/redis.conf |
2 | requirepass jusene |
3 | |
4 | ~]# redis-cli |
5 | 127.0.0.1:6379>auth jusene |
redis事务
通过multi,exec,watch等命令实现事务功能: 将一个或多个命令归并为一个操作提请服务器按顺序执行的机制,不支持回滚操作
- multi:启动一个事务
- exec:执行事务
一次性将事务中的所有操作执行完成后返回给客户端 - watch:乐观锁:在exec命令行之前,用于监视指定数量键:如果监视中的某任意键数据被修改,则服务器拒绝执行事务
1
127.0.0.1:6379> multi
2
OK
3
127.0.0.1:6379> set ip 192.168.1.2
4
QUEUED
5
127.0.0.1:6379> set port 3306
6
QUEUED
7
127.0.0.1:6379> exec
8
1) OK
9
2) OK
watch
1 | 127.0.0.1:6379> watch ip |
2 | OK |
3 | 127.0.0.1:6379> multi |
4 | OK |
5 | 127.0.0.1:6379> set ip 1.1.1.1 在事务执行的过程中,ip键发生改变则此处事务拒绝执行 |
6 | QUEUED |
7 | 127.0.0.1:6379> exec |
8 | (nil) |
发布和订阅
- 1) PSUBSCRIBE pattern [pattern …] 通配订阅频道
- 2) PUBLISH channel message 发布信息
- 3) PUNSUBSCRIBE [pattern [pattern …]] 通配取消订阅频道
- 4) SUBSCRIBE channel [channel …] 订阅频道
- 5) UNSUBSCRIBE [channel [channel …]] 取消订阅频道
订阅new频道
1 | 127.0.0.1:6379> SUBSCRIBE new |
2 | Reading messages... (press Ctrl-C to quit) |
3 | 1) "subscribe" |
4 | 2) "new" |
5 | 3) (integer) 1 |
发布信息
1 | 127.0.0.1:6379> PUBLISH new hello |
2 | (integer) 1 |
频道接受到信息
1 | 127.0.0.1:6379> SUBSCRIBE new |
2 | Reading messages... (press Ctrl-C to quit) |
3 | 1) "subscribe" |
4 | 2) "new" |
5 | 3) (integer) 1 |
6 | 1) "message" |
7 | 2) "new" |
8 | 3) "hello" |
统配订阅频道
1 | 127.0.0.1:6379> PSUBSCRIBE new* |
2 | Reading messages... (press Ctrl-C to quit) |
3 | 1) "psubscribe" |
4 | 2) "new*" |
5 | 3) (integer) 1 |
6 | 1) "pmessage" |
7 | 2) "new*" |
8 | 3) "new" |
9 | 4) "hello" |
10 | 1) "pmessage" |
11 | 2) "new*" |
12 | 3) "news" |
13 | 4) "hello" |
redis持久化
redis持久化有两种方式:
RDB和AOF
RDB:snapshot,二进制格式,按事先定制的策略,周期性将数据保存磁盘,数据文件默认为dump.rdb
客户端也可以使用save或bgsave命令启动快照保存机制
save:同步,在主线程中保存快照,此时会阻塞所有客户端请求
bgsave:异步,不会造成阻塞
相当于mysql周期性备份AOF:Append Only File
通过记录每一次写操作至指定的文件尾部实现持久化:当redis重启时,可通过重新执行文件中的命令在内存重建数据库;
bgrewriteaof:aof文件重写
不会读取正在使用的aof文件,而是通过将内存中的数据以命令的方式保存到临时文件中,完成之后替换原来的aof文件
相当于mysql的binlog
RDB:
1 | SAVE 900 1 |
2 | SAVE 300 10 |
3 | SAVE 60 10000 |
4 | stop-writes-on-bgsave-error yes |
5 | rdbcompression yes |
6 | rdbchecksum yes |
7 | dbfilename dump.rdb |
8 | dir ./ |
AOF:
重写过程:
- (1)redis主进程通过fork创建子进程
- (2)子进程根据redis内存中的数据创建数据库重建命令序列于临时文件中
- (3)父进程继承client的请求,并把这些请求的写操作继续追加至原来的aof文件中:额外地,这些新的写请求还会被放置于一个缓冲队列中
- (4)子进程重写完成,会通知父进程:父进程把缓冲队列的命令写到临时文件中
- (5)父进程用临时文件替换老的aof文件
相关参数:
1 | appendonly no |
2 | appendfilename "appendonly.aof" |
3 | # appendfsync always |
4 | appendfsync everysec |
5 | # appendfsync no |
6 | no-appendfsync-on-rewrite no |
7 | auto-aof-rewrite-percentage 100 |
8 | auto-aof-rewrite-min-size 64mb |
注意
:持久本身不能取代备份,还应该制定备份策略,对redis数据库定期进行备份
rdb与aof同时启用:
- (1)bgsave和bgrewriteaof不会同时执行
- (2)在redis服务器启动用于恢复数据时,会优先使用aof
redis主从复制
特点:
- 一个master可以有多个slave
- 支持链式复制
- master以非阻塞方式同步数据至slave
从服务器:
1 | slaveof masterip masterport |
redis.conf
1 | slaveof masterip masterport |
2 | masterauth <master-password> |
3 | slave-serve-stale-data yes 当与主服务器断开时,数据是否可用 |
4 | slave-read-only yes |
5 | repl-diskless-sync no 当在低io高带宽的场景,使用diskless的方法同步磁盘数据 |
6 | repl-diskless-sync-delay 5 |
7 | slave-priority 100 多个slave时的优先级 |
redis sentinel集群
redis sentinel(哨兵)可以有效的容灾,当主服务器宕机时,可以选出从服务器中的一台来作为主服务器来使用。
sentinel的作用:
- 监控:监控主从是否正常
- 通知:出现问题时,可以通知相关人员
- 故障迁移:自动主从切换
- 统一的配置管理:连接者询问sentinel取得主从的地址
1 | ~]# cp sentinel.conf /etc/sentinel.conf |
2 | ~]# cat sentinel.conf |
3 | port 26371 |
4 | daemonize yes |
5 | dir "/tmp" |
6 | logfile "/var/log/redis/sentinel.log" |
7 | sentinel myid 8cd979a05f7bbfb2dbd38d935c56ee0a0c193dd0 |
8 | #sentinel auth-pass <master-name> <password> |
9 | sentinel down-after-milliseconds <master-name> <milliseconds> #master和slave多长时间(默认30秒)不能使用后标记为sdown状态 |
10 | sentinel monitor <master-name> <ip> <redis-port> <quorum> #哨兵监控这个master,在至少quorum个哨兵实例都认为master down后把master标记为odown(objective down客观down;相对应的存在sdown,subjective down,主观down) |
11 | sentinel failover-timeout <master-name> <milliseconds> #若sentinel在该配置值内未能完成failover操作(即master/slave自动切换),则认为本次failover失败 |
12 | sentinel parallel-syncs <master-name> <numslaves> #当切换主从状态后,设定一个最低值值数量slaves来同步 |
13 | |
14 | sentinel config-epoch TestMaster 15 |
15 | sentinel leader-epoch TestMaster 8394 |
16 | |
17 | #除了当前哨兵, 还有哪些在监控这个master的哨兵 |
18 | sentinel known-sentinel <master-name> 127.0.0.1 26372 0aca3a57038e2907c8a07be2b3c0d15171e44da5 |
19 | sentinel known-sentinel <master-name> 127.0.0.1 26373 ac1ef015411583d4b9f3d81cee830060b2f29862 |
20 | |
21 | sentinel current-epoch 8394 |
sentiel 启动:
1 | ~]# redis-sentinel /etc/sentinel.conf |
2 | ~]# redis-server /etc/sentinel.conf --sentinel |
专有命令:
1 | sentinel masters |
2 | sentinel slaves <master name> |
3 | sentinel get-master-addr-by-name <master name> |
4 | sentinel reset |
5 | sentinel failover <master name> |