背景

​ 由于某些设计,系统不得不频繁读取整个用户表的数据做统计过滤使用,包括但不限于按部门找匹配员工、按项目找匹配员工等等等,直接查询表,sql优化的情况下查询倒是很快也不过是几百毫秒,But但是由于这些需求本身是服务于底层的比如权限功能,所以是特别高频的调用。直接读取数据库势必会造成数据库的连接暴增,很难保证DB的稳定性,说不定哪天就扛不住挂了。因此前人将他放到Redis的String结构上了,形成了一个大Value。Redis就不用多说了,单线程的,每秒读写都是上万的,但是这种大Value以及大Key都是很容易阻塞Redis的。

​ 实测过Redis读取这样一个9000条(7~8M大小)且不含大文本的表数据表时==getstring获取7~8M左右的大value耗时还可以接受==,只是set进去耗时长点2s多点

改进方案是改成hash(key -field-value,分别是表名-用户id-用户实体),但是hash结构适合查询单个用户id ,想要查询全部fields对应的value就不靠谱了, 用getvalues官方都不推荐,影响性能阻塞Redis,推荐使用HScan用游标分段遍历,我封装过也不适合没有性能,只是用HScan目的是保证Redis高可用不阻塞。适合用于批量的异步删除掉hash中的fields。

那么如何才能设计出一个适合以上场景的高可用方案呢?引出下文,哈哈~

==如果有幸正在阅读的你有过这个思考,并且有更好的方案,欢迎指教~==

目的

解决负载均衡中的服务器内存缓存同步更新问题,保存各服务器内存始终最新且一致

思想:

​ 数据每发生改变时,就通过reids设置版本号(incrby),
​ 每个服务器尝试写入ip到这个版本号的set集合中,
​ 写入成功表示没有被同步过,执行同步动作更新本地的内存缓存。
​ 否则跳过直接取内存缓存用

小缺点

但是可以改进

变化频率高的时候, redis存的数量也多,不过可以优化,版本号自增后就删掉旧版本的缓存

封装了一个内存全局协助同步辅助类

==三部曲==

  1. 通过这个GlobleAssistMemoryHelper.SetVersion来设置每次改动后的自增型版本
  2. 再配合GlobleAssistMemoryHelper.SetLocalReceivedTag来写入这次新改动的版本号改动所在的服务器的ip到Set集合中
  3. 获取内存缓存时调用GlobleAssistMemoryHelper.SetLocalReceivedTag写入当前服务器ip,如果写入失败说明已同步过最新的,直接读内存缓存,否则刷新最新数据到内存缓存

以上三步,如此便保证了每个服务器获取内存时始终是最新的那份!

食用方法:

// 设置缓存,只需要10毫秒
<List<RedisUser>> DistributeAssistMemoryCacheHelper.SetCache(key, usrslist, 24 * 60 * 60 - 500, isfromChange); 
// 读取缓存,几乎不耗时
result = ()DistributeAssistMemoryCacheHelper.GetCache(key);
// 删除缓存
DistributeAssistMemoryCacheHelper.DelCache(key);

附上源码