memcached: c实现的服务端,java实现的客户端有很多spymemcached据说代码写的不咋的
我们现在用的xmemached;国产的也是基于nio实现
1:memcached特点
2: 协议
3: 原理简介
memcached: 内存keyvalue结构,很好的水平扩展,容易集群;不支持持久化
memcached在数据删除方面有效利用资源
数据不会真正从memcached中消失
memcached不会释放已分配的内存。记录超时后,客户端就无法再看见该记录(invisible,透明), 其存储空间即可重复使用。
Lazy Expiration
memcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。 这种技术被称为lazy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU时间。(和redis超时机制差不多)
LRU:从缓存中有效删除数据的原理
memcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况, 此时就要使用名为 Least Recently Used(LRU)机制来分配空间。 顾名思义,这是删除“最近最少使用”的记录的机制。 因此,当memcached的内存空间不足时(无法从slab class 获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。 从缓存的实用角度来看,该模型十分理想。
不过,有些情况下LRU机制反倒会造成麻烦。memcached启动时通过“-M”参数可以禁止LRU,如下所示:
$ memcached -M -m 1024
启动时必须注意的是,小写的“-m”选项是用来指定最大内存大小的。不指定具体数值则使用默认值64MB。
指定“-M”参数启动后,内存用尽时memcached会返回错误。 话说回来,memcached毕竟不是存储器,而是缓存,所以推荐使用LRU。
2: 分布式算法,一致性hash
3:单个命令式原子的,提高cas操作
4:memcached高并发失效问题:
1:缓存失效时候,很可能高并发查询DB的情况
就是在你比如缓存了key=list vlaue=xxx的对象时候,失效了导致很多线程过来查询db
解决方法: 后台定时一个任务去更新缓存,显然不可取
在失效的时候保证只有一个线程进入db,先更新缓存,如何保证只有一个线程更新呢?
public list Pget test(int id){
llist list = client.get(getKey(id));
if(list == null){ // 这里保证 加锁? 可以但是分布式环境肯定不行,只能用分布式锁?
client.set(getListFromDB(id), time);
}else{
xx
}
}
可以考虑用memcahe的add方法:但是所有倒要等待这个,如果时间稍长点就会对服务器造成想不到的压力, 如何做:可以想办法在过期前就更新,我们可以把对应的过期时间也保存起来没取一次判定是否更新
具体情况具体分析吧:
(redis也有这种情况)
Redis:
丰富的数据结构 string hash list set zset, 高效的内存,可以持久化
缺点: 目前不支持服务端集群,3.0应该可以解决
我们目前架构是接合redis 和mysql,redis开启了AOP昨晚对mysql的辅助,提高分布式锁,减少mysql压力
·1: 游戏的实时聊天
2: 排行榜
3: 标记,计数,开关
4: 接合mysql分页
5: 串行化,分布式锁,
等
在jedis层面再对redis进行一次分装,可以参考spring data redis设计,
目前木有分片,也没怎么研究过,
redis持久化: rdb和aof
rdb快照的方式 ,通过save来配置;
redis的事务和乐观锁
乐观锁 watch
事务 multi exec; 事务不支持回滚,
mysql实现乐观锁; 在表的字段加一个version版本号,更新的时候+1;