背景:
在某些电商促消活动中需要搞活动,对某些页面的访问量(QPS)往往会非常高。如果直接读数据库,肯定DB会承受不住。那比较常见的方案就是让大部分相同信息的请求都尽可能压在cache上来缓解DB的压力,从而尽可能去满足高并发访问的需求
在一次具体的促销过程中,当运营同学给广大的消费者推了一条消息:10点准时抢购一批远低于市场价而且数量有限制促销商品。(比如3K块抢一台苹果手机之类的)。那用户一收到这条短信就会在10点集中进入抢购页面,结果持续几分钟内很多用户就会进入会场,发现页面异常并且服务器疯狂报警。
报警内容:cache异常。
由于cache有问题,直接走DB,结果导致DB压力难以支撑,整个业务集群处于雪崩
现在问题来了,什么我们的cache会出问题?我们应该要如何避免cache出问题呢?
来看看cache出问题的原因
原因可能有这么几个:
1、缓存服务器自身有限流保持
缓存服务器数量 * 单机能够承受的qps > 用户最大的QPS 就会触发限流保护
针对这个原因:可以做横向扩容。加机器即可
2、用户访问过来cache服务器集中打到一台上面了。大流量并没有按预期的那样分摊到不同的cache机器上
导致出现单机热点。(热点数据)
针对这个原因:只要计算cache-hash算法不出问题,那基本上可以做到缓存的随机分布均匀的
3、缓存里面的value过大,导致虽然QPS不高,但网络流量(qps * 单个value的大小)还是过大,触发了cache机器单台机器的网络流量限流;
针对这个原因:需要把大value进行精简,部分可以放在本机内存而不需要走远程获取这种方式的。
这里面有一个问题需要引点关注
1、如何避免热点数据的问题
其实我们在做分库分表设计的时候也要考虑这个问题,比如某些大的商家可能会占到80%的数据量,如果用商家ID进行分库分表,必然会出现热点数据问题。这跟上面提到的原因2其实是一样的。有些热点key都跑到一台机器上面了。所以简单的对key进行hash还不行。
我们在做设计之前,要先考虑一下
a. 是否存在热点key ?
b. 如果存在热点key ,那如何避免这些热点key落在同一机器上面
2、要考虑缓存的包大小
如果缓存的包过大,会导致堵塞网络的风险。
解决这两个问题的一个比较好的办法:
1、针对cache中元素key的访问监控。一旦发现cache有qps限流或网络大小限流时,能够通过监控看到到底是哪个key并发访问量过大导致,或者哪些key返回的value大小较大,再结合cache散列算法, 通过一定的规则动态修改key值去平摊到各个cache机器上去。