整个三级缓存的架构已经走通了nginx
咱们还遇到一个问题,就是说,若是缓存服务在本地的ehcache中都读取不到数据,那就恩坑爹了redis
这个时候就意味着,须要从新到源头的服务中去拉去数据,拉取到数据以后,赶忙先给nginx的请求返回,同时将数据写入ehcache和redis中算法
分布式重建缓存的并发冲突问题api
重建缓存:好比咱们这里,数据在全部的缓存中都不存在了(LRU算法弄掉了),就须要从新查询数据写入缓存,重建缓存缓存
分布式的重建缓存,在不一样的机器上,不一样的服务实例中,去作上面的事情,就会出现多个机器分布式重建去读取相同的数据,而后写入缓存中架构
分布式重建缓存的并发冲突问题。。。。。。并发
一、流量均匀分布到全部缓存服务实例上分布式
应用层nginx,是将请求流量均匀地打到各个缓存服务实例中的,可能我们的eshop-cache那个服务,可能会部署多实例在不一样的机器上高并发
二、应用层nginx的hash,固定商品id,走固定的缓存服务实例oop
分发层的nginx的lua脚本,是怎么写的,怎么玩儿的,搞一堆应用层nginx的地址列表,对每一个商品id作一个hash,而后对应用nginx数量取模
将每一个商品的请求固定分发到同一个应用层nginx上面去
在应用层nginx里,发现本身本地lua shared dict缓存中没有数据的时候,就采起同样的方式,对product id取模,而后将请求固定分发到同一个缓存服务实例中去
这样的话,就不会出现说多个缓存服务实例分布式的去更新那个缓存了
留个做业,你们去作吧,这个东西,以前已经讲解果了,lua脚本几乎都是如出一辙的,咱们就不去作了,节省点时间
三、源信息服务发送的变动消息,须要按照商品id去分区,固定的商品变动走固定的kafka分区,也就是固定的一个缓存服务实例获取到
缓存服务,是监听kafka topic的,一个缓存服务实例,做为一个kafka consumer,就消费topic中的一个partition
因此你有多个缓存服务实例的话,每一个缓存服务实例就消费一个kafka partition
因此这里,通常来讲,你的源头信息服务,在发送消息到kafka topic的时候,都须要按照product id去分区
也就时说,同一个product id变动的消息必定是到同一个kafka partition中去的,也就是说同一个product id的变动消息,必定是同一个缓存服务实例消费到的
咱们也不去作了,其实很简单,kafka producer api,里面send message的时候,多加一个参数就能够了,product id传递进去,就能够了
四、问题是,本身写的简易的hash分发,与kafka的分区,可能并不一致!!!
咱们本身写的简易的hash分发策略,是按照crc32去取hash值,而后再取模的
关键你又不知道你的kafka producer的hash策略是什么,极可能说跟咱们的策略是不同的
拿就可能致使说,数据变动的消息所到的缓存服务实例,跟咱们的应用层nginx分发到的那个缓存服务实例也许就不在一台机器上了
这样的话,在高并发,极端的状况下,可能就会出现冲突
五、分布式的缓存重建并发冲突问题发生了。。。
六、基于zookeeper分布式锁的解决方案
分布式锁,若是你有多个机器在访问同一个共享资源,那么这个时候,若是你须要加个锁,让多个分布式的机器在访问共享资源的时候串行起来
那么这个时候,那个锁,多个不一样机器上的服务共享的锁,就是分布式锁
分布式锁固然有不少种不一样的实现方案,redis分布式锁,zookeeper分布式锁
zk,作分布式协调这一块,仍是很流行的,大数据应用里面,hadoop,storm,都是基于zk去作分布式协调
zk分布式锁的解决并发冲突的方案
(1)变动缓存重建以及空缓存请求重建,更新redis以前,都须要先获取对应商品id的分布式锁(2)拿到分布式锁以后,须要根据时间版本去比较一下,若是本身的版本新于redis中的版本,那么就更新,不然就不更新(3)若是拿不到分布式锁,那么就等待,不断轮询等待,直到本身获取到分布式的锁