目录
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
Redis完整命令参见:http://redisdoc.com/index.html
安装:
-
下载(https://github.com/MSOpenTech/redis/releases)安装包,安装;
-
在命令行界面中执行:redis-server.exe redis.windows.conf,默认端口6379;
-
启动客户端:redis-cli.exe (通过info命令可查看基本信息)
-
安装redis-py:pip install redis
-
简单测试(Python):
import redis
r=redis.Redis()
r.set('foo','bar')
Out[35]: True
r.get('foo')
Out[36]: b'bar'
redis-cli连接
redis-cli -c -h host -p port -a password
// -h 服务器地址 -p 端口号 -a 密码
// -c 启用集群功能,若是集群,需要此命令
- ping:测试连接
- info:查看redis信息
- cluster nodes:查看集群节点
五种数据类型
string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
-
string:可以是字符串、整数或浮点数;整数和浮点数可执行自增(increment)或自减(decrement)操作;
-
list:链表(双向链表),每个节点都是一个字符串;从链表两端推入或弹出元素;根据偏移量修剪(trim)链表;读取单个或多个元素;根据值查找或移除元素;
-
set:包含字符串的无序集合(unordered collection),且保证唯一;添加、获取、移除单个元素;检查元素是否在集合中;计算交集、并集、差集;从集合中随机获取元素;
-
hash:包含键值对的无序散列表;添加、获取、移除单个键值对;获取所有键值对;
-
zset:有序集合(散列表+跳跃表skiplist),是字符串与对应分值(score,浮点型)的集合,字符串唯一且通过分值排序,分值可以重复;添加、获取、移除单个元素;根据分值范围(range)或成员获取元素;
type <key>:可获取键值对应的类型;
redis-benchmark.exe:可测试性能
字符串string
string可以存储:字符串(byte string)、整数(32位系统32位,64位系统64位)、浮点数(double);
自增、自减:
-
incr <key>:加1;若<key>不存在,设为0(即赋值为1);
-
decr <key>:减1;若<key>不存在,设为0(即赋值为1);
-
incr <key> <count>:加count;
-
decr <key> <count>:减count;
-
incrbyfloat <key> <count>:加上浮点值count;
处理子串(索引从0开始)和二进制:
-
strlen <key>:返回字符串长度;
-
append <key> <value>:在后面追加value;
-
getrange <key> <start> <end>:获取指定偏移处子串[start, end];
-
setrange <key> <offset> <value>:插入value;
-
getbit <key> <offset>:将字符串看做二进制位串(bit string),返回offset处二进制值;
-
"12"视为:"0000000100000010";只有7与14处为1,其他参数获取都为0(包括很大的数字,超过实际长度时);
-
-
setbit <key> <offset> <value>:看做二进制位串,插入value;
-
bitcount <key> [start end]:统计二进制位串中1的数量;
-
bitop <op> <destkey> key1 [key2 ... ]:二进制操作,结果保存到destkey中
-
and:并
-
or:或
-
xor:异或
-
not:非
-
setrange、setbit写入时若偏移超过字符串长度,则redis使用空字节(null)扩展字符串至所需长度,然后更新;getrange读取时,超过字符串长度部分视为空串,getbit读取时,超过部分视为0。
列表list
允许用户从列表两端推入或弹出元素,获取元素及常见的列表操作。
常用命令:
-
rpush/lpush <key> <value> [val1 ... ]:将一个或多个值推入列表;
-
rpop/lpop <key>:移除最右端或左端元素;
-
lindex <key> <offset>:返回指定位置元素(偏移从0开始);
-
lrange <key> <start> <end>:返回[start, end]范围内元素;
-
ltrim <key> <start> <end>:修剪,只保留[start, end]范围内元素;
-
移除所有:ltrim c1 1 0(start<end,且非负);
-
-
llen <key>:返回列表长度;
-
lrem <key> <count> <value>:搜索列表,移除指定数量的指定值;count说明:
-
>0:从头向尾搜索,移除count个value;
-
<0:从尾向头搜索,移除count个value;
-
=0:移除所有指定value;
-
阻塞与移动命令:
-
blpop/brpop <key> [key1 ... ] <secs>:从列表中弹出元素,若没有则等待secs秒;
-
rpoplpush <src-key> <dest-key>:移动元素,从src-key右端弹出元素,并从dest-key左端推入;
-
brpoplpush <src-key> <dest-key> <secs>:阻塞式移动元素;
集合set
以无序的方式来存储多个各不相同的元素,可快速地对集合执行添加、移除、检查是否存在。
常用命令:
-
sadd <key> <item> [item1 ... ]:将一个或多个元素加入到集合中,返回实际加入的元素(原本不在集合,本次添加的)个数;
-
srem <key> <item> [item1 ... ]:从集合中移除一个活多个元素,返回移除的数量;
-
sismember <key> <item>:检查item是否在集合中;
-
scard <key>:返回集合中元素数量;
-
smembers <key>:返回集合中所有元素;
-
srandmember <key> [count]:从集合中随机返回一个或多个元素;count为返回数量:
-
为正数时,返回值不会重复(实际数量少于count时,返回实际数量的元素),
-
为负数时(会返回指定数量元素,不足重复)可能会重复;
-
-
spop <key>:随机移除元素,返回被移除的元素;
-
smove <src-key> <dest-key> <item>:从src-key(存在元素时)中移动元素到dest-key集合中;成功返回1,失败返回0;
组合与多集合:
-
sdiff <key> [key1 ...]:返回差集,存在于第一个集合、但不存在于其他集合中元素;
-
sdiffstore <dest-key> <key> [key1 ...]:将存在于第一个集合、但不存在于其他集合中元素存储到dest-key集合中;
-
sinter <key> [key1 ...]:返回交集;
-
sinterstore <dest-key> <key> [key1 ...]:将交集存储到dest-key中;
-
sunion <key> [key1 ...]:返回并集;
-
sunionstore <dest-key> <key> [key1 ...]:将并集存储到dest-key中;
散列hash
可将多个键值对存储到一个redis键中
增删命令:
-
hmget <hkey> <key> [key1 ...]:获取一个或多个键的值;hget获取一个键的值;
-
hmset <hkey> <key value> [key1 val1 ...]:设定一个或多个键值;hset设定一个键值;
-
hdel <hkey> <key> [key1 ...]:删除一个或多个键值;
-
hlen <hkey>:获取键值对数量;
其他常用命令:
-
hexists <hkey> <key>:是否存在;
-
hkeys <hkey>:所有键;
-
hvals <hkey>:所有值;
-
hgetall <hkey>:所有键值对;
-
hincrby <hkey> <key> <count>:加count;
-
hincrbyfloat <hkey> <key> <fcount>:加浮点数;
有序集合sorted set
存储着成员与分值间的映射,并提供分值处理命令(分值不同时按分值排序,相同时按成员名排序)
常用命令:
-
zadd <key> <score mem> [score1 mem1 ...]:增加一个或多个带分值的成员到有序集合中;
-
zrem <key> <mem> [mem1 ...]:从有序集合中移除给定成员,返回移除数量;
-
zcard <key>:成员数量;
-
zincrby <key> <count> <mem>:将成员mem分值增加count;
-
zcount <key> <min> <max>:分值介于[min, max]间成员数量;
-
zrank <key> <mem>:返回mem的排名(由小到大,从0开始,相同分值的按添加先后);
-
zscore <key> <mem>:成员分值;
-
zrange <key> <start> <stop> [withscores]:返回排名介于[start, end]范围内(由小到大,从0开始计)的成员;
进阶命令:
-
zrevrank <key> <mem>:返回成员排名(由大到小,从0开始);
-
zrevrange <key> <start> <stop> [withscores]:返回排名介于[start, end]范围内(由大到小,从0开始计)的成员;
-
zrangebyscore <key> <min> <max> [withscores] [limit offset count]:返回介于[min, max]间的成员;zrevrangebyscore 为反序(从大到小)
-
zremrangebyrank <key> <start> <stop>:移除指定排名范围内成员;
-
zremrangebyscore <key> <min> <max>:移除指定分值范围内成员;
-
zinterstore <dest-key> <key-count> <zkey> [zkey1 ...] [weights w1 [w2 ...]] [aggregate sum|min|max]:计算交集,并存储到dest-key中;
-
key-count:后面键的数量(几个集合做交集);
-
weights:每个集合的权重(score*weight作为新的score);
-
aggregate:合并方式(同名成员的score值如何处理:加、最小、最大);
-
-
zunionstore <dest-key> <key-count> <zkey> [zkey1 ...] [weights w1 [w2 ...]] [aggregate sum|min|max]:计算并集;
发布与订阅
发布者与订阅者通过频道(channel)关联,当有消息发送(publish)到频道是,所有此频道的订阅者都会收到消息;
发布订阅命令:
-
subscribe <channel> [ch1 ...]:订阅一个或多个频道;
-
unsubscribe [ch1 ...]:退订一个或多个频道;若没有给出频道参数,则退订所有频道;
-
publish <channel> <msg>:向指定频道发消息;
-
psubscribe <pattern> [pat1 ...]:订阅指定模式频道(*作为通配符);
-
punsubscribe <pattern> [pat1 ...]:退订指定模式频道;
其他命令
排序:
Sort src-key [By pattern] [Limit offset count] [Get pattern [Get pat1 ...]] [ASC|DESC] [Alpha] [Store dest-key]
-
Alpha:默认为数值排序,使用Alpha指示按字符方式排序;
-
By pattern:按照指定的模式排序
sort时,hash中子键可通过->获取,如(根据分数,对三个散列表排序,并返回名称与分数):
lpush c1 ch math en
hmset c.math name n1 score 100
hmset c.en name n2 score 80
hmset c.ch name n3 score 70
sort c1 by c.*->score get c.*->name get c.*->score
事务操作
事务可以让一个客户端在不被其他客户端打断的情况下执行多条命令。
先执行multi命令,然后输入要执行的命令(redis会放入一个队列中),最后接收到exec时,开始统一执行所有命令。
在multi之前可用watch监视键是否被更改(若更改,执行exec命令时会失败);通过unwatch/discard来取消监视或撤销操作命令。
watch是乐观锁。可以通过后面介绍的lua脚本替换,以获取更好的性能。
通过setnx(set if not exists)也可以方便的模拟锁(与expire配合使用,可以有效避免死锁):
-
exists <key>:判断键是否存在
-
setnx <key> <value>:若不存在,则添加,且返回1;否则返回0;
-
get <key>:获取设定的值;
可用set扩展实现设定值与超时:
SET key value [EX seconds] [PX milliseconds] [NX|XX]
-
EX second :设置键的过期时间为 second 秒。
-
PX millisecond :设置键的过期时间为 millisecond 毫秒。
-
NX :只在键不存在时,才对键进行设置操作。
-
XX :只在键已经存在时,才对键进行设置操作。
键过期(expire)
通过过期时间(expiration)特性,让一个键在给定的时限后自动被删除;
命令:
-
persist <key>:移除键的过期时间;
-
ttl <key>:查看距离过期还有多少秒;
-
expire <key> <seconds>:设定多少秒后过期;
-
expireat <key> <timestamp>:设定过期时间(UNIX时间戳);
-
pttl <key>:查看距离过期还有多少毫秒;
-
pexpire <key> <millseconds>:设定多少毫秒后过期;
-
pexpireat <key> <timestamp-ms>:精确到毫秒的时间戳;
数据持久化
持久化,Redis提供了两种数据持久化方法:
-
快照(snapshotting):将某一时刻的所有数据写入硬盘里;
-
save <seconds> <changes>:在指定时间内有超过指定数量改动时,做快照;
-
save "" :取消所有快照;
-
dbfilename dump.rdb:快照保存文件名;
-
dir ./:文件保存路径;
-
redis-check-dump:检测文件是否完整的小程序
-
-
只追加文件(append-only file,AOF):在执行写命令时,将被执行的写命令复制到硬盘里;
-
appendonly yes/no:是否启动AOF;
-
appendfilename "appendonly.aof":保存文件
-
appendfsync always/everysec/no:如何同步
-
auto-aof-rewrite-percentage 100
-
auto-aof-rewrite-min-size 64mb
-
bgrewriteAOF:当AOF文件过大时,可通过此命令重写AOF文件;若设定了auto-aof-rewrite*,则文件超过min-size,且比上次大-percentage时,会重写(会fork一个进程写)。
-
redis-check-aof:检测文件是否完整的小程序
-
创建快照方法:
-
bgsave:客户端发送备份命令;
-
save:同步备份(在备份完成前,不能响应其他命令);
-
在配置文件中设定:save <seconds> <changes>;
-
接收到shutdown关闭命令强求时(或者标准term信号),会执行save;
-
redis间发送sync命令进行复制操作时,主服务器会执行bgsave操作;
bgsave比save消耗更多的时间:因bgsave需要先fork一个进程,并复制所有数据,但是不会中断对客户端命令的处理。
多服务器扩展
主从服务器(Redis不支持主主服务器),从服务器下还可以挂从服务器,从而形成主从从服务器(当从服务器从主服务器更新数据时,会断开从从服务器,让其重连,以获取新的数据):
当从服务器连接到主服务器时:
-
主服务器会执行bgsave操作(因此,主服务器必须正确配置dir与dbfilename,保证可写),创建一个快照文件以发送给从服务器;
-
从服务器需要开启slaveof;
-
slaveof no one:终止复制操作,不再接受主服务器的数据更新;
-
slaveof host port:开始复制一个新的主服务器;
-
接受到主服务器的快照文件后,会清空(原有数据全部丢失)后载入快照文件;
-
从服务器树
为扩展Redis的服务能力,可通过增加只读从服务器实现;但多从服务器时,就遇到重同步(resync)问题;为此可通过从服务器来解决。
内存节约
压缩列表(ziplist):
压缩列表是一个非结构化表示,用于需要降低内存(对项数与值的长度都有要求,一般小于512项,值长度小于64)的情况下,替代列表、散列和有序集合。是由节点组成的序列,每个节点由两个长度值和一个字符串组成:
-
第一个长度值,记录前一个节点的长度,用于前向遍历;
-
第二个长度值,记录当前节点的长度,用于后向遍历;
整数集合(intset):
整数集合是以有序整数数组的方式存储的集合;若所有成员都为十进制整数,且有在平台的有符号整数范围内,且数量足够少(默认少于512)的集合;
当数据较多时,可以通过分片的方式,降低每片记录数量,从而通过压缩列表与整数集合,来减少内存的消耗。
lua脚本
所有脚本执行都是原子的(Redis会把Eval和EvalSHA看做单个命令,而redis中每个单独命令都是原子的)。因此,执行lua脚本时,redis将无法为其他客户端提供服务:
-
脚本执行超过lua-time-limit(默认5s)后,可通过命令杀死:
-
若脚本没有写操作:script kill,杀死脚本;
-
若脚本已做个写入:shutdown nosave,杀死redis服务器,并丢弃最近快照或AOF;
-
-
脚本应是纯函数:即参数相同时,任何情况下执行的结果是相同的;
-
脚本内不允许创建全局变量;
-
redis内置lua库:
-
base
-
table
-
string
-
math
-
debug
-
cjson
-
cmsgpack
-
-
redis.log(level, msg):记录日志,level为:
-
redis.LOG_DEBUG
-
redis.LOG_VERBOSE
-
redis.LOG_NOTICE
-
redis.LOG_WARNING
-
script命令(控制脚本):
-
SCRIPT FLUSH :清除所有脚本缓存
-
SCRIPT EXISTS <sha1>:根据给定的脚本校验和,检查指定的脚本是否存在于脚本缓存
-
SCRIPT LOAD <script>:将一个脚本装入脚本缓存(不立即运行它),返回一个SHA值(以后通过Evalsha执行此脚本)
-
SCRIPT KILL :杀死当前正在运行的脚本
Eval执行脚本
EVAL script numkeys key [key ...] arg [arg ...]
-
script:一段lua5.1脚本(不要定义为lua函数),会在redis服务器上下文中运行;
-
numkeys key [key ...]:键名参数及个数,通过KEYS[n](从1开始)在脚本中引用;
-
arg [arg ...]:附加参数,通过ARGV[N] (从1开始)在脚本中引用;
在脚本中可通过redis.call()与redis.pcall()执行redis命令:
-
call:发生错误时,脚本停止执行并返回一个脚本错误(输出信息说明错误造成的原因);
-
pcall:出错时并不引发(raise)错误,而是返回一个带err域的table来表示错误;
eval "return redis.call('set', KEYS[1], ARGV[1])" 1 mykey myvalue
lua与redis间类型转换(正常情况下是一一对应的):
-
redis转换到lua:
-
integer reply -> number
-
bulk reply -> string
-
multi bulk reply -> table
-
status reply -> table with single ok field containing the status
-
error reply -> table with single err field containing the error
-
nil bulk or nil multi bulk reply -> boolean false
-
-
lua转换到redis:
-
number -> integer reply
-
string -> bulk reply
-
table(array) -> multi bulk reply
-
table with single ok field -> status reply
-
table with single err field -> error reply
-
boolean false -> nil bulk reply
-
-
例外: lua boolean true -> redis integer reply of 1
EvalSHA执行已加载脚本:
EVALSHA sha1 numkeys key [key ...] arg [arg ...]