上篇redis文章为大家介绍了redis与它的部署工作、这次我们来说一下redis的操作命令与持久化

一、命令总结

1)String操作

6379> set k1 v1			  #设定值
6379> get k1				  #获取值
6379> mset k2 v2 k3 v3		#批量设定值
6379> mget k2 k3			  #批量获取值
6379> setnx k4 v4			#为不存在的键设定值
6379> setex book 60 110		#原子性操作、同一时间可完成设定值与设置过期时间
6379> msetnx k1 v1 k2 v2	    #原子性操作、批量为不存在的键设定值
6379> getset k1 v1			#如果k1键不存在、相当于将k1键的值设置为v1
6379> append k1 _12138		#尾部追加数据、如果k1的值为v1、那么执行之后值就变为k1_12138
6379> substr k1 3 7			#查看3-7之间的数据、即显示为12138
6379> incr num				#递增num的值、如果值为1、那么执行之后num的值为2
6379> decr num			  #递减num的值、如果值为2、那么执行之后num的值为1
6379> incrby num 5			#按量递增num的值、如果值为1、那么执行之后num的值为6
6379> decrby num 5			#按量递减num的值、如果值为6、那么执行之后num的值为1
6379> incrbyfloat num 6.6	#递增浮点数、如果值为1、那么执行之后值为7.6
6379> incrbyfloat num -6.6	#递减浮点数、如果值为7.6、那么执行之后值为1
6379> strlen k1				#获取字符串的长度
6379> setrange book 3 456	#相当于替换、如果book的值为123abc、从第3位开始替换为456
6379> getrange book 0 2		#返回字符串中的指定部分、执行之后返回的为123、-1为返回所有

2)Hash操作

6379> hset info book 110			  #设定值
6379> hget info book				  #获取值
6379> hmset info k1 v1 k2 v2		  #批量设定值
6379> hmget info k1 k2				#批量获取值
6379> hgetall info					#获取info键中的所有值
6379> hsetnx info k4 v4				#给不存在的域设定值、存在则放弃执行
6379> hexists info k1				#检查k1这个域是否存于info键中
6379> hdel info k1					#删除info键中名为k1的域、如需删除多个、那就空格分隔
6379> hlen info						#返回info键中域的数量
6379> hkeys info					  #返回info键中所有的域
6379> hvals info					  #返回域中所有的值
6379> hstrlen info k1				#返回指定域中字符串的长度
6379> hincrby info book 4			#按量递增book这个域的值、如果初始值为136、那么执行之后值为140
6379> hincrby info book -4			#按量递减book这个域的值、如果初始值为140、那么执行之后值为136
6379> hincrbyfloat info book 1.1	  #递增浮点数、如果book的初始值为13、那么执行之后值为14.1
6379> hincrbyfloat info book -1.1	#递减浮点数、如果book的初始值为14.1、那么执行之后值为13

3)List操作

6379> lpush k1 a1 a2			  #创建列表、并在头部添加元素
6379> rpush k1 a3				#创建列表、并在尾部添加元素
6379> lpushx k1 a4				#将元素插入列表的头部、如果列表不在、则放弃执行
6379> rpushx k1 a5				#将元素插入列表的尾部、如果列表不在、则放弃执行
6379> lrange k1 0 3				#返回指定区间的元素、从0开始算、-1表示最后一个元素、以此类推
6379> linsert k1 before a1 a0	#在某个值前面插入数据、比如在a1这个值的前面插入a0这个值
6379> linsert k1 after a8 a9	  #在某个值后面插入数据、比如在a8这个值的后面插入a9这个值
6379> lset k1 2 mds				#相当于替换、从0开始算、比如将第三行的数据替换为mds
6379> ltrim k1 0 4				#保留指定的前5个元素、从0开始算、没有指定的将被删除
6379> llen k1					#返回k1这个列表中元素的个数
6379> lindex k1 0				#获取k1这个列表中的第一个值、从0开始算
6379> lpop k1					#移除k1这个列表的头部元素
6379> rpop k1					#移除k1这个列表的尾部元素
6379> blpop k1 15				#从头部开始移除元素、返回的值包括所属列表与被移除的元素、15为超时时间
6379> brpop k1 15				#从尾部开始移除元素、返回的值包括所属列表与被移除的元素、15为超时时间
6379> rpoplpush k1 k2			#将k1的尾部元素转移到k2
6379> brpoplpush k1 k2 15		#将k1的尾部元素转移到k2、每执行一次、就从尾部转移一次、15为超时时间
6379> lrem k1 2 23				#移除从首部到尾部的2个名为23的元素
6379> lrem k1 -1 11				#移除从尾部到首部的第一个名为11的元素

注意事项:

1、brpoplpush为rpoplpush的阻塞版本:当指定列表为空时、连接将被brpoplpush阻塞、直到等待超时或执行lpush与rpush命令为止
2、blpop为lpop的阻塞版本:当指定列表内没有任何元素可移除的时、连接将被blpop命令阻塞、直到等待超时或发现可移除元素为止
3、brpop为rpop的阻塞版本:当指定列表内没有任何元素可移除的时、连接将被brpop命令阻塞、直到等待超时或发现可移除元素为止

4)Set操作

6379> sadd k1 a1 a2			#添加元素、元素可有多个
6379> smembers k1			#获取k1集合中的所有元素
6379> scard k1				#获取k1集合中元素的个数
6379> sismember k1 a1		#判断a1这个元素、是否存在k1集合中
6379> spop k1 3				#在k1集合中随机返回3个元素、并将其移除
6379> srandmember k1 3		#在k1集合中随机返回3个元素、但不将其移除
6379> srem k1 a1 a2			#移除k1集合中名为a1和a2两个元素、值可一个、也可多个
6379> smove k1 k2 a1		   #将k1集合中名为a1的元素、移动到k2集合中去、一次一个
6379> sinter k1 k2			#获取k1与k2中相同的数据、并返回
6379> sinterstore k3 k1 k2	#获取k1与k2中相同的数据、返回之后并将其保存到k3集合中
6379> sunion k1 k2			#获取k1与k2中不同的数据、并返回
6379> sunionstore k3 k1 k2	#获取k1与k2中不同的数据、返回之后并将其保存到k3集合中
6379> sdiff k1 k2			#获取在k1而不在k2中的数据、并返回
6379> sdiffstore k3 k1 k2	#获取在k1而不在k2中的数据、返回之后并将其保存到k3集合中

5)Zet操作

6379> zadd info 10 www.mds.com			#添加元素、10为优先级、可设置多对
6379> zrange info 0 -1					#获取集合中的所有元素、按优先级从小到大显示
6379> zrem info www.mds.com				#删除集合中的元素、值可多个
6379> zrange info 0 -1 WITHSCORES		#获取集合中所有元素的同时也显示优先级
6379> zrevrange info 0 -1				#按照优先级进行逆向排序、与zrange相反
6379> zscore info www.mds.com			#获取集合中某个元素的优先级
6379> zrank info www.mds.com			  #获取元素在集合中的排名、最小的排名为0
6379> zrevrank info www.mds.com			#获取元素在集合中的倒序排名、即从大到小
6379> zincrby info 60 www.mds.com		#为集合中某个元素增加优先级、越大越往后
6379> zcard info						  #获取集合中元素的个数
6379> zcount info 20 60					#按照优先级获取区间内元素的个数
6379> zrangebyscore info 20 60			#按照优先级获取区间内元素的值
6379> zrevrangebyscore info +inf -inf	#从大到小逆向排序所有元素
6379> zrevrangebyscore info 60 20		#从大到小逆向排序优先级介于60-20之间的元素
6379> zremrangebyrank info 0 2			#删除区间内指定的元素、从0开始算
6379> zremrangebyscore info 25 60		#按照优先级删除区间内指定的元素
6379> zinterstore info3 2 info1 info2  #将info1与2集合中相同集合名的优先级进行相加、然后保存到info3中、2为集合数量
6379> zunionstore info3 2 info1 info2  #将info1与2集合中相同集合名的优先级进行相加、而不同的集合名则不相加、但仍然都保存到info3中

注意事项:

1、aggregate min:获取info1与info2中优先级最小的元素保存到info3中
2、aggregate max:获取info1与info2中优先级最大的元素保存到info3中
4、aggregate sum:对info1与info2中的优先级进行求和、然后保存到info3中、默认使用此方式

二、redis持久化

redis提供了两种不同级别的持久化方式:

名为RDB的持久化、可在指定的时间内生成数据集的时间点快照

名为AOF的持久化、用于记录服务器写的操作指令、并在服务器启动时、通过重新执行这些命令来还原数据

redis可同时使用RDB以及AOF、但重启之后仍然使用AOF来还原数据、因为AOF所保存的数据通常比RDB完整  

1)RDB持久化

1、RDB的优点

RDB为在某个时间内将数据从内存保存到磁盘、此方式适合备份与恢复、它只有一个文件、内容非常紧凑
在性能层面上、RDB可突出redis的性能、因为父进程在保存RDB文件时、需要做的操作只是fork出一个子进程
而保存操作就是子进程需要做的事情、所以父进程没有任何的磁盘I/O操作、性能自然而然的就得到了提升
在数据恢复层面上、RDB在恢复大数据集的时候、恢复速度要比AOF的恢复速度快很多

2、RDB的缺点

在每一次对RDB文件进行保存的到时候、都要fork出一个子进程、然后由子进程完成实际的持久化工作、但是在数据集比较庞大的时候fork会非常的耗时
如果我们想最大限度避免数据丢失、那么RDB可能不是一个好的选择、尽管redis为我们提供了保存RDB文件的频率
但RDB文件需要保存整个数据的状态、所以这不是一件轻松的事情、如果保存的时间很久、而这个时候系统出现故障
那此前还没有来得及写入磁盘的数据将全部丢失

3、RDB快照

在默认的情况下、redis将快照默认保存于dump.rdb二进制文件中、这个文件的名称也可自定义
可以自定义时间、让它在多少秒内数据集有多少个改动、当这个条件被满足时、将自动保存一次数据集
用户也可以通过执行save或者bgsave指令、手动让redis进行数据集保存操作

4、RDB快照运作方式

1、需要做持久化时、redis将fork出一个子进程
2、子进程将数据集写入到一个临时的RDB文件当中
3、当子进程完成对新RDB文件的写入时、redis用新RDB文件替换原来的RDB文件、并删除旧的RDB文件

2)AOF持久化

1、AOF的优点

AOF为记录服务器上执行写的操作指令、并在服务器启动时、通过重新执行这些命令来还原数据
同时我们还可以定义不同的fsync策略、AOF的默认策略为每秒钟fsync一次、就算发生了故障、最多也只会丢失一秒的数据、并且在这种情况下redis还能保存良好的性能、因为fsync会在后台线程执行、而主线程可继续处理命令请求
AOF文件只是一个进行追加操作的日志文件、就算在写入一半的时候系统出现了故障、也可以在下次启动时、通过redis-check-aof工具来对其进行修复
在AOF文件中、有序的保存了所有写的操作指令、这些操作以redis的协议格式保存、因此通俗易懂
数据导出也非常简单、如果大家不小心执行了falushall命令、只要AOF文件未被重写、那么只需停止redis服务
移除AOF文件末尾的flushall命令、然后重启redis、这样即可把数据恢复到执行flushall之前的状态

2、AOF的缺点

对相同的数据集来说、AOF文件的体积要大于RDB文件的体积、根据同步策略、AOF的速度可能慢于RDB
AOF在恢复大数据集的时候、AOF的恢复速度要慢于RDB的恢复速度

3、AOF重写

AOF的运作方式为不断地将命令追加到文件的末尾、随着不断增加、AOF文件体积也会变大
为了压缩AOF文件、redis提供了bgrewriteaof命令、收到命令后redis将数据以命令的方式保存到临时文件中
以此来控制AOF文件的增长、由于是模拟快照、因此在重写时、并没有去读取旧的AOF文件、而是将整个内存当中的数据用命令方式重写了一个新的AOF文件、所以在使用AOF的时候、redis同时也推荐使用bgrewriteaof命令

4、重写运作方式

1、需要做持久化时、redis将fork出一个子进程
2、子进程开始将新AOF文件的内容写入到临时文件
3、对于新执行的写入指令、父进程将其累积到一个内存缓存、并把这些改动追加至现有AOF文件的末尾
4、当子进程完成重写时、会给父进程发送信号、父进程收到以后、将内存缓存中的数据追加至新AOF文件的末尾
5、到这一步差不多完成了、现在redis原子的用新文件替换旧文件、之后所有命令都会直接追加到新AOF文件的末尾

三、redis持久化实现

1)部署redis

1、安装依赖包

[root@redis ~]# yum -y install gcc gcc-c++ pcre pcre-devel zlib zlib-devel tcl tcl-devel

2、下载软件包

[root@redis ~]# wget -c http://download.redis.io/releases/redis-3.2.13.tar.gz

3、安装redis

[root@redis ~]# tar xf redis-3.2.13.tar.gz -C /usr/src/
[root@redis ~]# cd /usr/src/redis-3.2.13/
[root@redis redis-3.2.13]# make -j 8 && make PREFIX=/usr/local/redis install && cd ~

4、创建对应的存储目录

提示:依次排序、目录为:配置文件目录、PID目录、日志文件目录、数据存储目录、socket文件存储目录

[root@redis ~]# mkdir /usr/local/redis/conf
[root@redis ~]# mkdir /usr/local/redis/pid
[root@redis ~]# mkdir /usr/local/redis/logs
[root@redis ~]# mkdir /usr/local/redis/data
[root@redis ~]# mkdir /usr/local/redis/socket

5、复制范本文件

[root@redis ~]# cp /usr/local/redis/bin/* /usr/local/bin/
[root@redis ~]# cp /usr/src/redis-3.2.13/redis.conf /usr/local/redis/conf/
[root@redis ~]# cp /usr/local/redis/conf/redis.conf /usr/local/redis/conf/redis.conf.bak

6、将redis添加为系统服务

[root@redis ~]# cat > /usr/lib/systemd/system/redis.service << EOF
[Unit]
Description=redis
After=network.target

[Service]
Type=forking
LimitNOFILE=65535
ExecStart=/usr/local/bin/redis-server /usr/local/redis/conf/redis.conf

[Install]
WantedBy=multi-user.target
EOF

7、定义redis配置文件

[root@redis ~]# cat > /usr/local/redis/conf/redis.conf << EOF
bind 0.0.0.0
port 6379
timeout 180
daemonize yes
maxclients 6500
protected-mode yes
requirepass abc-123
tcp-backlog 2048
tcp-keepalive 300
databases 16

supervised no
syslog-enabled yes
syslog-ident redis
syslog-facility local0
loglevel notice
logfile "/usr/local/redis/logs/redis.log"
pidfile "/usr/local/redis/pid/redis.pid"
unixsocketperm 755
unixsocket "/usr/local/redis/socket/redis.sock"
slowlog-log-slower-than 5000
slowlog-max-len 128
dir "/usr/local/redis/data"

save 900 1
save 300 10
save 60 10000
rdbcompression yes
rdbchecksum no
dbfilename dump.rdb
stop-writes-on-bgsave-error no

appendonly yes
appendfsync everysec
aof-load-truncated yes
appendfilename appendonly.aof
no-appendfsync-on-rewrite no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
aof-rewrite-incremental-fsync yes

repl-diskless-sync no
repl-diskless-sync-delay 5
repl-disable-tcp-nodelay no
repl-backlog-size 1mb
repl-backlog-ttl 3600
slave-priority 100

hz 10
maxmemory-policy noeviction
activerehashing yes
hash-max-ziplist-value 64
hash-max-ziplist-entries 512
list-compress-depth 0
lua-time-limit 5000
notify-keyspace-events ""
list-max-ziplist-size -2
latency-monitor-threshold 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
hll-sparse-max-bytes 3000
client-output-buffer-limit normal 0 0 0
client-output-buffer-limit pubsub 32mb 8mb 60
client-output-buffer-limit slave 256mb 64mb 60
EOF

8、启动redis服务并将其设置为开机自启

[root@redis ~]# systemctl start redis
[root@redis ~]# systemctl enable redis
Created symlink from /etc/systemd/system/multi-user.target.wants/redis.service to /usr/lib/systemd/system/redis.service.
[root@redis ~]#
[root@redis ~]# netstat -anput | grep redis
tcp        0      0 0.0.0.0:6379            0.0.0.0:*               LISTEN      4244/redis-server 0

9、解决redis警告

[root@redis ~]# echo never > /sys/kernel/mm/transparent_hugepage/enabled
[root@redis ~]# echo "echo never > /sys/kernel/mm/transparent_hugepage/enabled" >> /etc/rc.local
[root@redis ~]# echo net.core.somaxconn = 4096 >> /etc/sysctl.conf
[root@redis ~]# echo vm.overcommit_memory = 1 >> /etc/sysctl.conf
[root@redis ~]# echo vm.swappiness = 0 >> /etc/sysctl.conf
[root@redis ~]# sysctl -p
[root@redis ~]# systemctl restart redis

2)RDB持久化实现

提示:redis默认使用RDB持久化、可在配置文件当中定义如下内容

save 900 1							#在900秒内、如果有一个键被改动、则自动保存一次数据集
save 300 10							#在300秒内、如果有十个键被改动、则自动保存一次数据集
save 60 10000						#在60秒内、如果有六十键被改动、则自动保存一次数据集
rdbcompression yes					#是否启动RDB文件压缩、不压缩文件很大、压缩则性能有所下降
rdbchecksum no						#是否对压缩之后的文件进行检查、关闭可提升性能
dbfilename rdbfile.rdb				#RDB文件的名字、可自定义、比如我这里为rdbfile.rdb
stop-writes-on-bgsave-error no		#当RDB快照后台进程失败、不影响用户的写操作

测试:往redis中写入数据、将redis服务器重启、之后查看数据是否还在

注意:如果将save关闭、那么就关闭了RDB的持久化

手动保存:RDB并不是实时将数据持久化、而是周期性的、这个时候为了数据的安全、我们可以手动保存数据

save:节约资源、因为会阻塞redis进程、服务器无法处理其它请求

bgsave:fork出一个子进程去完成持久化、父进程继续处理其它请求、但会消耗资源、因为fork出子进程

3)AOF持久化实现

提示:redis默认使用RDB持久化、可在配置文件当中开启AOF持久化、如下所示

appendonly yes						#开启AOF持久化
appendfsync everysec				#每秒都调用fsync刷新到AOF文件、如果为no则依靠系统进行刷新
appendfilename aoffile.aof			#AOF文件的名字、可自定义、比如我这里为aoffile.aof
no-appendfsync-on-rewrite no		#为yes、则redis执行的命令会存放到缓冲区、待系统自动同步到硬盘
auto-aof-rewrite-percentage 100		#当前写入的文件达到了上次rewrite文件大小的100%、则触发wewrite操作
auto-aof-rewrite-min-size 64mb		#定义重写文件的最小值、达到60M、符合100%条件时、则触发wewrite操作
aof-load-truncated yes				#在恢复的时候、忽略最后一条可能存在问题的指令
aof-rewrite-incremental-fsync yes	#开启增量文件同步策略、可减少AOF文件写入对磁盘的操作次数

测试:往redis中写入数据、将redis服务器重启、之后查看数据是否还在

注意:如果appendonly为no、则AOF持久化关闭、默认也是关闭的、但是AOF持久化也可以与RDB持久化可共存

【只是为了打发时间】

05-22 22:00