本文共 1860 字,大约阅读时间需要 6 分钟。
对于一个大型的数据缓存系统,会部署多层缓存服务来达到高并发、高可用的系统需求
nginx层
对于传统的缓存系统,请求到达nginx,然后分发到对应的服务系统,然后查询redis中是否有数据,然后将结果返回,这里会花费很大的网络开销。nginx可以支持热数据的缓存,对这些数据直接缓存在nginx内存中,请求到来直接返回,不需要去发送网络请求。但是nginx内存的大小一般会很小,所以适合缓存热数据redis cluster层
这一层的数据是最完整的,大部分的离散请求都会访问到这一层。因此一定要做到高可用,可水平伸缩的模式tomcat层
tomcat中的堆也可以缓存一定的数据,但是容量也不会太大。主要是用来防止redis层大面积崩溃之后,大量数据请求直接到DB层对于数据不同的实时性要求,我们可以采取不同的方式来修改缓存
对于这种实时性很高的数据,当有修改的时候,一般是修改DB然后同时去修改redis缓存的双写模式。但是这里会设计到数据不一致的问题。
数据库、缓存更新与读取操作进行异步串行化
将需要更新的数据,发送到jvm内部的队列中,一般会维护多个内存队列,对数据的唯一标识hash然后对内存队列数量取模,就可以保证同样的数据操作一定会在同一个队列中去。
每个队列有一个工作线程,每个工作线程串行拿到对应的操作,然后逐条执行。因此一个数据的变更,会先删除缓存,然后再去更新数据库,当还没有更新完成的时候,另一个读请求过来来,读到空的缓存,那么可以将这个缓存更新的请求发送到队列中,从而会同步等待缓存更新完成。需要注意的一点,对于缓存为空,多个读请求过来,将多个更新缓存的请求发送到队列是没有必要的,因此需要做过滤,然后可以将这些读请求hang住一个时间段,轮询去查询缓存,当前面队列中的更新缓存请求执行完成后,就可以拿到缓存数据直接返回,否则,可以让服务直接取查询DB来拿数据。在高并发下,需要注意:
基于zookeeper分布式锁解决多服务缓存重建并发冲突:
对于多个缓存服务,可能存在这种情况,nginx请求到达发现都没有相应缓存数据,会发送请求给缓存服务到数据源拉取数据并写入相应tomcat/redis,同时kafka生产了消息的变更记录也需要去拉取数据并存入tomcat/redis。两者拉取数据源与缓存重建可能会出现并发冲突导致tomcat/redis中的最终数据并不是最新。
对于实时性不高的数据,如果发生了变更,几分钟之后才更新到页面上,我们采取异步更新缓存的策略。缓存数据生产服务,监听一个消息队列,然后数据源服务(商品信息管理服务)发生来变更之后,就将数据变更的消息推送到消息队列(topic),缓存数据生产服务可以去消费这些变更的信息,然后根据消息的提示提取一些参数,然后调用对应的数据源服务接口拉取数据,一般是从mysql拉取,然后将数据存放到本地堆缓存和redis缓存
一般来说,默认会部署多个nginx,在里面都会放一些缓存,此时缓存的命中率会非常底,因为对同样数据的请求可能被路由到多个nginx从而未能找到相应缓存而多次对redis发起请求。因此,可以采用分发层+应用层双层ngin来提升缓存命中率。
转载地址:http://rqrgi.baihongyu.com/