上篇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持久化可共存
【只是为了打发时间】