举出一个使用Memcache比Redis更优的使用场景
- 适合大量get,而且只用简单KV的场景。
- 一个典型的场景,Memcache可以作为集中Session存储,比Redis更优秀。
- Memcached是多线程,非阻塞IO复用的网络模型,分为监听主线程和worker子线程,监听线程监听网络连接, 接受请求后,将连接描述字pipe 传递给worker线程,进行读写IO, 网络层使用libevent封装的事件库,多线程模型可以发挥多核作用。
什么是分布式锁
- 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
- 在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,这个时候,便需要使用到分布式锁。
memcache分布式锁
- [场景]
- Mutex主要用于有大量并发访问并存在cache过期的场合
- 首页top 10, 由数据库加载到memcache缓存n分钟
- 微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
- 需要执行多个IO操作生成的数据存在cache中, 比如查询db多次
- Mutex主要用于有大量并发访问并存在cache过期的场合
- [问题]
- 在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障。
- [解决方法]
- 在load db之前先add一个mutex key, mutex key add成功之后再去做加载db, 如果add失败则sleep之后重试读取原cache数据。为了防止死锁,mutex key也需要设置过期时间。伪代码如下
//缓存key失效后,假设当前是高并发的时候
if (memcache.get(key) == null) {
//3分钟超时互斥锁持有者,以免撞车
if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
value = db.get(key);
memcache.set(key, value);
memcache.delete(key_mutex); //使用完锁后释放
} else {
sleep(50); //加锁失败后,休眠下重试
retry();
}
}
- [实现原理]
- memcached带有add函数,利用add函数的特性即可实现分布式锁。add和set的区别在于:如果多线程并发set,则每个set都会成功,但最后存储的值以最后的set的线程为准。而add的话则相反,add会添加第一个到达的值,并返回true,后续的添加则都会返回false。利用该点即可很轻松地实现分布式锁。
- [缺点]
- memcached采用列入LRU置换策略,所以如果内存不够,可能导致缓存中的锁信息丢失,提供足够支撑锁服务的内存空间。
- memcached无法持久化,一旦重启,将导致信息丢失,使用稳定的集群化管理。
redis分布式锁
Redis 里,所谓 SETNX,是「SET if Not eXists」的缩写,也就是只有不存在的时候才设置,可以利用它来实现锁的效果。