今天接到一个需求,在聊天界面右下角新增一个运营活动位,活动信息会通过一个HTTPS接口返回,同时每个活动有一个过期倒计时,在这个倒计时结束之前,后台希望前端不要再次请求了。具体的流程如下
上面例子的特点是后台明确知道数据失效的时间
两个星期前,产品提了一个需求,增加一个动态表情搜索模式,进入该模式的时候自动自动展示全平台最火的20个动态表情,经过和后端同学沟通发现,虽然表情是从实时队列中取的前20个,但是基本前二十在当天的变化不大,因此不希望客户但每次进入搜索模式的时候都调用一次,最终协商之后客户端每次进入聊天界面的时候调用一次。
上面例子的特点是后台不知道数据什么时候失效,但是确定短时间内不会失效
类似的需求和实现在客户端中挺多的,最终积累下来,每次客户端启动的时候请求的接口多达10个,为了避免这种短时间不会失效的数据频繁请求,我们用了几个配置接口做数据下发。
为此我们需要一种缓存机制
说到缓存,绕不开几个特性
- 命中率
- 查询速度
- 时效性,避免使用过期的缓存
- 占用空间,过小命中率低,过大则占用空间
- 为了保证命中率,起码根据28法则,我们最好最少要有足够的空间保存常用的那20%的数据
- 当本地的数据足够多之后,我们也要确保高效的查询效率
- 当使用缓存的手段之后,我们也要确保数据的新鲜度,过期的数据一律需要摒弃,重新向服务器发起请求
- 缓存不是保存越多越好,首先缓存消耗内存,也消耗用户本地空间,因此需要设置最大的缓存大小,同时需要兼顾命中率
设计一个缓存功能
- 依赖后台数据的客户端其实不需要怎么考虑命中率,除非最大缓存空间设置过小,导致用到的缓存被频繁删除
- 查询速度,为了占用空间和查询速度,我们用请求URL进行MD5,作为文件名,同时进行Hash记录
- 时效性,如果后台明确告诉我们失效时间了,那么就在失效时间过期之后再去请求数据,否则我们需要跟后台约定,对数据进行hash,请求的时候带上本地记录的hash码,后台通过对比hash码,决定是否要给客户端返回数据
- 客户端应该设置缓存最大数,并且通过使用合适的淘汰算法,移除超过大小的数据,这里我们用LRU,不用FIFO
通过请求数据,Hash、LRU、DiskLRU一顿操作之后,我们就可以有效得减少用户流量消耗,加快应用的启动速度,减少服务器的带宽压力、减少流量开销、降低服务器数据库压力
小结
经过上面一顿酣畅淋漓地操作之后,我们取得了不错的效果,就是客户端麻烦一点,需要写一套缓存框架,当然我们可以用现成的数据结构和淘汰算法,对了,同时iOS的同学也参考一下,翻译过去就好了,完美。
即使有这么大的好处,但是最终我还是没有去实现上面的设计,不过既然既然今天这个运营活动的流程图写好了,服务端的同学也给出了接口,那么就这样做吧。
其实我之所以不想做,是因为只要一行代码就可以实现上面所有逻辑,但是需要服务端同学配合。