单线程,通过epoll实现高并发,端口6379
10年积累的成都网站设计、成都网站建设、外贸网站建设经验,可以快速应对客户对网站的新想法和需求。提供各种问题对应的解决方案。让选择我们的客户得到更好、更有力的网络服务。我虽然不认识你,你也不认识我。但先网站策划后付款的网站建设流程,更有团风免费网站建设让你可以放心的选择与我们合作。
linux下载地址:http://redis.io/download
windows下载地址:https://github.com/MSOpenTech/redis/releases
本文介绍的内容:
string:存字符串
hash:存名字和值
list:存列表
set:存集合
sort set:有序集合,带权值排序的集合,可以应用到学生对应的分数
发布和订阅
小技巧
系统下命令 | 参数 | 作用 | |
redis-cti -h ip port | ip:指定IP port:主机端口 | 在redis安装目录下运行,启动redis实例 | |
set name value | name:键名 value:键值 | 设置键名和键值 | |
get name | name:键名 | 获取键值 | |
set name value ex time | name :键名 value:键值 ex:指定存在时间 time:时间 | 设置键的存在时间,过期自动删除 | |
Python下命令: | |||
ConnectionPool(host,port) | host:redis服务器地址 port:端口 | 连接到redis服务器 | pool=redis.ConnectionPool(host='192.168.1.1',port=6379) |
Redis(connection_pool) | connection_pool:上面的链接 | 绑定链接实例 | conn=(connection_pool=pool) |
pipeline(transaction) | transaction:redis链接 | 创建管道 | pipe=redis.pipeline(transaction=conn) |
execute() | 提交操作 | pipe.excute() | |
通用操作 | |||
select(db) | db:redis数据库名。redis默认16个数据库。名字是0~15 | 选取并使用redis的数据库 | |
delete(*names) | *names | 删除对应的name | |
exists(name) | name | 判断key是否存在 | |
keys(pattern='*') | pattern:支持以正通配符 *:匹配任意多个字符 ?:只匹配一个字符 []:指定匹配[]的字符 以上可以搭配使用 | 匹配pattern指定的name
| |
expire(name,time) | name: time: | 为name设存活时间,过期自动删除 | |
rename(src,dst) | src: dst: | 把name由src改成dst | |
move(name,db) | name: db: | 把name移动到指定的db下,如果目标db已存在相同name,则不移动 | |
type(name) | name: | 查看name的类型 | |
randomkey() | 随机获取一个name | ||
scan(cursor,match,count) | cursor:默认0 match:默认None count:默认None | 从cursor开始,匹配符合match条件,只匹配count条 | |
scan_iter(match,count) | match: count: | 匹配count个,符合match条件的name,返回迭代器 | |
Redis() | host: port: connection_pool: | 连接到redis服务器 | |
ConnectionPool() | host: port: | 创建链接凭据,供Redis()方法使用 | |
pipeline(transaction,shard_hint) | transaction:默认False,不每次都与服务器交互 shard_hint:默认None | 创建一个道对象,使用管道对象进行set后,必须使用execute()方法,才能上传数据到redis服务端,减少了服务器和客户端的交互次数 | pipe=r.pipeline() pipe.set(name,value) |
execute() | 提交管道内容到redis服务器 | pipe.execute() | |
STR操作 | |||
set() | name:key名 value:key值 ex:过期时间,秒 px:过期时间,毫秒 nx:False。True:name不存在则set xx:False。True:name存在则set | 设置key和key值 | |
setnx(name,value) | name:key名 value:key值 | 如果key不存在,设置key和key值 | |
setex(name,value,time_s)
| name:key名 value:key值 time_s:过期时间,秒 | 设置key和key的值,到时间自动删除key | |
psetex(name,time_ms,value) | name:key名 value:key值 time_ms:过期时间,毫秒 | 设置key和key的值,到时间自动删除key | |
mset(*args,**kwargs) | 批量设置 | mset(r1='1',r2='2') 或: mset({r1:'1',r2:'2'}) | |
setbit() | name:key名 offset:偏移量 value:值 | 设置string的ASCII码,二进制位的值 | |
get() | name:key名 | 获取键值 | |
mget() | *args:多个key名,逗号分割 | 获取多个键值 | |
getset() | name:key名 value:值
| 获取当前键值,并设置新值 | |
getbit() | name:key名 offset:偏移量 | 获取string的ASCII码二进制位的值 | |
bitop('operation',dest,*keys) | operation:and(与)or(或)not(非)xor(异或) dest:新的redis名字 *keys:要查找的redis名 |
把要查找的redis名按operation进行二进制位运算,结果存放在dest里面 | bitop('and','result','r1','r2','r3') |
incr(name,amount) | name:key名 amount:只能是整型,默认是1 | 每次运行把name增量加amount,运行几次incr,name的值就是几 | |
decr(name,amount) | name:key名 amount:只能是整型,默认是1 | 每次运行把name字段减amount,运行几次decr,name就减几次,可以减到负值 | |
imcrbyfloat(name,amount) | name:key名 amount:可以是浮点型,默认1.0 | ||
strlen() | name:key名 | 返回name的字符串长度 | |
append(name,str) | name:key名 str:追加的字符 | 把str追加到name的后面 | |
HASH操作 | |||
hset(name,key,value) | name:redis的name | hash以字典存储 设置name[key]的值 | |
hsetnx(name, key, value) | name:redis的name | name中不存在当前key 设置key的值,存在则不修改 | |
hget(name,key) | name:redis的name key:name对应的hash中的key | 获取neme中key的值 | |
hkeys(name) | name:redis的name | 获取name对应的hash中所有的key的名字 | |
hvals(name) | name:redis的name | 获取name对应的hash中所有的key的值 | |
hmset(name,dict) | name:redis的name dict:字典,如:{'k1':'v1', 'k2': 'v2'} | 批量设置name的哈希值 | |
hgetall(name) | name:redis的name | 获取name对应hash的所有键值 | |
hmget(name,*keys) | name:redis的name *keys:['k1', 'k2']或'k1', 'k2' | 一次获取指定的多个key值 | |
hdel(name,*keys) | name:redis的name *keys:['k1', 'k2']或'k1', 'k2' | 删除name中的keys | |
hlen(name) | name: | 获取name中keys的个数 | |
hexists(name,key) | name: key: | 检查name的key是否存在 | |
hdel(name,*keys) | name: *keys: | 删除 | |
hincrby(name,key,amount) | name: key: amount:默认1,可指定。 | 自增name中key的值,不存在则创建新key key=amount | |
hincrbyfloat(name,key,amount) | name: key: amount:默认1.0,可指定其浮点数。 | 自增name中key的值,不存在则创建新key key=amount | |
hscan(name,cursor,match,count) | name: cursor:默认0,指定游标位置。从哪开始查。 match:默认None,匹配表达式。 count:默认None | 查找指定key **增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆 | 从位置0开始,查找info中的包含a的字段,并且只找前三个 hscan('info',0,'*a*',3) |
hscan_iter(name,match,count) | name: match:匹配指定key,默认None 表示所有的key count:每次分片最少获取个数,默认None表示采用Redis的默认分片个数 | 查找指定key,并返回迭代器,读取时循环迭代器 | for item in r.hscan_iter('xx'): print item |
LIST操作 | |||
lpush(name,values) | name:表名 values:值。 1, 2, 3 | 向name表里存values,新的在左边,先入后出 | |
lrange(name,start,end) | name: start:开始位置 end:结束位置 | 取列表 取所有start=0,end=-1 | |
rpush(name,values) | name:表名 values:值。 1, 2, 3 | 向name表里存values,新的在右边,后入先出 | |
rrange(name,start,end) | |||
lpushx(name,values) | name:表名 values:值。 1, 2, 3 | 列表存在才存 | |
llen(name) | name:表名 | 返回列表个数 | |
linsert(name,where,refvalue,value) | name:表名 where:before或after refvalue:标杆值,在它的前或后插入 value:要插入的数据 | 在name表的某一个值前或后插入一个新值 | |
lset(name,index,value) | name:表名 index:修改索引第几个参数,从0开始 value:修改的值 | 修改 | |
lrem(name,value,num) | name:表名 value:要删除的值 num:0删除表中所有的value指定值 2 从前到后,删除两个 -2 从后到前,删除两个 | 删除 | |
lpop(name) | name: | 从左向右读取一个值,并删除 | |
lrange(name,start,end) | name: start: end: | 获取name表分片数据 | |
lindex(name,index) | name: index:下标 | 读取指定下标的值 | |
ltrim(name,start,end) | name: start: end: | 保留start到end之间的数据,其它删除 | |
rpoplpush(src,dst) | src: dst: | 从src表的最右边取出数据 存放到dst表的最左边 | |
blpop(keys,timeout) | keys:redis name的集合 timeout:默认为0。超时时间,所有的元素取完以后,等待timeout秒,0为永远阻塞 | 从列表左边取出并删除redis name所有元素,并等待timeout秒 等待期间,其它用户放入值,会继续删除 | |
brpop(keys,timeout) | keys: timeout | 从列表右边取出并删除redis name所有元素,并等待timeout秒 | |
brpoplpush(src,dst,timeout) | src: dst: timeout: | 从src列表右边取出并删除元素,存入dst列表的左边。 | |
SET操作 | |||
sadd(name,*values) | name: values: | 集合有去重特性,所以重复数据不能添加 | |
smembers(name) | name: | ||
scard(name) | name: | 获取元素个数 | |
sdiff(*keys) | *keys:多个redis 的name
| 获取前者的差集,只显示第一个集合中,其它集合没有的元素 | sdiff("name1","name2") |
sdiffstore(dst,*src) | dst: *src: | 将只存在src1集合里,不存在src2,src3等等的元素,存放到dst里。 | |
sinter(*keys) | *keys:多个redis 的name | 交集,显示几个keys里都有的元素 | |
sinterstore(dst,*src) | 交集,把几个src中都有的元素存到dst里 | ||
sunion(*keys) | *keys: | 并集,把所有keys里的元素相加 | |
sunionstore(dst,*src) | dst: *src: | ||
sismember(name,value) | name: value: | 查找name里面的value成员 有返回1,没有返回0 | |
smove(src,dst,value) | src: dst: value: | 将value从src移动到dst | |
spop(name) | name: | 从集合的后面删除元素,并返回值 | |
srandmember(name,numbers) | name: numbers:默认1 | 随机返回numbers个元素 | |
srem(name,value) | name: value: | 删除name里指定的value | |
sscan(name,index,match,count) | name: index: match: count: | ||
sscan_iter(name,match,count) | name: match: count: | ||
有序集合 | |||
zadd(name,*args,**kwargs) | name: *args: **kwargs" | 把权重和值放入name里面 数越小,值越在前 如查value和权重值已存在,修改权重为当前权重 | redis.zadd('my-key', 'name1', 1.1, 'name2', 2.2, name3=3.3, name4=4.4) |
zcount(name,min,max) | name: min: max: | 获取min到max分数的个数(包含min和max) | |
zcard(name) | name: | 统计name里元素的个数 | |
zrange(name,start,end,desc,withscores,score_cast_func) | name: start:元素起始位置 end: desc:默认False,从小到大排序,True从大到小排序。 withscores:默认False,只获取元素的值。True获取值和分数。 score_cast_func:默认float,可以对分数进行类型的转换 | 取出name中,从start到end的元素 全取:0 -1
应用场景,可以保存成绩。。。 | |
zrevrange(name,start,end,withscores,score_cast_func) | name: start:元素起始位置 end: withscores:默认False,只获取元素的值。True获取值和分数。 score_cast_func:默认float,可以对分数进行类型的转换 | 获取指定位置的值和分数,从大到小排序 | |
zrangebyscore(name,min,max,start,num,withscores,score_cast_func) | name: min: max: start:默认None num:默认None withscores:默认False,只获取元素的值。True获取值和分数。 score_cast_func:默认float,可以对分数进行类型的转换 | 按照分数范围,从start(value)位置开始,获取name中的有序集合的元素,顺序从小到大 | |
zrevrangebyscore(name,min,max,start,num,withscores,score_cast_func) | name: min: max: start:默认None num:默认None withscores:默认False,只获取元素的值。True获取值和分数。 score_cast_func:默认float,可以对分数进行类型的转换 | 从大到小排序。 | |
zincrby(name,value,amount) | name: value: amount:默认1 | 运行一次,value的值增加amount指定的数值。 | |
zrank(name,value) | name: value: | 获取value在name中的index(从0开始) | |
zrevrank(name,value) | name: value: | 获取value在name中的index(从0开始), 从大到小 | |
zrangebylex(name,min,max,start,num) | name: min:左区间,+表示正无限,-表示负无限,(表示开区间,[表示闭区间。 max:右区间 start:默认None,对结果进行分片,从start开始。 num:默认None,对结果进行分片,从start开始显示num个 | 当有相同的分数时,对value进行匹配。 | |
zrem(name,value) | name: value: | 删除集合中value的元素 | |
zremrangebyrank(name,min,max) | name: min: max: | 删除排行(index)从min到max范围的元素 | |
zremrangebyscore(name,min,max) | name: min: max: | 删除分数是min到max范围的元素 | |
zremrangebylex(name,min,max) | name: min: max: | 删除值是min到max范围的元素 | |
zscore(name,value) | name: value: | 获取value的分数 | |
zinterstore(dest,keys,aggregate) | dest: keys: aggregage:默认None,分数按sum。可以为sum,min,max | keys的交集,存储到dest,keys对应的分数,按aggregage操作 | |
zunionstore(dest,keys,aggregate) | dest: keys: aggregage:默认None,可以为sum,min,max | 并集,存储到dest, | |
zscan(name,cursor,match,count,score_cast_func) | name cursor: match: count: score_case_func:默认float,可以对分数进行类型的转换 | 从cursor开始查找符合match的元素,查找count个 | |
zscan_iter(name,match,count,score_cast_func) | name: match: count: score_cast_func: | 从cursor开始查找符合match的元素,查找count个,返回迭代,需要循环读取。 | |
发布和订阅:
redis自带命令 | |||
PSUBSCRIBE pattern [pattern...] | 订阅一个或多个符合给定模式(条件)的频道。 支持*通配符 | ||
PUNSUBSCRIBE [pattern[pattern...]] | 退订所有给定模式(条件)的频道 支持*通配符 | ||
PUBSUB | 查看订阅与发布系统状态 | ||
PUBLISH channel message | 将信息发送到指定的频道。 | ||
SUBSCRIBE channel [channel...] | 订阅给定的一个或多个频道的信息。 | ||
UNSUBSCRIBE channel [channel...] | 命令用于退订给定的一个或多个频道的信息。 | ||
Python模块命令 | |||
subscribe | |||
publish | |||
事务:
事务开始后,所有的操作必须提交,否则不保存到数据库
MULTI | 事务开始 | ||
EXEC | 事务结束 | ||
问题:
1、1亿在线用户查询:
把数据库里的自增ID写进offset,在线则设置为1,下线清除掉。一个用户状态只占一个二进制位。
setbit(n5,1,1)
setbit(n5,2,1)
......
统计用户在线,使用bitcount(n5),就可以了。
查看用户是否在线,使用getbit(n5,999),返回0,不在线;返回1在线。
2,验证码
我们经常在登录一些网站或是进行付款等操作的时候,都会收到一些验证码,并且说10min后失效。
实际上就可以通过下面一条指令来实现:
set phone_num code ex 600
用手机号作为key,验证码作为值,超时6min。这样当你输入好验证码,提交的时候,后台就可以了先get phone_num,再比较你的输入和数据库里面存的值,从而完成身份的验证。
3,session
早前,网站通过cookie来保存用户的用户名和密码,之后出现了很多的安全隐患,因此就提出了session的机制。
用户登陆成功之后,本地的cookie会保留一个较长的随机码,而网站后的后台则存储了这个随机码和你的用户id的对应关系。在你第二次登录的时候,cookie会传输到后台,而后台则根据你的随机码,获取你的用户信息,如果符合,则自动登录。这样,即使网站上有不法分子获取了你的cookie,也得不到你的任何信息,因为你的真实的有用的信息都存储在网站的后台。
我们在登录邮箱的时候,通常都会有一个选项,7天内自动登录。这其实就是给后台存的session设置了一个超时。聪明的你是不是已经会自己实现了呢?
NX:(if Not eXist)只有键key不存在的时候才会设置key的值
XX:只有键key存在的时候才会设置key的值
NX通常用于实现锁机制,XX的功能,小喵暂时木有头绪。。。想到应用场景的筒子们可以留言告诉小喵,小喵看到了一定会更新的。
系统下命令参考:
http://www.runoob.com/redis/redis-tutorial.html
https://www.cnblogs.com/idiotgroup/p/5455282.html
https://www.cnblogs.com/xtsec/p/7000404.html