一. 概述
-
Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。
-
Redis 与其他 key - value 缓存产品有以下三个特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
Redis 优势
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 丰富的数据类型 – Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
- 原子 – Redis的所有操作都是原子性的,意思就是要么成功执行要么失败完全不执行。单个操作是原子性的。多个操作也支持事务,即原子性,通过MULTI和EXEC指令包起来。
- 丰富的特性 – Redis还支持 publish/subscribe, 通知, key 过期等等特性。
Redis 支持哪些数据结构
STRING:字符串、整数或浮点数
LIST:列表,可存储多个相同的字符串
SET:集合,存储不同元素,无序排列
HASH:散列表,存储键值对之间的映射,无序排列
ZSET:有序集合,存储键值对,有序排列
redis 最适合的场景
Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的差别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用Redis呢?
- 如果简单地比较Redis与Memcached的区别,大多数都会得到以下观点:
- Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
- Redis支持数据的备份,即master-slave模式的数据备份。
- Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
1. 会话缓存(Session Cache)
最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?
幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。
2. 全页缓存(FPC)
除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。
再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。
此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。
3. 队列
Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。
4. 排行榜/计数器
Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:
当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:
ZRANGE user_scores 0 10 WITHSCORES
Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的。
验证码
防止流量攻击
二、 Redis命令
Redis命令用于在redis服务上执行操作。要在redis服务上执行命令需要一个redis客户Redis客户端
常用命令
keys:返回满足的所有键,可以模糊匹配比如 keys abc* 代表abc开头的key
exists key:是否存在指定的key,存在返回1,不存在返回0
expire key second:设置某个key的过期时间时间为秒
del key:删除某个key
ttl key:查看剩余时间,当key不存在时,返回-2;存在但没有设置剩余生存时间时,返回-1,否则,以秒为单位,返回key的剩余生存时间。
pttl key:以毫秒为单位查看剩余时间
persist key:取消过去时间
PEXPIRE key milliseconds修改key的过期时间为毫秒
select: 选择数据库数据库为0-15 默认一共16个数据库,设计成多个数据库实际上是为了数据库安全和备份
move key dbindex:将当前数据中的key转移到其他数据库
randomkey:随机返回一个key
rename key key2:重命名key
echo: 打印命令
dbsize:查看数据库的key数量
info:查看数据库信息
config get:实时传储收到的请求,返回相关的配置
flushdb:清空当前数据库
flushall:清空所有数据库
三、 5中基本数据类型
1. string命令
127.0.0.1:6379[1]> set name sky # 设置
OK
127.0.0.1:6379[1]> APPEND name hello # 在尾部添加
(integer) 8
127.0.0.1:6379[1]> get name # 获取
"skyhello"
127.0.0.1:6379[1]> STRLEN name # 获取字符串长度
(integer) 8
127.0.0.1:6379> set view 0 # 设置访问量
OK
127.0.0.1:6379> incr view # 增加 view++
(integer) 1
127.0.0.1:6379> decr view # 减少 view--
(integer) 0
127.0.0.1:6379> incrby view 10 # 按步长增加 view=view+10
(integer) 10
127.0.0.1:6379> decrby view 10 # 按步长减少 view=view-10
(integer) 0
127.0.0.1:6379> set name sky,hilohijsk. # 设置name的值
OK
127.0.0.1:6379> getrange name 0 4 # 截取字符串[0,4]
"sky,h"
127.0.0.1:6379> getrange name 0 -1 # 获取全部的字符串 和 get key是一样的
"sky,hilohijsk."
127.0.0.1:6379> setrange name 2 empe # 替换指定位置开始的字符串
(integer) 14
127.0.0.1:6379> get name
"skempelohijsk."
# setex (set with expire) # 设置过期时间
# setnx (set if not exist) # 不存在在设置 (在分布式锁中会常常使用!) setex key3 30 hello # 设置key3 的值为 hello,30秒后过期
setnx mykey redis # 如果mykey不存在,创建mykey
(integer) 1
mset mget
# 同时设置和获取多个值
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 a1 k4 v4 # msetnx是一个原子性的操作,要么一起功,要么一起失败!
(integer) 0
127.0.0.1:6379> get k4
(nil)
# 设置对象
127.0.0.1:6379> set user:1 {name:sky,age:14} # 设置一个user:1 对象,值为json字符来保存一个对象!
# 这里的key是一个巧妙的设计: user:{id}:{filed}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
# 先get然后再set
127.0.0.1:6379> getset name sky # 若不存在该值,则返回nil
(nil)
127.0.0.1:6379> getset name aa # 如果存在值,获取原来的值,并设置新的值
"sky"
127.0.0.1:6379> get name
"aa"
2. List命令
在redis里面,我们可以把list玩成 ,栈、队列、阻塞队列!所有的list命令都是用l开头的
lpush list first # 将一个值或者多个值,插入到列表头部 (左)
rpush list second # 将一个值或者多个值,插入到列表尾部 (右)
lrange list 0 -1 # 获取list中值
lrange list 0 1 # 通过区间获取具体的值
lpop list # 移除list的第一个元素
rpop list # 移除list的最后一个元素
lindex list 1 # 通过下标获得 list 中的某一个值
Llen list # 返回列表的长度
lrem list 2 one # 移除list集合中指定个数(2个)的value,精确匹配
ltrim mylist 1 2 # 通过下标截取指定的长度,这个list已经被改变了,只剩下截取的元素!
rpoplpush list otherlist # 移除列表的后一个元素,将他移动到新的列表中!
exists list # 判断这个列表是否存在
lset list 0 item # 如果不存在列表,更新会报错
lset list 6 other # 如果不存在当前下标(6),则会报错!
LINSERT list before "world" "other" # 将某个具体的value插入到列把你中某个元素的前面或者后面
LINSERT mylist after "world" "other"
3. Set命令
sadd myset "hello" # set集合中添加元素
smembers myset # 查看指定set的所有值
sismember myset hello # 判断某一个值是不是在set集合中!
scard myset # 获取set集合中的内容元素个数
srem myset hello # 移除set集合中的指定元素
spop myset # 随机删除一些set集合中的元素!
smove myset set2 "hi" # 将一个指定的值,移动到另外一个set集合!
sinter set1 set2 # 交集
sunion set1 set2 # 并集
adiff set1 set2 # 差集
4. Hash命令
hash变更的数据 user name age,尤其是是用户信息之类的,经常变动的信息! hash 更适合于对象的 存储,String更加适合字符串存储!
hset myhash field1 hello # set一个具体key-vlaue
hmset myhash field1 hello field2 world # set多个 key-vlaue
hget myhash field1 # 获取一个字段值
hgetall myhash # 获取全部的数据
hdel myhash field1 # 删除hash指定key字段,对应的value值也就消失了
hlen myhash # 获取hash表的字段数量
hexists myhash field1 # 判断hash中指定字段是否存在!
hkeys myhash # 获得所有field
hvals myhash # 只获得所有value
hincrby myhash field3 3 # 指定增量3
hsetnx myhash field4 hello # 如果不存在则可以设置,存在则不能
5. Zset(有序集合)
在set的基础上,增加了一个值,set k1 v1 ---> zset k1 score1 v1
zadd myset 1 one # 添加一个元素,1是score
zadd myset 2 two 3 three # 添加多个值
zrange myset 0 -1 # 查看所有元素(从小到大排序)
zrevrange myset 0 -1 # 查看所有元素(从大到小排序)
ZRANGEBYSCORE salary -inf +inf withscores # 显示全部的用户并且附带成绩
zrem salary hello # 移除有序集合中的指定元素
zcard salary # 获取有序集合中的个数
zcount myset 1 3 # 获取指定区间的成员数量
四、 三种特殊数据类型
Geospatial 地理位置
略
Hyperloglog
优点:占用的内存是固定,2^64 不同的元素的技术,只需要废 12KB内存!如果要从内存角度来比较的话Hyperloglog 首选!
网页的 UV (一个人访问一个网站多次,但是还是算作一个人!)
传统的方式, set 保存用户的id,然后就可以统计 set 中的元素数量作为标准判断 ! 这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;
0.81% 错误率! 统计UV任务,可以忽略不计的!
pfadd mykey a b c d e f g h i j # 创建第一组元素 mykey
pfcount mykey # 统计mykey元素的基数数量
pfadd mykey2 i j z x c v b n m # 创建第二组元素 mykey2
pfmerge mykey3 mykey mykey2 # 合并两组 mykey mykey2 => mykey3 并集
Bitmap
位存储
统计用户信息,活跃,不活跃! 登录 、 未登录! 打卡,365打卡! 两个状态的,都可以使用 Bitmaps
Bitmap 位图,数据结构! 都是操作二进制位来进行记录,就只有0 和 1 两个状态!
365 天 = 365 bit 1字节 = 8bit 46 个字节左右!
# 使用bitmap来记录周一到周日的打卡!
setbit sign 0 1
setbit sign 1 0
setbit sign 2 0
setbit sign 3 1
setbit sign 4 1
setbit sign 5 0
setbit sign 6 0
getbit sign 3 # 查看第4天是否打卡
bitcount sign # 统计这周的打卡记录
五、 Redis发布订阅
当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端
命令
测试
- 发布者
127.0.0.1:6379> publish sky hello
(integer) 1
- 接收者
127.0.0.1:6379> subscribe sky
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "sky"
3) (integer) 1
1) "message"
2) "sky"
3) "hello"
Comments | 0 条评论