第一种情况,也是最常用的情况,就是获取一个帖子对应的回复,sql语句应该是象 select id from T where topicId=2008 order by createTime desc limit 0,5 select id from T where topicId=2008 order by createTime desc limit 5,5 select id from T where topicId=2008 order by createTime desc limit 10,5 的样子,那么这种列表很显然用topicId做散列是最好的,把上面三个列表缓存(可以是N个)都散列到key是topicId=2008这一个Map中,当id是2008的帖子有新的回复时,系统自动把key是topicId=2008的散列Map清除即可。由于这种散列不需要遍历,因此可以设置成很大,例如100000,这样10万个帖子对应的所有回复列表都可以缓存起来,当有一个帖子有新的回复时,其余99999个帖子对应的回复列表都不会动,缓存的命中率极高。
第二种情况,就是后台需要显示最新的回复,sql语句应该是象 select id from T order by createTime desc limit 0,50 的样子,这种情况不需要散列,因为后台不可能有太多人访问,常用列表也不会太多,所以直接放到通用列表缓存B中即可。
第三种情况,获取一个用户的回复,sql语句象 select id from T where userId=2046 order by createTime desc limit 0,15 select id from T where userId=2046 order by createTime desc limit 15,15 select id from T where userId=2046 order by createTime desc limit 30,15 的样子,那么这种列表和第一种情况类似,用userId做散列即可。
第四种情况,获取一个用户对某个帖子的回复,sql语句象 select id from T where topicId=2008 and userId=2046 order by createTime desc limit 0,15 select id from T where topicId=2008 and userId=2046 order by createTime desc limit 15,15 的样子,这种情况比较少见,一般以topicId=2008为准,也放到key是topicId=2008这个散列Map里即可。
列表缓存B是: Key键(String型) Value值(ArrayList型) from T order by createTime desc limit 0,50 ArrayList,对应取出来的所有id from T order by createTime desc limit 50,50 ArrayList,对应取出来的所有id from T order by createTime desc limit 100,50 ArrayList,对应取出来的所有id ……
总结:这种缓存思路可以存储大规模的列表,缓存命中率极高,因此可以承受超大规模的应用,但是需要技术人员根据自身业务逻辑来配置需要做散列的字段,一般用一个表的索引键做散列(注意顺序,最散的字段放前面),假设以userId为例,可以存储N个用户的M种列表,如果某个用户的相关数据发生变化,其余N- 1个用户的列表缓存纹丝不动。以上说明的都是如何缓存列表,缓存长度和缓存列表思路完全一样,如缓存象select count(*) from T where topicId=2008这样的长度,也是放到topicId=2008这个散列Map中。如果再配合好使用mysql的内存表和memcached,加上F5设备做分布式负载均衡,该系统对付像1000万IP/天这种规模级的应用都足够了,除搜索引擎外一般的应用网站到不了这种规模。