EdsCache通用缓存框架——(2.6) 负载均衡

达芬奇密码2018-06-22 16:34
问题描述
当出现热点数据,如几万人参加一场考试。
即使是分布式缓存,一个key对应的数据,也只会存在某一个节点上,并发很高时,缓存单点的性能无法扩展,变成了性能的瓶颈。

解决思路
可以将缓存数据拷贝N份,分布到缓存各个节点中,达到负载均衡的目的。
如,配置负载均衡count为N,需要写缓存时,将原始key添加0~N的结尾,再分别将数据写到缓存中;
需要查询时,从0到N之间随机选择一个值,添加到原始key的结尾,进行缓存查询,来达到利用负载均衡的目的,如下图:


优点:
能解决缓存的单点瓶颈问题。
缺点:
一定程度的浪费缓存空间;
N份数据在分布式缓存中分布不一定很均匀,跟分布式缓存的算法相关,如hash一致性算法;
开启负载均衡功能的接口,非热点数据目前也会无差别的缓存N份,造成浪费。(目前有优化方案,待实现)

EdsCache使用样例
通过添加@EdsCacheLoadBalance注解,并执行冗余的份数,开启负载均衡功能,如:
查询流程
@EdsCache(key = “paper", expire = 60*60)
@EdsCacheLoadBalance(constants.BALANCE_COUNT)
public PaperDTO getPaper(@EdsCacheKey Long id){
    return paperDao.getPaper(id);
}
更新流程
@EdsCache(key = “paper", expire =  60*60, opType = CacheOpEnum.WRITE)
@EdsCacheLoadBalance(constants.BALANCE_COUNT)
public PaperDTO savePaper(@EdsCacheKey Long id, PaperDTO update){
    PaperDTO ret = paperDao.savePaper(id, update);
    return ret;
}
删除流程
@EdsCacheDelete(key = “paper")
@EdsCacheLoadBalance(constants.BALANCE_COUNT)
public void delPaper(@EdsCacheKey Long id){
    paperDao.removePaper(id);
}
注意事项:
负载均衡需要在查询、更新(如果需要更新缓存的话)、删除(如果需要删除缓存的话),必须配置保持一致,均同时启用@EdsCacheLoadBalance,且份数相同(定义统一的常量等)。
否则功能不正常,比如,写缓存时,配置了负载均衡,实际key是带编号结尾的;但查询接口没有配置负载均衡,以没有编号结尾的key去查,是查不到数据的。

优化方案
目前负载均衡功能存在优化的空间,对于同一个接口,非热点数据目前也会无差别的缓存N份,如果缓存时间较长,造成较大的空间浪费。
可以借鉴多级缓存的思路,查询流程如:
先查带随机结尾的key,如paper_1001_8,如果命中缓存直接返回;
如果带随机结尾的key没有命中,再查没有结尾的key,如paper_1001,如果命中,扩展到N份写缓存,且超时时间为一个较短的时间。

通过该方案减少冷门数据长时间占N份空间的机会。

本文来自网易实践者社区,经作者陈婷授权发布。  

相关阅读:EdsCache通用缓存框架——(1)总览导航