继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

NoSQL之缓存数据库redis

_潇潇暮雨
关注TA
已关注
手记 17
粉丝 119
获赞 1654

MYSQL QPS:8000读,4000写,redis 10W读写。memcached的瓶颈在于libevent,而redis用了epoll。

使用场景
  1. 最新N个数据的操作。例如取网站的最新文章,我们可以将最新的5000条评论的id放入到redis的list集合中,并将超出集合的部分从DB获取。
  2. 取TOP N的操作。排行榜应用。这个需求与上面的需求不同之处在于,前面的操作以时间为权重,这个是以某个条件为权重,例如按顶的次数进行排序,使用sorted set,将需要排序的字段设置为sorted setscore,将具体的值设置成相应的value,每次只执行一次ZADD命令即可。
  3. 需要精确设置过期时间的应用。例如可以将上面的sorted scorescore值设置成过期时间的时间戳,那么就可以简单通过过期时间进行排序,定时清除过期数据了,不仅是清除redis中的过期数据,完全可以将redis中的过期时间当成是对数据库中数据的索引,用redis找出哪些数据需要过期删除,然后从DB中精确删除相关记录。
  4. 计数器应用。命令都是原子性的,可方便使用INCR,DECR
  5. uniq,获取某段时间所有数据重排值。使用set结构,不断将数据向set中扔,会自动去重。
  6. pub/sub构建实时消息系统。
  7. 构建队列系统。使用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. 批量处理。将一次处理一条数据改善为1次处理多条数据性能可成倍提高。网络IO。
  2. 最好在本机部署,性能提高10~20倍。
  3. 少用get/set,多用hset。主要是为了内存考虑。假设一个k-v单元最少占用512bytes,即使只存储了一个字节也占用了512bytes。这时候有一个设计模式,可以将key复用,几个k-v对放在一个key中,将value作为一个set存入,同样512bytes可存储10~100倍的容量。

命令参考

打开App,阅读手记
3人推荐
发表评论
随时随地看视频慕课网APP