问题背景
略谈服务端缓存设计一文说到缓存不是必须的,因为数据库本身就利用了内存。但实际情况是缓存是大型网站的标配。
虽然经验显示RDBMS最快时只需0~1ms就能响应,不逊于专门的缓存,但是当压力增大时,性能的下降也是飞快的。随着业务的逐渐复杂、开发团队的逐渐扩大,难以全面优化所有的SQL,数据库内存的命中率难免下降。
数据库的连接数是有限的、磁盘的并发能力也很差(一块磁盘才一个磁头),因此当访问量增大或数据库内存命中率下降,平均响应速度会陡然下降;更糟的是,某些查询导致大量的冷数据换入并占用数据库内存(例如全表扫描),真正最需要的热数据暂时被挡在内存外,等到1~ms(或更久)之后才能重新被读入数据库内存,到这种时候,压力可能爆棚了。
MySQL的buffer_pool_hit_rate指标统计了命中率。
MySQL有类似于分代LRU的机制,按这个链接调优能有所缓解。
以上分析告诉我们:缓存架构要满足冷热分离的特征——RDBMS不满足,因为冷数据可能挤走热数据。
另外,众所周知,缓存架构还要满足读写分离的特征——RDBMS也不满足,因为写操作会争抢读操作的资源。
鉴于这些局限性,RDBMS终归还是顶不住,缓存成为大型网站的标配就是顺理成章的了。
方案选择略谈服务端缓存设计一文还比较了本地缓存和分布式缓存,首推分布式缓存。那么就要选择一款缓存系统。而且强烈建议预先考虑水平扩展,如果先用了单机方案,之后很难不关机就在线迁移到基于sharding的集群方案。
缓存系统的选择,我随手列一些典型方案(没有每个都用过),分成三系:Memcached系:Twemproxy,Couchbase(自动维护集群)Redis系:Twemproxy,Codis/RebornDB(自动维护集群),官方的RedisCluster(慎用)Java系:ApacheIgnite(自动维护集群,支持多种语言,兼容MemcachedAPI),基础性能低于前两系,但支持SQL查询、事务和丰富的数据结构,还能远程执行代码、推送事件通知、对接本地缓存/数据库/HDFS等。同类产品有Hazelcast、Gemfire。
应用代码怎么写?通常是:读操作先get缓存,若没有,查数据库,并且set缓存;写操作直达数据库,并且delete缓存。这种风格称为直写式缓存。
为避免重复代码,可以利用AOP:Java可用SpringCache,另外Hibernate可自动管理缓存;支持高阶函数的语言自带AOP,把数据操作变成闭包,外层包一个处理缓存的函数。
还有一种风格称为写回式缓存,读写操作都走缓存,由缓存来负责与数据库同步。这种风格需要缓存系统的支持。
结语以上对问题背景和方案选择都做了分析,尤其触及一些知识盲点,然而这只是理论。是的!鉴于实际环境的复杂性(即使是本篇文章也无法反映真实情况),最推荐的做法仍然是实测!根据真实的应用场景来设计你的缓存架构!(并不是只能线上实测,可以在测试环境尽量模拟。)
最后再推荐一些相关文章:
Pinterest谈实战经验:如何在两年内实现零到数百亿的月访问
微博“异地多活”部署经验谈
TheLog:Whateverysoftwareengineershouldknowaboutreal-timedata’sunifyingabstraction
以上文章可点击阅读原文。
白癜风晚期能治愈吗白癜风怎么治愈