资源链接 推荐书籍:《redis入门指南》 资源列表: redis命令速查command | cmd索引-中文 | cmd树-中文 redis源码github 下载地址redis.io the little redis book 入口 redis资料概要 @江南白衣 gist redis资料汇总专题 nosqlfan (这个站有很多文章) redis的设
资源链接推荐书籍:《redis入门指南》
资源列表:
redis命令速查command | cmd索引-中文 | cmd树-中文
redis源码github
下载地址redis.io
the little redis book 入口
redis资料概要 @江南白衣 gist
redis资料汇总专题 nosqlfan (这个站有很多文章)
redis的设计与实现 文档
redis2.6带注释源码 github
redis 各种语言clientsclients
python redis cli redis-py
网络文章汇总 入口
文章列表:
十五分钟介绍redis数据结构 入口
redis的订阅与发布 入口
redis之七种武器 入口
使用redis的五个注意事项 入口
redis源码分析系列文章 入口
largest redis clusters ever 入口 (使用场景)
成人网站youporn使用redis之经验谈 入口
相关项目
redis监控web工具 redmon
简介简介redis(remote dictionary server),远程字典服务器,以字典结构存储数据,允许通过tcp协议读取字典中内容. 高性能键值对数据库
作用:
1.缓存系统: 可以为每个键设置ttl(time to live),生存时间到期后键会自动被删除 可限定数据占用最大内存空间,数据大道空间限制后自动按照一定规则淘汰不需要键2.任务队列: redis列表类型可以用来实现队列, 支持阻塞式读取,很容易用作高性能队列,还支持“发布/订阅“消息的模式
其他:
1.redis中, 所有数据都存储在内存中, 但提供了持久化支持, 内存中数据可以异步写入硬盘, 不影响现有服务2.与memcached对比, redis单线程模型, memcached支持多线程. 但redis支持高级数据类型和持久化
安装安装
1.wget http://download.redis.io/releases/redis-2.6.16.tar.gz2.tar -xzvf redis-2.6.16.tar.gz3.cd redis-2.6.164.make5.make install
osx
brew install redis
安装后,在/usr/local/bin下面有
redis-server 服务器, 重点redis-cli 命令行客户端, 重点redis-benchmark 性能测试工具redis-check-aof aof文件修复工具redis-check-dump rdb文件检查工具
启动
直接启动
redis-server #默认6379redis-server --port 6380# 启动命令中配置将覆盖配置文件中同名参数redis-server /path/to/redis.conf --loglevel warning
通过初始化脚本运行(生产环境)
在安装包目录redis-2.6.16/utils/redis_init_script1.将脚本复制到/etc/init.d目录下,文件名为 redis_端口号, 修改文件第六行 redisport为相同端口号2.建立目录 /etc/redis 存放配置文件 /var/redis/端口号 存放持久化文件3.修改配置文件 将配置文件redis-2.6.16/redis.conf 复制到/etc/redis目录下,以端口号命名 e.g. 6379.conf 修改配置文件中部分参数 daemonize yes 使redis以守护进程模式运行 pidfile /var/run/redis_端口号.pid 设置redis的pid文件按位置 port 端口号 设置监听的端口号 dir /var/redis/端口号 设置持久化文件存放位置
停止
redis-cli shutdown//server断开所有客户端连接, 根据配置执行持久化, 最后退出
redis命令行客户端
发送命令: redis-cli -h 127.0.0.1 -p 6379 redis-cli ping redis-cli命令返回值 状态回复,e.g. >ping 错误恢复, e.g. >ecmd 整数回复, e.g. >incr foo 字符串回复,e.g. >get foo >get notexists` 多行字符串回复,e.g. >keys *
五种数据类型及相应命令基础命令(redis-cli)
返回符合规则的键名列表pattern支持通配符, ? * [] 等, 会遍历所有键, 当键的数量较多时影响性能
>keys pattern
e.g.
>set bar 1>keys *
判断一个键是否存在返回,0不存在,1存在
>exists key
e.g.
127.0.0.1:6379> exists bar(integer) 1127.0.0.1:6379> exists foo(integer) 0
删除键可以删除多个键, 返回删除的个数
>del key [key ...]
e.g.
127.0.0.1:6379> del bar(integer) 1127.0.0.1:6379> del bar(integer) 0
获取键值的数据类型返回string,hash(散列),list(列表),set(集合),zset(有序集合)
>type key
e.g.
127.0.0.1:6379> set bar 1ok127.0.0.1:6379> type barstring
1. 字符串类型最基本类型, 能存储任何形式/编码字符串, 包括二进制. 允许存储最大容量是512m
赋值和取值命令
>set key value>get key
e.g.
127.0.0.1:6379> set hi hello worldok127.0.0.1:6379> get hihello world127.0.0.1:6379> get abc(nil)
递增数字(当存储的字符串是整数形式时)
当操作键不存在时,默认值0,第一次递增后结果1,当键值不是整数时,报错>incr key原子操作,可用于类似访问量统计, 自增id>incrby key increment>incrby bar 2
e.g.
127.0.0.1:6379> incr abc(integer) 1127.0.0.1:6379> get abc1127.0.0.1:6379> incrby abc 2(integer) 3127.0.0.1:6379> get abc3
减少数字
>decr key>decrby key decrement
e.g.
127.0.0.1:6379> decr abc(integer) 2127.0.0.1:6379> decrby abc 2(integer) 0
浮点数
>incrbyfloat key increment>incrbyfloat bar 2.7
e.g.
127.0.0.1:6379> get bar1127.0.0.1:6379> incrbyfloat bar 1.52.5
向尾部追加
返回追加字符串长度>append key value
e.g.
>set key hello>append key world
获取字符串长度
>strlen key
e.g.
127.0.0.1:6379> get hihello world127.0.0.1:6379> strlen hi(integer) 11
同时设置,获取多个键值
>mget key [key ...]>mset key value [key value ...]
e.g.
127.0.0.1:6379> mset k1 v1 k2 v2ok127.0.0.1:6379> get k1v1127.0.0.1:6379> mget k1 k21) v12) v2
位操作
>getbit key offset>setbit key offset value>bitcount key [start] [end] #获取值为1的二进制位个数>bitop operation destkey key [key ...] #对多个字符串类型键进行位运算, 并将结果存储到destkeye.g. bitop or res fol fo2 get res
e.g.
a 97 01100001127.0.0.1:6379> set k 'a'ok127.0.0.1:6379> get ka127.0.0.1:6379> getbit k 0(integer) 0127.0.0.1:6379> getbit k 1(integer) 1127.0.0.1:6379> bitcount k(integer) 3
bp: redis对键的命名, 对象类型:对象id:对象属性
2. 散列类型一种字典结构,其存储了字段(field)和字段值映射,但字段值只能是字符串,不支持其他数据类型(即散列类型不支持数据类型嵌套)
散列类型适合存储对象
对象类型:id - 对象属性 - 对象属性值
基本命令
>hset key field value>hget key field#hset不区分插入更新>hmset key field value [field value ...]>hmget key field [field ...]>hgetall key
e.g.
127.0.0.1:6379> hset car name bmw(integer) 1127.0.0.1:6379> hget car namebmw127.0.0.1:6379> hmset car price 100 score 50ok127.0.0.1:6379> hmget car name price score1) bmw2) 1003) 50127.0.0.1:6379> hgetall car1) name2) bmw3) price4) 1005) score6) 50
判断字段是否存在
#存在返回1,否则返回0>hexists key field
e.g.
127.0.0.1:6379> hexists car name(integer) 1127.0.0.1:6379> hexists car model(integer) 0
当字段不存在时赋值
#已存在不进行任何操作, 不存在赋值>hsetnx key field value
e.g.
127.0.0.1:6379> hsetnx car name abc(integer) 0127.0.0.1:6379> hget car namebmw127.0.0.1:6379> hexists car model(integer) 0127.0.0.1:6379> hsetnx car model 1(integer) 1127.0.0.1:6379> hget car model1
增加数字
>hincrby key field increment
e.g.
>hincrby person score 60
删除字段
>hdel key field [field ...]
e.g.
hdel car price
只获取字段名或字段值
>hkeys key>hvals key
e.g.
127.0.0.1:6379> hkeys car1) name2) price3) score4) model127.0.0.1:6379> hvals car1) bmw2) 1003) 504) 1
获取字段数量
>hlen key
e.g.
127.0.0.1:6379> hlen car(integer) 4
3. 列表类型list, 可以存储一个有序的字符串列表, 列表内元素非唯一性,可以向两端加入元素,或者获得列表的某一个片段
内部使用双向链表实现,两端添加元素复杂度o(1), 通过索引访问的速度较慢
可以用在分页, 新鲜事, 记录日志等
向列表两端增加元素(可同时增加多个)
>lpush key value [value ...]>rpush key value [value ...]
e.g.
127.0.0.1:6379> lpush num 1 2 3(integer) 3127.0.0.1:6379> rpush num 0(integer) 4# 3 2 1 0
从列表两端弹出元素先移除一个元素,然后返回之
>lpop key>rpop key
e.g.
127.0.0.1:6379> lpop num3127.0.0.1:6379> rpop num0
获取元素个数
>llen key
e.g.
127.0.0.1:6379> llen num(integer) 2
获取片段(同python切片,-1表最后一个, stop超出返回最右边元素, start大于stop返回空)
>lrange key start stop
e.g.
127.0.0.1:6379> lpush test a b c d e f g(integer) 7127.0.0.1:6379> lrange test 0 21) g2) f3) e
删除列表中指定值的元素
>lrem key count value删除列表中前count个值为value的元素,返回值为实际删除元素的个数 count = 0 所有 > 0 从左边开始删count个
e.g.
127.0.0.1:6379> lrange test 0 21) g2) f3) e127.0.0.1:6379> lrem test 0 f(integer) 1127.0.0.1:6379> lrange test 0 21) g2) e3) d
设置指定索引元素值
>lindex key index>lset key index value
e.g.
127.0.0.1:6379> lpush lt 3 2 1(integer) 3127.0.0.1:6379> lindex lt 01127.0.0.1:6379> lset lt 0 -1ok127.0.0.1:6379> lindex lt 0-1
只保留列表指定片段
删除指定索引范围之外的所有元素>ltrim key start end
e.g.
127.0.0.1:6379> lrange la 0 991) 62) 53) 44) 35) 26) 1127.0.0.1:6379> ltrim la 0 2ok127.0.0.1:6379> lrange la 0 991) 62) 53) 4
向列表中插入元素
>linsert key before|after pivot value从左到右查找值为pivot的元素,然后根据before/after决定将value插入该元素前面还是后面
e.g.
127.0.0.1:6379> lrange la 0 991) 62) 53) 4127.0.0.1:6379> linsert la after 5 3(integer) 4127.0.0.1:6379> lrange la 0 991) 62) 53) 34) 4
将元素从一个列表转到另一个列表
rpoplpush source destination#rpop,然后lpush,返回每个元素值,e.g.循环测试网址的可用性
4. 集合类型无序,无重复(唯一),可以存储最多2^32 - 1 个字符串
增加删除元素返回操作成功的个数
>sadd key member [member ...] >srem key member [member ...]
e.g.
127.0.0.1:6379> sadd letters a(integer) 1127.0.0.1:6379> sadd letters a b c(integer) 2
获得集合中的所有元素
>smembers key
e.g.
127.0.0.1:6379> smembers letters1) c2) a3) b
判断元素是否在集合中(复杂度o(1))
>sismember key member
e.g.
127.0.0.1:6379> sismember letters a(integer) 1127.0.0.1:6379> sismember letters d(integer) 0
集合间运算
# 差集>sdiff key [key ...]# 交集>sinter key [key ...]# 并集>sunion key [key ...]
进行集合运算并将结果存储
>sdiffstore destination_key key [key ...]>sinterstore destination_key key [key ...]>sunionstore destination_key key [key ...]
获得集合中元素个数
>scard key
e.g.
127.0.0.1:6379> scard letters(integer) 3
随机获取集合中元素
>srandmember key [count]count,正数,获取count个不重复的元素count, 负数,获取|count|个,可能重复
e.g.
127.0.0.1:6379> srandmember lettersb127.0.0.1:6379> srandmember letters 21) a2) c127.0.0.1:6379> srandmember letters -21) b2) b
弹出一个元素
>spop key
e.g.
127.0.0.1:6379> spop lettersc127.0.0.1:6379> scard letters(integer) 2
5. 有序集合sorted set,集合中每个元素都关联一个分数(不同元素分数可以相同),可以根据分数进行排序(最高/最低n个),进行有序相关的操作(分数可以相同)
有序集合使用散列表和跳跃表实现, 读取复杂度更低, 更耗费内存
按点击量排序,按时间排序等等,时间轴操作
增加元素
>zadd key score member [score member]
e.g.
127.0.0.1:6379> zadd scoreboard 89 tom 67 peter 100 david(integer) 3127.0.0.1:6379> zadd scoreboard 70 peter(integer) 0
获取元素分数
>zscore key member
e.g.
127.0.0.1:6379> zscore scoreboard peter70
获取排名在某个范围内的元素列表分数相同,按字典序排,中文的话,取决于编码方式
#分数从小到大排,返回索引从 start-stop之间的所有元素,包含两端元素, withscores同时获得元素分数>zrange key start stop [withscores]>zrevrange key start stop [withscores]
e.g.
127.0.0.1:6379> zrange scoreboard 0 21) peter2) tom3) david127.0.0.1:6379> zrange scoreboard 0 2 withscores1) peter2) 703) tom4) 895) david6) 100127.0.0.1:6379> zrevrange scoreboard 0 2 withscores1) david2) 1003) tom4) 895) peter6) 70
获取指定分数范围的元素
>zrangebyscore key min max [withscores] [limit offset count]
e.g.
127.0.0.1:6379> zrangebyscore scoreboard 80 100 withscores1) tom2) 893) david4) 100
希望不包含端点值
>zrangebyscore scoreboard 80 (100正负无穷大 +inf -inf
e.g.
127.0.0.1:6379> zrangebyscore scoreboard 80 (100 withscores1) tom2) 89127.0.0.1:6379> zrangebyscore scoreboard 80 +inf withscores1) tom2) 893) david4) 100127.0.0.1:6379> zrangebyscore scoreboard 80 +inf withscores limit 0 11) tom2) 89
增加某个元素分数
>zincrby key increment member
e.g.
127.0.0.1:6379> zscore scoreboard tom89127.0.0.1:6379> zincrby scoreboard 2 tom91127.0.0.1:6379> zscore scoreboard tom91
获得集合中元素数量
>zcard key
e.g.
127.0.0.1:6379> zcard scoreboard(integer) 3
获得指定分数范围内的元素个数
>zcount key min max
e.g.
127.0.0.1:6379> zcount scoreboard 80 100(integer) 2
删除一个或多个元素
>zrem key member [member ...]
按照排名范围删除元素
>zremrangebyrank key start stop
按照分数范围删除
>zremrangebyscore key min max
获得元素排名
>zrank key member #从小到大>zrevrank key member #相反
e.g.
127.0.0.1:6379> zrank scoreboard tom(integer) 1
计算有序集合的交集
>zinterstore destination numkeys key [key ...] [weights weight [weight ...]] [aggregate sum|min|max]#返回值为destination中元素个数#aggregate sum默认值,destination键中元素分数是每个参与计算的集合中该元素分数的和 min取最小值 max取最大值#weights 设置每个集合的权重,每个集合在参与计算时分数会被乘以权重
其他事务redis中事务是一组命令的集合, 一个事务中的命令要么都执行, 要么都不执行
> multi> sadd k1 v1> sadd k2 v2> exec
注意, 不支持回滚功能
sort可以对列表/集合/有序集合进行排序
最强大最复杂, 用不好可能成为性能瓶颈 o(n + mlogm) n为排序个数, m为返回个数
>sort key #从小到大>sort key desc #从大到小
sortby
127.0.0.1:6379> lpush sortbylist 2 1 3(integer) 3127.0.0.1:6379> set itemscore:1 50ok127.0.0.1:6379> set itemscore:2 100ok127.0.0.1:6379> set itemscore:3 -10ok127.0.0.1:6379> sort sortbylist by itemscore:* desc1) 22) 13) 3
sortby get
127.0.0.1:6379> sort sortbylist by itemscore:* desc get post:*->title get post:*->time
sotrby get store
127.0.0.1:6379> sort sortbylist by itemscore:* desc get post:*->title get post:*->time store new_key
生存时间ttl, time to live
时效数据,过一定时间删除这些数据
#设置>expire key seconds1表示设置成功, 0表键不存在或设置失败#查询>ttl key键不存在返回-1 or 没有设置生存时间#去除时效>persist key#set/getset为键赋值会同时清除键的生存时间
任务队列一般队列
生产者 lpush消费者 rpopbrpop 和rpop类似,但是当列表中没有元素时,brpop会一直阻塞住链接,直到有新元素加入
优先队列
blpop key [key ...] timeout,同时检测多个键,如果所有键都没有元素则阻塞,如果其中有一个键有元素,则从该键中弹出元素如果都有,则从左到右的顺序取第一个键中的一个元素blpop queue:1 queue:2 queue:3 0
发布/订阅模式进程间消息传递
订阅者:订阅者可以订阅一个或多个频道
>subscribe channel1
发布者:可以向指定的频道发送消息,所有订阅此频道的订阅者都会受到此消息
>publish channel1 helloworld
python中使用redis官方推荐redis-py
安装
sudo pip install redissudo easy_install redis
使用
redis-py提供两个类redis和strictredis用于实现redis的命令,strictredis用于实现大部分官方的命令,并使用官方的语法和命令(比如,set命令对应与strictredis.set方法)redis是strictredis的子类,用于向后兼容旧版本的redis-py>>> import redis>>> r = redis.strictredis(host='localhost', port=6379, db=0)>>> r.set('foo', 'bar')true>>> r.get('foo')'bar'
connection pool
管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数redis,这样就可以实现多个redis实例共享一个连接池。pool = redis.connectionpool(host='127.0.0.1', port=6379)r = redis.redis(connection_pool=pool)
pipeline机制
可以在一次请求中执行多个命令,这样避免了多次的往返时延当一组命令中每条命令都不依赖于之前的执行结果, 可以使用pipe = r.pipeline()pipe.set('one', 'first')pipe.set('two', 'second')pipe.execute()pipeline中的操作是原子的,要改变这种方式,可以传入transaction=falsepipe = r.pipeline(transaction=false)
实际实例什么应用,都用什么方式处理的
1.一般的缓存
用字符串类型足矣,e.g.注册时得用户名冲突,在线用户
>set key value>get
2.计数,访问量统计,自增id等
>incr key
3.存储对象实例
用散列>hset key field value>hget key field
4.存列表,队列相关
文章分类列表,评论列表等
用列表>lpush key value>rpush key value>lpop key>rpop key
5.集合相关的
标签云等
>sadd key member>srem key member
6.排序相关
访问量排序,点击量等
用有序结合>zadd key score member
7.访问频率控制
设置key的失效时间用 incr访问时检查次数, 若超过阈值, 走限制逻辑
or 记录次数, 超过阈值, 检查与最早一个相差是不是1分钟, 是, 走限制逻辑, 不是, 现有时间加入列表, 同时删除最早元素
管理重启后数据不丢失, 两种方式, 可单独使用或者结合使用
持久化:
rdb
快照,符合一定条件时,将内存中的所有数据进行快照并存储到硬盘上快照的条件可以在配置文件中配置, 两个参数: 时间和改动的键的个数redis默认采用的持久化方式过程1. redis使用fork函数复制一份当前进程(父进程)的副本(子进程) (存的是fork时刻的数据) 写时复制copy-on-write 开始时父子共享同一内存数据, 当父进程修改某片数据, 操作系统复制一份以保证子进程数据不受影响2. 父进程继续接收命令, 子进程开始将内存中数据写入硬盘中临时文件3. 写入结束后, 替换旧的rdb文件任意时刻rdb文件都是完整地, 可以用于备份可以手动发save / bgsave 让redis执行快照(前者由主进程进行快照操作,阻塞其他请求, 后者fork子进程)
aof
每次执行一条会修改redis中数据的命令,redis会将该命令写到硬盘中的aof文件开启, 设置 appendonly yes默认文件名 appendonly.aof 可以通过appendfilename设置纯文本文件, 每当达到一定条件时可以进行重写auto-aof-rewrite-percentage 100 #超过上一次百分比auto-aof-rewrite-min-size 64mb #允许重写的最小aof文件大小默认30s, 执行的命令同步到aof可以配置appendfsync everysec # 每秒一次
redis可以配置主从数据库
redis-server --port 6380 --slaveof 127.0.0.1 6379
复制原理: 从数据库启动, 向主库发sync, 主库后台开始保存快照(rdb), 并将保存期间的命令缓存起来. 快照完成后, 将快照文件和缓存的命令发送给从库,从库收到后载入快照文件并执行命令. 不支持断点续传
读写分离: 主库禁用持久化, 从库启用. 从库崩溃, 重启自动更新. 主库崩溃, 从库提升为主库再修复
常用查看命令
telnet连接
>telnet 127.0.0.1 6379
设定最大可用内存
如果服务器内存有限, 大量使用缓存且生存时间设置过长会导致redis占满内存. or 为了防止占用内存过大而将生存时间设太短导致命中率过低
可以限制redis使用的最大内存, 按照一定规则淘汰不需要的键
配置文件 maxmemory 限制最大可用内存大小(单位字节)maxmemory-policy 超过限制时的删除策略,一直删除直到小于指定内存volatile-lru 使用lru算法删除一个键,只对设置了生存时间的allkeys-lru 使用lru算法删除一个键volatile-random 随机,只对设置了生存时间的allkeys-randomvolatile-ttl 删除生存时间最近的noeviction 不删除键,返回错误
耗时命令日志
> slowlog get
其他批量删除
#删除 /test/*开始的./redis-cli -a password -n 0 keys /test/* | xargs ./redis-cli -a password -n 0 del
精简键名和键值, 最直观的减少内存占用的方式
the end! to be continue ....
原文地址:redis基础笔记, 感谢原作者分享。