redis 实战学习笔记1
redis:数据文件存储在dump.rdb中
第一章:
1、redis的持久化:数据存放问题
(1)时间点转储:指定时间段内指定数量的写操作执行
(2)将之追加写入设置为 从不同步,每秒同步,每写入一个命令就同步一次
2、数据结构类型:
string、list、set、hash、zset
(1)string字符串:键-值
命令:get set del
set 成功 返回OK,python返回Ture
get 成功 返回 键对应的值
del 成功 返回删除值的数量,再次获取该键的值时候返回nil, python返回None
set abc 123
get abc
del abc
get abc
(2)list列表: 链表
一个列表结构可以有序的存储多个字符串,
命令:lpush左、rpush右、lpop、rpop、lindex、lrange范围所有元素
rpush list-key item
rpush list-key item2
rpush list-key item
lrange list-key 0 -1 取出该链表的所有元素 下表从0开始
lindex list-key 0
lpop list-key 弹出元素
(3)set集合:无序unordered
命令:sadd、smembers、sismember、srem、 sinter、sunion、sdiff
sadd set-key item 添加元素成功返回1,存在返回0
smembers set-key 获取集合所有元素 pyhton返回set
sismember set-key item 检查元素是否存在于集合中0|1 python返回bool
srem set-key item2 移除元素,返回移除数量
(4)hash散列hset:存储多个键值对之间的映射,值即可是字符串又可以是数字值,键无序排列
它其实是一个字典或者map,只是每一个hash都有一个名字
键不重复
命令:hset、hget、hgetall、hdel
hset hashkey subkey1 value1
hset hashkey subkey2 value2
hset hashkey subkey2 value2
hgetall hashkey python 返回字典
hdel hashkey subkey2
hget hashkey subkey
hmset( article,{
'title':title,link:link,poster:user,time:now,votes:1
}
)
hmset article title title1 link link1 poster zhengyi time now votes 1
hset:
article:110000{
title:title1
link:link1
poster:zhengyi
time:now
votes:1
}
hgetall article 返回字典
(5)zset有序集合:和散列一样,存储键值对。有序集合的键被称为 成员,值则为分值,浮点数
集合有序、键不重复
命令:zadd、zrange、zrangebyscore、zrem、
zadd zsetkey 728 member1
zadd zsetkey 982 member2
zadd zsetkey 982 member0
zrange zsetkey 0 -1 withscores 省略withscores 则返回所有的成员
zrangebyscore zsetkey 0 800 withscires 返回分值在0~800之间的成员
zrem zsetkey member1 移除元素
zrange zsetkey 0 -1 返回所有的成员 不包括分值
zcard zsetkey 返回该集合成员个数
功能函数:
expire key seconds 让某个键 多少秒后 自动删除
第二章:使用redis构建web应用
web应用就是通过http协议对网页游览器发送的请求进行响应的服务
(1)服务器对客户端发送的请求request进行解析
(2)请求被转发给一个预定义的处理器handler
(3)处理器可能会从数据库中取出数据
(4)处理器根据去除的数据对模板template进行渲染render
(5)处理器向客户端返回渲染后的内容作为对请求的响应 response
这种请求被认为是无状态的stateless
第三章:redis命令
1、字符串string
字符串可以存储三种类型的值:字节串,整数,浮点数
increment decrement
1)命令 用例描述
incr incr key-name 键存储值+1
decr decr key-name -1
incrby incrby key-name amount 键存储值+amount
decrby decrby key-name amount -amount
incrbyfloat incrbyfloat key-name amount +浮点数amount
append append key-name value 将value追加到键key-name当前存储值的末尾 返回当前值字符串的个数
getrange getrange key-name start end 获取范围内的所有字符组成的子串,包括start end在内
setrange setrange key-name offset value 从偏移量开始的子串设置给定值 setrange hello 0 H 0索引替换成H 也可以添加一个字符串
getbit getbit key-name offset 将字符串看作是二进制位串,并返回位串中偏移量offset的二进制位的值
setbit setbit key-name offset value 二进制位的值设置为value
bitcount bitcount key-name [start end] 统计二进制位串值为1的二进制位的个数,可以选定范围内的1的个数
bitop bitop operation dest-key key-name [key-name...]对一个或者多个二进制位串执行包括
and、or、xor、not 在内任意一种按位运算操作,并将计算结果保存在dest-key键里面
python:
conn.set('key',0)
conn.get('key')
conn.incr('key')
conn.decr('key')
conn.incr('key',10)
conn.decr('key',10)
2、列表list
1)命令 用途描述
rpush rpush key-name value [value...] 将一个或多个值推入列表的右端
lpush lpush key-name value [value...] 将一个或多个值推入列表的左端
rpop rpop key-name 移除并返回最右端的元素
lpop lpop key-name 移除并返回最左端的元素
lindex lindex key-name offset 返回列表中偏移量为offset 的元素
lrange lrange key-name start end 返回偏移量[start,end]之间的所有元素包括两端
lrange key-name 0 -1 返回列表所有元素
ltrim ltrim key-name start end 对列表进行修剪,只保留[start,end]之间的所有元素包括两端
ltrim listkey 2 -1 保留第3个元素到最后
组合使用ltrim 和 lrange 可以构建出一次返回并弹出多个元素的操作
2)阻塞式的列表弹出命令及在列表之间移动元素的命令
blpop blpop key-name [key-name...] timeout 从第一个非空列表中弹出位于最左端的元素,
或者在timeout秒之内阻塞并等待可弹出的元素出现
brpop brpop key-name [key-name...] timeout
rpoplpush rpoplpush source-key dest-key 从source-key 列表中弹出位于最右端的元素,
然后将这个元素推入到dest-key列表的最左端,
并返回这个元素
brpoplpush brpoplpush source-key dest-key timeout 从source-key列表中弹出位于最右端的元素,
然后将这个元素推入到dest-key列表的最左端,并返回这个元素。
如果source-key为空,那么在timeout秒之内阻塞并等待可弹出的元素出现
列表的一个主要优点在于可以包换多个字符串值,可以将数据集中在同一个地方降低内存占用
3、集合set
集合以无序的方式存储不同的元素
1)命令 用途描述
sadd sadd key-name item [item...] 将一个或多个元素添加到集合里面并返回数量
srem srem key-name item [item...] 从集合里面移除一个或多个元素,并返回被移除的数量
sismember sismember key-name item 检查元素是否存在于集合中
scard scard key-name 返回集合的元素数量
smembers smembers key-name 返回集合的所有元素
srandmember srandmember key-name [count] 从集合中随机返回一个或多个元素,count为负数可能元素会重复出现
spop spop key-name 随机移除集合中的一个元素,并返回
smove smove source-key dest-key item 如果集合source-key 包含元素item,那么从source-key 里面移除item
并将item添加到集合dest-key中,如果item被移除成功,那么返回1,否则返回0
2)多个集合的命令
sdiff sdiff key-name [key-name....] 返回存在第一个集合而不存在其他集合的元素,差集运算
sdiffstore sdiffstore dest-key key-name [key-name...] 将存在第一个集合但不存在其他集合的元素,存储到dest-key集合中
sinter sinter key-name [key-name...] 返回那么同时存在于所有集合中的元素 交集
sinterstore sinterstore dest-key key-name [key-name...] 将所有集合的交集 存储到dest-key集合中
sunion sunion key-name [key-name...] 返回至少存在于一个集合中的元素,并集
sunionstore sunionstore dest-key key-name [key-name] 并集的元素 存储到dest-key集合中
4、散列hash
散列可以让多个键值对存储到一个键里面
1)命令 用途描述
hset hset key-name key value
hget hget key-name key
hgetall hgetall key-name 返回该散列的所有键值对,python 返回字典
hmget hmget key-name key [key...] 从散列里获取一个或多个键的值
hmset hmset key-name key value [key value....] 为散列里面的一个或多个键设置值
hdel hdel key-name key [key...] 删除散列里的一个或者多个键值对,返回成功找到并删除的键值对数量
hlen hlen key-name 返回散列包含键值对的数量
hexists hexists key-name key 检查给定的键是否存在散列中
hkeys hkeys key-name 获取散列包含的所有键
hvals hvals key-name 获取散列包含的所有值
hgetall hgetall key-name 获取散列包含的所有键值对
hincrby hincrby key-name key increment 将键key的值+整数increment
hincrbyfloat hincrbyfloat key-name key increment 将键key的值+浮点数increment
5、有序集合zset
有序集合存储着成员与分值之间的映射
1)命令 用途描述
zadd zadd key-name score member [score member ...] 将带有给定分值的成员添加到有序结合里面
zrem zrem key-name member [member...] 从有序结合里面移除给定的成员,并返回移除成功的数量
zcard zcard key-name 返回有序集合包含的成员数量
zincrby zincrby key-name increment member 将member成员的分值加上increment
zcount zcount key-name min max 返回分值介于min和max之间的成员数量
zrank zrank key-name member 返回成员member在有序集合中的排名 从小到大排名0~max
zscore zscore key-name member 返回成员member的分值
zrange zrange key-name start stop [withscores] 返回有序结合中排名介于start和stop之间的成员
如果给定withscores,那么连成员分值也一并返回
按照分值从小到大排列
zrevrank zrevrange key-name member 返回有序集合成员member排名 第0~第max 成员按照分值从大到小排列
zrevrange zrevrange key-name start stop [withscores] 返回有序结合给定排名范围内的成员,成员按照分值从大到小排列
zrangebyscore zrangebyscore key min max [withscores] [limit offset count] 返回有序集合中分值介于min和max之间的所有成员 分值从小到大
zrevrangebyscore zrevrangebyscore key min max [withscores] [limit offset count] 返回有序集合中分值介于min和max之间的所有成员,并按照分值从大到小的顺序来返回他们
zremrangebyrank zremrangebyrank key-name start stop 移除有序集合中排名介于start stop之间的所有成员
zremrangebyscore zremrangebyscore key-name min max 移除有序集合中分值介于min max之间的所有成员
zinterstore zinterstore dest-key key-count key [key...] [weights weight] 有序集合执行集合的交集运算 默认聚合函数为sum,相同的成员 分值相加,min取最小的分值,max取最大的分值
zunionstore zunionstore dest-key key-count key [key...] 有序集合并集操作 可以添加aggregate = min max sum 聚合函数
zinterstore,zunionstore可用来构建不同类型的搜索系统
6、发布与订阅pub/sub
发布与订阅又称pub/sub的特点是订阅者负责订阅频道,发送者负责向频道发送二进制字符串消息
1)命令 用途描述
subscribe subscribe channel [channel...] 订阅给定的一个或者多个频道
unsubscribe unsubscribe [channel [channel...]] 退订给定的一个或多个频道,如果没给频道,则退订所有频道,取消订阅
publish publish channel message 向给定频道发送消息
psubscribe psubscribe pattern [pattern...] 订阅与给定模式相匹配的所有频道
punsubscribe punsubscribe [pattern [pattern....]] 退订给定的模式,退订所有模式
7、其他命令
7.1)排序
sort sort source-key [by pattern] [limit offset count] [get pattern [get pattern...]] [asc|desc] [alpha] [store dest-key]
根据给定的选项,对输入的列表、集合、有序集合进行排序,然后返回或者存储排序的结果
根据降序而不是默认的升序来排序元素
将元素看做是数字来进行排序,或者二进制字符串进行排序
使用被排序元素之外的其他值作为权重来进行排序,
rpush sortinput 23 15 110 7 列表
sort sortinput 默认升序 7 15 23 110
sort sortinput alpha 使用字典序 110 15 23 7
hset d-7 field 5
hset d-15 field 1
hset d-23 field 9
hset d-110 field 3
sort sortinput by 'd-*->field'
15 110 7 23
sort sortinput by 'd-*->field' get 'd-*->field'
1 3 5 9
sort命令不仅可以对列表进行排序,还可以对集合进行排序,返回一个列表形式的排序结果
7.2)redis事物
为了对相同或者不同类型的多个键执行操作,redis有5个命令可以让用户在不被打断的情况下对多个键执行操作
watch、multi、exec、unwatch、discard
事务可以让客户端在不被其他客户端打断的情况下执行多个命令
被multi和exec包围的命令会一个接一个执行
一个事务操作完毕后才会处理其他客户端命令
redis会将素有命令放入到一个队列里面 等待exec命令执行
主要作用:移除竞争条件
7.3)键的过期时间
通过使用过期操作来自动删除过期数据并降低redis内存占用
1)命令 示例描述
persist persist key-name 移除键的过期时间
ttl ttl key-name 查看给定键距离过期还有多少秒
expire expire key-name seconds 给定键在指定秒数后过期删除
expireat expireat key-name timestamp 将给定键的过期时间设置给定的unix时间戳
pttl pttl key-name 查看给定键距离过期还有多少毫秒
pexpire pexpire key-name milliseconds 给定的键多少毫毛后过期
pexpireat pexpireat key-name timestamp-milliseconds 将一个毫秒级经度的unix时间设置为过期时间
第四章:数据安全与性能保障
1、数据持久化-到硬盘里
1)快照持久化
可以通过创建快照来获得存储在内存里面的数据在某个时间点上的副本
利用快照进行创建相同的数据服务器副本
快照被写入dbfilename选项指定的文件 dump.rdb里面,并存储在dir路径上
2)创建快照的方法
[1]客户端向redis发送bgsave命令来创建快照--通过fork创建子进程负责写入硬盘
[2]发送save命令创建快照,并不响应其他命令,不常用
[3]设置save配置选项 save 60 10000 从最近一次快照之后算起 当60s内有10000次写入 这个条件满足时,自动触发bgsave命令
可以设置多个save选项
[4]redis通过shutdown命令接收关闭服务器请求时候或者受到term信号时候 会执行save命令 执行完毕后关闭服务器
[5]一个redis连接另一个redis并发送sync命令开始一次复制操作时候,主服务器会执行bgsave命令
快照只使用与即使丢失一部分数据也不会造成问题的应用程序
[3] 大数据,存储数据只有几GB的时候 使用快照存储数据是没问题的很快
对于非常大的数据50GB等,每天可以在凌晨的时候备份快照一次通过save命令
2、AOF持久化(只追加文件)
对于丢失数据不可接受,可以使用AOF持久化来存储在内存中的数据尽快的保存到硬盘里面
AOF持久化 会将被执行的写命令写到AOF文件的末尾,以此来记录数据发生的变化
因此,redis只要从头到尾重新执行一次AOF文件包含的所有写命令,就可以恢复AOF文件所记录的数据集
配置选项appendonly yes 打开
appendfsync 选项同步频率 always、everysec 、no建议everysec always会严重降低速度
最多也就丢失1s内的数据
缺陷:aof文件的体积不断增大,还原操作执行的时间就非常长(通过重新执行aof文件的所有命令还原数据)
解决AOF文件体积不断增大的问题:发送bgrewriteaof命令,移除aof文件中冗余命令来重写aof文件,使得aof文件变得小的多
尽可能多的备份快照文件和aof文件
3、复制
1)复制可以让其他服务器拥有一个不断更新的数据副本
一主多从服务器,主:写入 主更新从,从:读取请求
客户端可以向任意一个从服务器发送读请求,将负载平均分配到各个从服务器上
2)复制相关选项进行配置:
从服务器连接主服务器时,主服务器会执行bgsave操作,
主服务器需要 设置 dir 和 dbfilename
开启从服务器:slaveof <masterip> <masterport> 设置为masterip port 的从服务器
slaveof no one 命令 可以让服务器终止复制操作,不再接收主服务器的数据更新
slaveof host port命令 开始复制一个新的主服务器
3)redis 复制的启动过程
从服务器连接主服务器时的步骤
主服务器操作 从服务器操作
[1] 等待命令进入 连接主服务器,发送sync命令
[2] 执行bgsave,并使用缓冲区记录 根据配置选项来来决定使用现有的数据
bgsave之后执行的所有写命令 来处理客户端的命令请求
[3] bgsave执行完,向从服务器发送快 丢弃所有旧数据,开始载入主服务器发送的快照
照文件,并继续记录写命令
[4] 快照发送完,开始向服务器发送 完成快照文件的解释操作,接受命令请求
存储在缓冲区里面的写命令
[5] 缓冲区的写命令发送完, 执行主服务器发来的所有缓冲区的写命令,
从现在开始没执行一个写命令, 从现在开始,接收并执行主服务器传来的每个命令
就向从服务器发送相同的写命令
建议:实际中主服务器只使用50~60%的内存,留下30~45%内存用于执行bgsave命令和创建记录写命令的缓冲区
redis 不支持主主复制
4)主从链master/slave chaining
5)检测硬盘写入
检查info命令输出结果中aof_pending_bio_fsync的属性是否为0,为0表示所有数据写入到磁盘上面
info命令提供了redis服务器当前状态有关的信息
通过使用 复制和AOF持久化,用户可以增强redis 对系统崩溃的抵抗能力
4、处理系统故障
1)验证快照文件和aof文件
命令:修复快照或者aof文件 剔除出错的命令
redis-check-aof
redis-check-dump
2)更换故障主服务器
主A、从B、新C
首先:向B发送save命令,创建新的快照文件
接着:将快照文件scp给机器C,并在C上启动redis
最后:设置B为C的从服务器 slaveof c port
5、redis事务,保证数据安全、防止数据出错
多个客户端同时处理相同的数据时、会出现竞争
使用 wathc、multi、exec命令对多种数据进行操作
6、非事务型 流水线
在不是用事务的情况下 ,可通过流水线来提升redis的性能
即使用conn.pipeline(false)使用流水线,不开启事务操作
减少程序与redis之间的通信往返次数 为一次
7、性能注意
测试机器各命令性能
redis-benchmark -c 1 -q
PING_INLINE: 19193.86 requests per second
PING_BULK: 19527.44 requests per second
SET: 18460.40 requests per second
GET: 18889.31 requests per second
INCR: 18719.58 requests per second
LPUSH: 18358.73 requests per second
RPUSH: 18372.22 requests per second
LPOP: 18412.81 requests per second
RPOP: 18453.59 requests per second
SADD: 18487.71 requests per second
SPOP: 18807.60 requests per second
LPUSH (needed to benchmark LRANGE): 18399.26 requests per second
LRANGE_100 (first 100 elements): 12286.52 requests per second
LRANGE_300 (first 300 elements): 8552.86 requests per second
LRANGE_500 (first 450 elements): 6349.61 requests per second
LRANGE_600 (first 600 elements): 5094.24 requests per second
MSET (10 keys): 17099.86 requests per second
不使用流水线的python客户端的性能大概只有所示性能的50~60%
redis客户端库提供了内置连接池,python 只需穿件一个redis.Redis()对象
该对象按需穿件连接,重用已有连接并关闭超时连接,可以安全的应用于多进程多线程中