Web需要解决大访问量的问题,不能局限于数据库。事实上80%的恳求只关注在20%的热门数据上。我们需要建立Web服务器租用和数据库之间的缓存机制。我们可以应用磁盘作为缓存机制,也可以应用内存作为缓存的方法。以此将大部分的热门数据查询,减小数据库的压力。我们在之前的章节也提到过缓存的机制,这一章将做详细的探讨。
页面静态化技巧,用户访问网站的某个页面,大部分网站的页面在很长时间内,可能都是没有变更的。例如一些博客,一旦发布几乎是不会修正内容的。这样,通过动态技巧生成的静态HTML页面缓存到Web服务器的本地磁盘。除了第一次恳求是通过动态技巧査询数据库(或者文本数据)获取之外,之后都直接将本地磁盘文件返回给用户。PHP等框架都供给了这样的技巧来做磁盘缓存。
在Web系统规模比较小的时候,这种做法并没有什么问题。但如果Web系统规模变大,例如,当企业或者业务有数十台数百台服务器的时候,这些盘文件将会有无数份,这样资源就会比较糟蹋,也非常不好掩护。于是有人就提出将磁盘缓存集中到某一台服务器。
在页面静态化的例子中,我们将缓存搭建在Web机器本机,这样掩护起来是有难度的,会带来更多问题。因此我们选择搭建的内存缓存服务一定要是一个独立的服务。
内存缓存的选择有 Redis和 Memcache,我们在前面的章节已经详细介绍过当搭建单台内存缓存后,我们又会见临单独服务器宕机的问题,所以一定要将它变成一个集群。简略的做法是増加一个 slave作为备份机器。但是如果有海量恳求,会创造 cache的命中率不高,所以我们盼望将它配置成一个集群,比如 Redis Cluster。
Redis Cluster集群内的 Redis互为多组主从服务,同时每个节点都可吸收恳求,在拓展集群的时候比较方便。客户端可以向任意一个节点发送恳求,如果是它负责的内容,则直接返回内容;否则,查找实际负责Redis节点,然后将地址告诉客户端,客户端重新发送恳求。
内存缓存服务在切换的时候存在必定风险。在A、B集群切换的过程中,一定要保证B集群的内存中的热门数据应当尽量与A集群雷同,否则切换的一瞬间大批恳求内容在B集群的内存缓存中查找不到,流量直接冲击后端的数据库服务,很可能导致数据库逝世机。
上面机制的目标都是减少数据库的读操作,但是,写的操作也是一个大的压力。写操作虽然无法減少,但是可以通过合并恳求,来起到减小压力的效果。这个时候,我们就需要在内存缓存集群和数据库集群之间,建立一个修正同步机制。
我们可以先将修正恳求生效在缓存中,让外界查询显示正常,然后将这些SQL修正放入到一个队列中存储起来,队列满或者每隔一段时间,合并为一个恳求到数据库中进行更新。
除了转变系统架构的方法提升写的性能外, MYSQL本身也可以通过配置参数 innodb_flush_log_attrx_commit:来调剂写入磁盘的策略。我们也可以选择RAID或者SSD等方法来进步写的性能。
不管数据库的读还是写,当流量再进一步上涨,就会穷尽这些资源当然继绩加服务器也不是不可行,但这么做的成本会比较高。这个时候,对于部分核心数据,就可以考虑应用 NOSQL的数据库。 NOSQL存储大部分都是采用Key/alue的方法,这里比较推荐应用 Redis, Redis本身是一个内存 Cache,同时也可以当作一个存储来应用,让它直接将数据序列化到磁盘。这个我们在前面都有过介绍。
我们可以将数据库中某些被频读写的数据分别出来,放在我们新搭建的 Redis存储集群中,又进一步减小本来 MYSQL数据库的压力,同时因为 Redis本身是个内存级别的 Cache,读写的性能都会大幅度提升。
一般的海量数据网站,架构上采用的解决方案很多是类似上述的方案,不过,应用的缓存服务可能多种多样,会根据自身业务特点开发出自己的缓存服务。
我们还会创造其他的问題,比如数据库中根本不存在的数据查询或者操作恳求。例如,我们会恳求查询一个不存在的信息,系统会从各级缓存逐级查找,最后查到数据库本身,然后才得出查找不到的结论,返回给页面,因为各个级别的各级缓存对它无效(根本不存在)。这个恳求是非常耗费系统资源的,大批的空内容查询,是可以冲击系统服务的。我们可以采用映射表来做缓存,这张映射表对应着记载的映射,如果需要查询不存在的内容,则会被拦阻在外面。