【第六讲,Redis的高并发实战:抢购系统】
讲师:浅奕,阿里云NoSQL内核工程师。
课程内容:IO模型和问题;资源竞争,与分布式锁;如何利用Redis的高并发原理做抢购系统。
答疑汇总:特感谢班委@张鹏 同学
1. zset 和 hash 的配合使用
zset 存储主键 key 和分数,然后 key 用 hash, 这样容量和缓存占比应该是最小的。但是问题是批量查询,zset 是有一个还是很多个,如果是一个,要小心成为热点 key 。hash 有一个 mget ,可以拿一个hash 的多个字段,但是多个 hash 是没有相关API 一次性拿的,原因是多个 hash 的 key 可能存在集群的多个分片上。
2. 用 stream 实现一个消息队列?
使用方法类似于 kafka , 需要有producer, consumer group, topic 等。
3. 缓存怎么和数据库保持强一致?
首先是很难保证的,应该尽量避免数据不一致。如果出现不一致,要以最可靠的数据库做一个兜底。要避免这个问题,主要是解决缓存在更新的时候。一种方式是只有一个线程写,定时从数据库更新数据到缓存,可以监听数据库 binlog 的修改,更新缓存。另一种方式是业务线程来更新,先持久化再删除缓存,然后读逻辑来更新缓存。缓存一般是要设置过期时间的。
4. Set 和Sorted Set对性能是否有影响?
Redis 的数据结构为了省内存,编码是有两种或两种以上的,在配置里边会有一个默认值,比如可以设置 set 它在成员小于多少的时候是一个列表,大于的时候是一个哈希结构。hash 结构的查询效率是O(1), 排序集合使用跳表,成员小于一定数量是使用压缩表。一般情况不要调大这个参数值,可以改小这个参数值,尽量用稀疏的数据结构,用 hash和跳表,不要使用压缩结构,压缩结构查询和插入效率一般都是O(n) 的。
5. 秒杀场景节点多少个比较好?
看业务需求了,单分片单key 的能力是QPS 10万左右,然后对业务的预估确定分片数,理想情况,查询比较散的情况下,根据总的QPS 计算,预留 30% 的水位就可以了。
分片太多也不好,正常的访问是没问题的,只是发生变化的时候,客户端会有比较多的错误。如果是开源版,节点比较多集群Gossip 协议广播会比较厉害。
6. Lua 的问题是不是可以使用单独集群处理?
Lua 需要慎用,但不是不用。我们要清楚正常的一个读写能达到 QPS 10万,如果在lua 里面可能就只有8万了。对性能有一定影响。不要在 lua 里写比较复杂的循环。对性能的影响就是lua 本身需要编译执行。如果 lua 都非常小,不需要单独集群处理。主要是控制好lua 执行的时间就好了。
7. 对于大 key 有什么好的方案?
大 key 一般都是指 list、hash、set 这类数据结构,list 没有什么好的解法,可以将list 拆分成多个list ,但是对于业务来说是比较难处理的,建议尽量避免大 key。
8. Redis 的key 或value 用string 或byte数组有什么区别吗?
对于服务端来说没有什么区别,主要看客户端是怎么实现的,比如看最终key 或 value 是怎么序列化的,最终发的时候肯定是一个序列化对象,发到服务端存储的时候就是一个字节数组。只是比如在执行incr 的时候,会对value 做一个数字解析。
9. Memcached 和Redis 怎么选?
Memcached 只有 k-v 操作和原子计数操作,Memcached 是多线程方式,单分片性能可能优于Redis,但是数据结构支持较少。业务比较简单只用key-value结构和incr 操作的话,可以选择Memcached。memcached 数据导入导出比较困难,如果需要,建议选择Redis,而且 Redis 社区比较活跃一点。
10. Mysql 和 Redis 的同步?
一般的方案是监听 mysql 的 binlog 的变动,然后解析出原始数据操作,去 Redis更新数据。