数据库缓存策略

数据库

指持久化数据库,如

  • mysql
  • mongodb

缓存

指内存型的数据存储,如

  • redis
  • memcached

一个良好的缓存策略需兼顾

  • 命中率
  • 缓存数据与数据库数据的一致性

对命中率的兼顾

多大的命中率是好的?

用数学知识来分析这个问题,先设定几个关键的参数

  • T(c):读一次缓存所需时间
  • T(d):读一次数据库所需时间
  • G:缓存命中率

一次数据读取所需的时间的期望值为:

T(c)*G + (T(c)+T(d))*(1-G)

增加数据库缓存的目标为提高数据读取速度,可以归结为一个表达式

T(c)*G + (T(c)+T(d))*(1-G) < T(d)

等同于

T(c) - T(d)*G < 0

读取速度提升的比值为

(T(d)*G - T(c))/T(d)

假如,T(d)=50ms,T(c)=10ms,G=0.6,读取速度提升比值为

(50*0.6 - 10)/50 = 0.4

化为百分比也就是40%。

假如,T(d)=50ms,T(c)=10ms,G的值必须大于

G = T(c)/T(d) = 0.2

才能期望读取速度得到提升。

可以看出

加入缓存不一定能够提升读取性能,这取决于缓存读取速度、数据库读取速度以及缓存的命中率。

对数据一致性的兼顾

这里只探讨对数据一致性有高要求的场景,可以总结为

只要数据库有更新,就要使和已更新数据相关的所有缓存失效。

最终的策略

先从缓存的key入手

为了确保缓存数据的唯一性,key的前缀可以是这样的

<server_name>:<db_name>:<table_name>
  • server_name 服务器名称
  • db_name 数据库名称
  • table_name 表名称

还要区分简单查询与复杂查询

  • 简单查询:根据主键进行的查询
  • 复杂查询:除简单查询外的都是复杂的

key前缀加上查询类型

<server_name>:<db_name>:<table_name>:<query_type>

举个例子

对app服务器上的数据库做简单查询

select * from homestead.users where id in (1,2,3)

对应的缓存key

app:homestead:users:simple:{1,2,3}

复杂查询

select * from homestead.users where age > 18

对应的缓存key

app:homestead:users:complex:{select * from homestead.users where age > 18}

缓存失效策略

假定sql-1更新了id为3,4,5的数据库记录

#sql-1
update homestead.users set age=age+1 where age>18

更新完成后需失效的缓存

  • 缓存类型为复杂查询的
  • 缓存类型为简单查询的,且id包含3、4、5的

缓存选型

以上的策略需要缓存支持key的模糊查询,例如查询id包含3的类型为简单查询的缓存key。

Redis自1.0.0版本开始支持根据模式查询缓存中的key,例如

KEYS app:homestead:users:simple:{*,3,*}

可以看出,1.0.0及以上版本的Redis满足该策略的需求。
不够幸运的是,memcached暂时不满足需求。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值