redis
redis的特点以及安装使用
redis是开源,BSD许可,高级的key-value存储系统,可以用来存储字符串、哈希结构、链表、集合,因此常用来提供数据结构服务。
下载安装
1、到官网(https://redis.io/)下载稳定版本
2、解压安装包
3、解压之后进入目录(/home/xdl/redis-2.8.3/src)执行make命令
4、执行安装命令:make PREFIX=/home/xdl/redis install , /home/xdl/redis为安装目录
5、安装完成之后在/home/xdl/redis/bin目录下出现如下5个文件
1、redis-benchmark:性能测试工具
2、redis-check-aof: 日志文件检测工具(比如断电造成日志损坏,可以检测并修复)
3、redis-check-dump:快照文件检测工具,效果同上
4、redis-cli: 连接用的客户端
5、redis-server: redis服务进程
6、复制配置文件:xdl@xdl-gj:~/redis/bin$ cp ../../redis-2.8.3/redis.conf ./
7、启动服务:xdl@xdl-gj:~/redis/bin$ ./redis-server ./redis.conf
如果想要以后台进程的形式运行,需要修改redis.conf配置文件中的daemonize no为daemonize yes
再次启动服务,使用ps -aux | grep redis可以查看是否成功启动
xdl 18203 0.0 0.0 46100 3408 ? Ssl 00:59 0:00 ./redis-server *:6379
8、连接服务:xdl@xdl-gj:~/redis/bin$ ./redis-cli -h localhost -p 6379
set name xdl : 设置键值
get name: 获取name键的值
说明:在redis.conf配置文件中databases 16,表示含有16个数据库,标号是0~15,通过select 0选择使用的数据库,默认是0
通用key操作命令
1、del key1 key2 ... keyn
作用:删除1个或多个键
返回值:不存在的key忽略掉,返回真正删除的key的数量
2、rename key newkey
作用:给key赋一个新的key名
说明:newkey已经存在,则newkey的原值将会被覆盖
3、renamenx key newkey
作用:把key改名为newkey
返回值:发生修改返回1,未发生修改返回0
说明:nx(not exists),即newkey不存在时才可以修改
4、move key db
作用:将当前数据库中的key移动到db数据中,db一般用数字代表
返回值:移动成功返回1,移动失败返回0
说明:一次只能移动一个key
5、keys pattern
作用:查询响应的key
返回值:返回查询到的key
说明:pattern支持模糊查询,*表示任意多个字符,?表示任意一个字符,[]表示括号内某一个字符,字符之间不需要分割符
6、randomkey
作用:随机返回某个key
7、exists key
作用:查看某个可以时候存在
返回值:存在返回1.不存在返回0
8、type key
作用:查看某个可以的数据类型
返回值:key存储的值的数据类型,包括sting、link、set、order set, hash
9、expire key 整型值
作用:设置key的生命周期,以秒为单位
10、pexpire key 整型值
作用:设置key的生命周期,以毫秒为单位
11、persist key
作用:把指定的key设置为永久有效
12、ttl key
作用:查询key的生命周期
返回:以秒为单位的数值
说明:对于不存在的key或已经过期/永久有效的key都返回-1,redis2.8中对于不存在或已经失效的返回-2,对用永久有效的返回-1
13、pttl key
作用:查询key的生命周期
返回:以毫秒为单位的数值
说明:同上
字符串类型的操作
1、set key value [ex 秒数]/ [px毫秒数] [nx]/[xx]
作用:设置key的值
说明:ex px同时存在时以后面的为准,nx表示key不存在的时候执行,xx表示key存在的时候执行
2、mset key1 value1 key2 value2 ...
作用:同时设置多个key的值
3、get key
作用:获取key的值
4、mget key1 key2 ... keyn
作用:获取多个key的值
5、setrange key offset value
作用:把字符串的offset偏移字节改成value,下标从0开始
返回值:返回字符串的长度
说明:如果offset大于字符长度,则自动补\x00
127.0.0.1:6379> set name xdl
OK
127.0.0.1:6379> setrange name 4 gj
(integer) 6
127.0.0.1:6379> get name
"xdl\x00gj"
6、append key value
作用:把value追加到key的原值上
返回值:返回字符串的长度
7、getrange key start stop
作用:获取字符串[start, stop]的范围值,闭区间
说明:对于字符串左边从0开始右边从-1开始
8、getset key newvalue
作用:获取并返回旧值,设置新值
9、incr key
作用:指定的key的值加1
返回值:返回加1之后的值
说明:执行对为整数数值类型的字符串进行加1操作,对于不存在的key当做0,再incr操作
10、incrby key number
作用:指定的key的值加number
11、incrbyfloat key floatnumber
作用:加的数值可以是浮点数值
12、decr key
作用:对指定的key的值做减1操作
13、decrby key number
作用:指定的key的值做减number操作
14、getbit key offset
作用:获取值的二进制表示,对应位上的值(从左,从0编号)
15、setbit key offset value
作用:设置offset对应二进制位上的值
返回值:返回该位的旧值
说明:如果offset过大,则会在中间填充0,offset最大为2^32-1,可推出最大的字符串为521M
练习:将大写字母转换为小写字母
分析:A对应的ascci为65,对应的二进制0100 0001,a对应的ascii为97(65+32),对应的二进制01100 0001
127.0.0.1:6379> set char A
OK
127.0.0.1:6379> setbit char 2 1
(integer) 0
127.0.0.1:6379> get char
"a"
16、bitop operation destkey key1 [key2 ....]
作用:对key1,key2,keyn做operation操作,并将结果保存到destkey上,operation可以是:AND、OR、NOT、XOR,操作符不区分大小写
说明:NOT操作,key不能多个
127.0.0.1:6379> setbit lower 2 1
(integer) 0
127.0.0.1:6379> get lower
" "
127.0.0.1:6379> set char Q
OK
127.0.0.1:6379> bitop or char char lower
(integer) 1
127.0.0.1:6379> get char
"q"
127.0.0.1:6379> set ch A
OK
127.0.0.1:6379> bitop OR ch ch lower
(integer) 1
127.0.0.1:6379> get ch
"a"
说明:任意一个大写字母与lower(0010 0000)做or操作就会得到小写字母
link(list)链表结构
1、lpush key value1 value2 ... valuen
作用:把值插入到链表的头部(左边)
返回值:链表的长度
2、rpush key value1 value2 ...valuen
作用:把值插入到链表的尾部(右边)
返回值:链表的长度
3、lpop key
作用:返回并删除链表的尾元素
4、rpop key
作用:返回并删除链表的头部元素
5、lrange key start stop
作用:返回链表中[start, stop]中的元素
说明:左边从0开始,右边从-1开始
6、lrem key count value
作用:删除key链表中值为value的元素,count的绝对值表示删除的个数
返回值:返回删除的个数
说明:count > 0 表示从头删除, count < 0 表示从尾部删除, count = 0 表示全部删除
7、ltrim key start stop
作用:剪切key对应的链表,切[start, stop]一段,并把该段的值重新赋值给key
127.0.0.1:6379> lrange ans 0 -1
1) "b"
2) "c"
3) "b"
4) "c"
127.0.0.1:6379> ltrim ans 0 2
OK
127.0.0.1:6379> lrange ans 0 -1
1) "b"
2) "c"
3) "b"
8、lindex key index
作用:返回index索引上面的值
9、llen key
作用:获取链表的长度
10、linsert key after|before search value
作用:在key链表中从头开始寻找‘search’元素,一旦找到将value插入到search的前面或后面
返回值:插入成功返回链表的长度,插入失败返回-1
127.0.0.1:6379> rpush ans a b c d
(integer) 4
127.0.0.1:6379> linsert ans before b e f
(error) ERR wrong number of arguments for 'linsert' command
127.0.0.1:6379> linsert ans before b e
(integer) 5
11、rpoplpush source dest
作用:将soure链表的最后一个元素取出并插入到dest链表的头部
返回值:pop出来的元素
应用场景:为了防止pop取出值,进行某个操作失败了,但是数据丢失的事情发生
12、brpop | rlpop key timeout
作用:等待弹出key的头部元素或尾部元素,timeout为等待超时时间,值为0时表示永久等待,单位为秒
返回值:返回链表的所有元素和等待时间
应用场景:长轮询Ajax,在线聊天
集合set相关命令
1、sadd key value1 value2 ... valuen
作用:向key集合中增加元素
返回值:插入元素的个数
2、smembers key
作用:返回集合中所有的元素
3、srandmember key
作用:随机返回集合中的某个元素(只是取出不会删除)
4、sismember key value
作用:判断value值是否在key集合中
返回值:如果存在返回1,不存在返回0
5、scard key
作用:返回集合中元素的总个数
6、srem key value1 value2 ... valuen
作用:删除集合中值为value1 ... valuen的元素
返回值:返回真正删除的元素的个数,忽略不存在的元素
7、spop key
作用:返回并删除集合中的某个元素,体现了集合的无序性
8、smove source dest value
作用:将source中值为value的元素取出并删除,然后添加到dest集合中
返回值:成功返回1,失败返回0
说明:dest集合不存在则创建
9、sinter key1 key2 ... keyn
作用:求出key1 key2 ... keyn集合中的交集并返回
10、sinterstore dest key1 key2 ... keyn
作用:求出key1 key2 ... keyn集合中的交集并赋值给dest
11、sunion key1 key2 ... keyn
作用:求出key1 key2 ... keyn集合中的并集并返回
12、sdiff key1 key2 ... keyn
作用:求key1与key2...keyn的差集
有序集合 Order set
1、zadd key score1 value1 .... scoren valuen
作用:向key有序集合添加元素
说明:score是用来排序的
2、zrange key start stop [withscores]
作用:把集合排序(升序)完之后,返回[start, stop]的元素,withscores表示把score也打印出来
说明:start=0,stop= -1 表示取出所有的元素
3、zrevrange key start stop [withscores]
作用:同zrange只是排序变为降序
4、zrangebyscore key min max [withscores] [limit offset N]
作用:将key集合升序之后,取score在[min, max]内的元素,并跳过offset个,取出N个
5、zrevrangebyscore key max min [withscores] [limit offset N]
作用:同zrangebyscore,只是降序排序,取值范围由大到小
6、zcard key
作用:返回集合元素的个数
7、zcount key min max
作用:返回集合元素在[min, max]之间的个数
8、zrank key value
作用:查询值为value元素的排名(升序,从0开始)
9、zrevrank key value
作用:查询值为value元素的排名(降序,从0开始)
10、zrem key value1 ... valuen
作用:删除集合的元素
返回值:返回成功删除元素的个数
11、zremrangebyscore key min max
作用:删除score在[min, max]之间的元素
返回值:返回成功删除元素的个数
12、zremrangebyrank key start stop
作用:删除名次在[start, stop]之间的元素
返回值:返回成功删除元素的个数
13、zinterstore dest numkeys key1 [key2... keyn] [weights weight1 [weight2... weightn]] [aggregate sum | min | max ]
作用:就key1...keyn的交集,并对交集的score进行权重和聚合操作,把最后的结果赋值给dest
返回值:返回新插入dest集合的元素个数
说明:weight * score 获取新的score,sum求和,min求最大score, max求最小的score,如果dest集合原先存在元素会先将其清空,weight可以是0 负数 浮点数
127.0.0.1:6379> zadd z1 2 a 3 b 4 c
(integer) 3
127.0.0.1:6379> zadd z2 3 a 4 b 5 e
(integer) 3
127.0.0.1:6379> zinterstore z3 2 z1 z2 weights 2 1 aggregate min
(integer) 2
127.0.0.1:6379> zrange z3 0 -1 withscores
1) "a"
2) "3"
3) "b"
4) "4"
Hash哈希数据类型相关命令
1、hset key field value
作用:把key中field域的值设为value
说明:如果没有field域直接添加,如果有则覆盖原来field域的值
2、hsetnx key field value
作用:如果key中不存在field域则添加并赋值为value,如果已经存在则操作无效
返回值:成功添加新域为1,操作无效为0
3、hmset key field1 value1 [ ... fieldn valuen]
作用:设置field1->N个域,对应的值是value1->N
4、hget key field
作用:返回key中field域的值
5、hmget key field1 [... fieldn]
作用:返回key中多个域对应的值
6、hgetall key
作用:获取key中所有的域和值
7、hdel key field1 [...fieldn]
作用:删除key中field...fieldn多个域
返回值:返回删除域的个数
8、hlen key
作用:返回key中域的个数
9、hexists key field
作用:判断key中有没有field域
返回值:存在返回1,不存在返回0
10、hincrby key field value
作用:把key中field域的值增加整数值value
说明:如果key不存在,会创建一个新的哈希集域key关联,如果field域不存在,在添加并且值为0
11、hincrbyfloat key field value
作用:把key中field域的值增加浮点值value
说明:同hincrby
12、hkeys key
作用:返回key中所有的field
13、kvals key
作用:返回key中所有的value
14、hstrlen key field
作用:返回hash指定field的value的字符串长度,如果hash或者field不存在,返回0.
说明:3.2.0版本之后才有的命令
redis中的事务和锁的应用
multi、exec、discard、watch是redis事务的相关命令,事务可以一次执行多个命令, 并且带有以下两个重要的保证:
1、事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
2、事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
redis与mysql事务的对比
Mysql | redis | |
开启事务 | start transaction | multi |
语句 | insert、delete、update、select语句 | 普通命令 |
失败 | rollback回滚 | discard取消 |
成功 | commit提交事务 | exec |
说明:在multi后面的语句中,语句出错可能有两种情况
1、语法本身就有问题,在添加到queued队列的时候就已经报错了,这种情况在exec时报错,所有的语句都得不到执行
2、语法本身没有问题,成功的添加到了queued队列中,比如:sadd gj 1(gj是字符串类型的),这种情况exec是之后错误的语句执行失败,其他都能成功
执行exec之后事务就会关闭
思考:
正在买票ticket只剩1张,票价money为100元,如果在multi之后和exec之前,票被别人买了,即ticket变为0了,应该如何观察这种情景,并不再提交
1、悲观的想法:
世界充满危险,肯定有人和我抢票,给ticket加锁,只有我能操作(悲观锁)
2、乐观的想法
没有那么多人和我抢票,因此,只需要注意有没有人更改ticket的值就可以了(乐观锁)
redis中的事务,启用的是乐观锁,只负责检测key有没有被改动,使用watch命令给key加锁
127.0.0.1:6379> watch tick
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> decr tick
QUEUED
127.0.0.1:6379> decrby xdl 100
QUEUED
127.0.0.1:6379> exec
(nil) #说明监视的tick的值发生了变化,事务取消
watch可以同时监控多个可以:watch key1 ... keyn ,只要其中有一个key的值发生变化,则事务取消
unwatch:取消所有watch的key
说明:watch命令必须在multi命令之前
频道发布与消息订阅
使用方法:
1、订阅端:subscribe 频道名称1 ...频道名称n
2、发布端:pulish 频道名称 发布内容
返回值:返回有多少个订阅端
3、订阅端可以根据pattren匹配多个频道
psubscribe pattern
说明:发布/订阅与key所在空间没有关系,它不会受任何级别的干扰,包括不同数据库编码。 发布在db 10,订阅可以在db 1
redis持久化配置
redis的持久化分为两种方式
1、快照rdb
在redis.conf配置文件中
save 900 1 :表示900秒(15分钟内)有1条写入,则生成快照
save 300 10 :表示5分钟内有10条写入,则生成快照
save 60 10000 :表示1分钟内有10000条写入,则生成快照
说明:这三个选项都屏蔽,则rdb被禁用,可以自己自定义生成快照的策略
stop-writes-on-bgsave-error yes :后台备份进程出错,主进程是否停止写入
rdbcompression yes :d导出的rdb文件是否压缩
rdbchecksum yes :导入rdb恢复数据时,是否要检测rdb的完整型
dbfilename dump.rdb :备份rbd的文件名
dir ./ :备份rdb文件的保存路径
2、日志aof
在redis.conf配置文件中
appendonly no : 是否打开aof日志功能
appendfilename appendonly.aof : aof文件的路径加文件名,默认为appendonly.aof
appendfsync always :每1条命令,都立刻同步到aof中,安全,但是速度慢
appendfsync everysec :每隔1秒写入一次,比较好的方案
appendfsync no : 写入工作交给操作系统,由操作系统判断缓冲区大小,统一写入到aof,同步频率低(容易造成大量数据的丢失),速度快
no-appendfsync-on-rewrite no : 正在导出rdb快照时,是否要停止同步aof
auto-aof-rewrite-percentage 100 : aof文件大小比起上次重写的大小,增长率100%时,重写,比如上次写入后文件2M,下次写入文件为4M时将进行重写
auto-aof-rewrite-min-size 64mb :aof文件,至少超过64M时,重写,(如果值太小,前期重写太过频繁)
问答:
在dumpr rdb过程中,aof如果停止同步,会不会丢失数据?
答:不会,所有操作将会缓存在内存的队列里,dump完成后,统一操作
aof重写指的是什么?
答:aof重写是指把内存中的数据,逆化成命令,写入到aof日志里,以解决aof日志过大的问题,比如一个值一直增加1,我们只去最后的值
如果rdb文件和aof文件都存在,优先使用谁进行数据恢复呢?
答:aof,会出现rbd中有数据,但是我们重启服务之后内存中没有数据,这是因为我们启用了aof但是aof中没有数据
两种方式是否可以同时使用
答:可以,而且推荐这么做
恢复数据时,哪种方式更快
答:rdb,因为rdb是数据的内存映射,直接载入到内存,而aof是命令,需要逐条执行
redis集群
Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。就是多个redis服务器
作用:
1、主从备份,防止主机宕机
2、读写分离,分担master的任务
3、任务分离,主从服务分别分担备份工作与计算工作
有两种方式实现
1、 slave1
master ...
slaven
2、master <-- slave1 ... <--slaven
方式2的好处在于master宕机之后,可以直接切换到slave1,让slave1作为master,方式1需要手动修改,或使用sentinel监控
配置redis集群
master配置:
1、关闭rdb快照(备份工作交给slave),注释掉save即可
2、可以开启aof
3、配置密码,# requirepass foobared,设置密码之后,启动客户端时需要输入密码
4、可以通过命令: config set requirepass 密码 进行设置密码
slave配置:
1、声明slaveof,slaveof <masterip> <masterport>
2、配置密码(如果master有密码), masterauth <master-password>
3、某一个slave打开rdb快照功能
4、配置slave只读,slave-read-only yes
5、配置pid文件,pidfile /var/run/redis6380.pid
6、配置端口,port 6380
缺点:
每次slave断开后,(无论是主动断开,还是网络故障)在连接master,都要master全部dump出来rdb,在aof,即同步的过程都要重新执行一遍
所以要记住,多台slave不要一下都启动起来,否则master可能IO剧增,
如果redist集群中master宕机,应该怎么处理
手动处理的方式:
1、修改一台slave(A)为master
1、命令该服务不做其他redis服务的slave,slaveof no one
2、修改readonly 为 no, config set slave-read-only no
3、修改其他slave作为A服务的slave
1、slaveof localhost 6380
使用sentinel监控实现
1、将sentinel.conf拷贝到安装目录(bin)下~/redis/bin$ cp ../../redis-2.8.3/sentinel.conf ./
2、监控master并起名为mymaster(可以自定义但是后面的必须与其一致),2表示两个sentinel实例都未连接到master才是真正的宕机:
sentinel monitor mymaster 127.0.0.1 6379 2
3、如果master设置的有密码,需要配置密码:sentinel auth-pass <master-name> <password>
4、设置间隔多长时间之内得到响应则认为失败,sentinel down-after-milliseconds mymaster 30000
5、sentinel parallel-syncs mymaster 1 :表示一次只添加一台master,否则会造成新的master IO剧增
6、启动监控: ./redis-server ./sentinel.conf --sentinel
说明:sentinel根据redis.conf配置文件中的优先级选择哪个slave作为新的master(slave-priority 100),数值越小优先级越大,如果优先级相同,则随机选择。
redis key的设计技巧
1、把表名转换为key的前缀,比如tag:
2、第二段放置用于区分key的字段,对用mysql中的主键的列名
3、第三段放置主键的值
4、第四段放置要存储的列名
说明:在关系型数据库中,还有可能其他列也经常作为查询字段,这种字段往往也是加了索引的,转为key-value数据库中,则也要相应的生成
一条按照该列为主的key-value,根据这个可以找到对应的主键,然后在查询相应的内容
下面看一个例子
在MySQL数据库中创建book和tags两张表,内容如下:
mysql> select * from book;
+--------+----------------------+
| bookid | title |
+--------+----------------------+
| 5 | PHP 圣经 |
| 6 | ruby 实战 |
| 7 | mysql 运维 |
| 8 | ruby 服务端编程 |
+--------+----------------------+
mysql> select * from tags;
+------+--------+----------+
| tid | bookid | content |
+------+--------+----------+
| 10 | 5 | PHP |
| 11 | 5 | WEB |
| 12 | 6 | WEB |
| 13 | 6 | ruby |
| 14 | 7 | database |
| 15 | 8 | ruby |
| 16 | 8 | server |
+------+--------+----------+
根据上面两张表,查询出既有WEB标签,又有PHP标签的书,
select b.bookid,b.title from book as b inner join tags as t1 inner join tags as t2 on b.bookid=t1.bookid and t1.book=t2.bookid where t1.content='PHP' and t2.content='WEB';
使用上面的连接查询确实可以获取结果,但是效率很低
现在使用redis构造与上面两张表相同的效果
mset book:bookid:5 PHP book:bookid:6 ruby book:bookid:7 mysql book:bookid:8 reub2
创建标签表使用集合数据类型
127.0.0.1:6379> sadd tags:PHP 5
(integer) 1
127.0.0.1:6379> sadd tags:WEB 5 6
(integer) 2
127.0.0.1:6379> sadd tags:ruby 6 8
(integer) 2
127.0.0.1:6379> sadd tags:database 7
(integer) 1
127.0.0.1:6379> sadd tags:server 8
(integer) 1
可以使用集合的交集找到既有PHP又有WEB标签的bookid
127.0.0.1:6379> sinter tags:PHP tags:WEB
1) "5"