MYSQL QPS:8000读,4000写,redis 10W读写。memcached的瓶颈在于libevent,而redis用了epoll。
使用场景- 最新N个数据的操作。例如取网站的最新文章,我们可以将最新的5000条评论的id放入到redis的
list
集合中,并将超出集合的部分从DB获取。 - 取TOP N的操作。排行榜应用。这个需求与上面的需求不同之处在于,前面的操作以时间为权重,这个是以某个条件为权重,例如按顶的次数进行排序,使用
sorted set
,将需要排序的字段设置为sorted set
的score
,将具体的值设置成相应的value
,每次只执行一次ZADD
命令即可。 - 需要精确设置过期时间的应用。例如可以将上面的
sorted score
的score
值设置成过期时间的时间戳,那么就可以简单通过过期时间进行排序,定时清除过期数据了,不仅是清除redis中的过期数据,完全可以将redis中的过期时间当成是对数据库中数据的索引,用redis找出哪些数据需要过期删除,然后从DB中精确删除相关记录。 - 计数器应用。命令都是原子性的,可方便使用
INCR
,DECR
- uniq,获取某段时间所有数据重排值。使用
set
结构,不断将数据向set中扔,会自动去重。 - pub/sub构建实时消息系统。
- 构建队列系统。使用
list
可构建队列,使用sorted set
可以构建优先级队列。
String
k-v类型,其中value不仅可以是字符串,也可以是数字。可以享受定时持久化(RDB模式和AOF模式)。是二进制安全的,也就是说redis的string可以包含任何数据,例如jpg图片或者序列化的对象,内部实现可以看做byte数组,上限为1GB,定义如下:
struct{
long len;
long free;
char buf[];
}
部分命令可以按照int处理,例如INCR
,如果只使用该种类型,相当于带有持久化功能的memcached。
Hash(字典)
在memcached中,我们经常将一些结构化的信息打包成hashmap,在客户端序列化后存储为一个字符串的值(一般是JSON),例如用户的昵称、年龄、性别、积分等。这时候需要修改其中的某一项时需要将字符串(JSON)取出来,然后进行反序列化,修改某一项的值,再序列化成JSON存储回去,消耗太大,不适合用于一些可能并发操作的场合(例如2个并发操作都需要修改积分),而redis的hash可以像在DB中UPDATE一个属性一样只修改某个属性的值。
List(列表)
说白了就是链表(redis使用双向链表实现的List)。使用该结构可以轻松实现最新消息排行榜等功能(sina微博的timeline)。另外一个作用就是消息队列,利用PUSH
操作将任务存在List中,然后工作线程用POP
操作将任务取出并执行。提供了操作List某一段元素的API,可直接查询、删除List中某一段元素。
Set(集合)
例如在weibo应用中,将一个用户所有关注的人存储在一个集合中,将其粉丝存在一个集合中。redis针对集合提供了方便的求交集、并集、补集等操作,可以非常方便实现共同关注、共同喜好、二度好友等功能,集合也可以存储在一个新的集合中。
Sorted Set(有序集)
有序集将Set中的元素增加了一个权重参数score,使得集合中的元素能够按照score进行升序排列,例如一个存储全班成绩的Sorted Set,其集合value可以是同学的学号,而score就可以是其考试得分,这样在数据插入集合的时候就已经进行了天然的排序(游戏用户得分排行榜)。另外还可以使用有序集来做带权重的队列,例如普通消息的score为1,重要消息的score为2,然后工作线程可以按照score的逆序来获取工作任务。让重要的任务先执行。
Pub-Sub
微信群,拉到一个群相当于每个人订阅了这个信道,当有一个人向群里发消息的时候相当于在这个频道发布消息,所有订阅该信道的用户都将收到消息。
Transaction
提供了Watch功能,对key进行watch,然后再执行transaction,在这个过程中,如果这个watched的值进行了修改,那么这个transaction会发现并拒绝执行。例如:以下的命令在多客户端连接的时候可能出现数据一致性问题:
set age 10
incr age
incr age # 此时有一个客户端进行get age,将得到11
get age
以上的命令打包成一个原子操作即可解决。
配置文件配置文件中有一项databases 16
,redis默认有16个DB,默认使用的是0号DB。我们可以使用SELECT 0-15
的方式切换DB,各个DB是相互隔离的。多个应用可以共用一个物理redis server。
rename-command CONFIG ""
,命令重命名,在共享环境下可以重命名相对危险的命令,例如把CONFIG
重命名为一个不容易猜测的字符。rename-command CONFIG dsfd8324kndskdksfjdfdsjnfdsdfjsl
,如果想要删除这个别名直接重命名为空字符串即可。
- RDB,默认为dump.rdb,内存快照。
- AOF,记录每一次写操作,生成历史记录文件,可压缩
以上2种方式可同时配置。
最佳实践- 批量处理。将一次处理一条数据改善为1次处理多条数据性能可成倍提高。网络IO。
- 最好在本机部署,性能提高10~20倍。
- 少用get/set,多用hset。主要是为了内存考虑。假设一个k-v单元最少占用512bytes,即使只存储了一个字节也占用了512bytes。这时候有一个设计模式,可以将key复用,几个k-v对放在一个key中,将value作为一个set存入,同样512bytes可存储10~100倍的容量。