1、模板引擎
常日我们可以合营利用freemaker/velocity等模板引擎来抗住大量的要求
2、双层nginx来提升缓存命中率

对付支配多个nginx而言,如果不加入一些数据的路由策略,那么可能导致每个nginx的缓存命中率很低。因此可以支配双层nginx
分发层nginx卖力流量分发的逻辑和策略,根据自己定义的一些规则,比如根据productId进行hash,然后对后端nginx数量取模将某一个商品的访问要求固定路由到一个nginx后端做事器上去后端nginx用来缓存一些热点数据到自己的缓存区3、推举架构
nginx作为最前真个web cache系统,常日的架构如下
这个构造的优点:
可以利用nginx前端进行诸多繁芜的配置,这些配置从前在squid是没法做或者做起来比较麻烦的,比如针对目录的防盗链。nginx前端可以直接转发部分不须要缓存的要求。由于nginx效率高于squid,以是某些情形下可以利用nginx的缓存来减轻squid压力。可以实现url hash平分派策略可以在最前端开启gzip压缩,这样后面的squid缓存的纯粹是无压缩文档,可以避免很多无谓的穿透。由于nginx稳定性比较高,以是lvs不须要常常调度,通过nginx调度就可以。squid的文件打开数按默认的1024就绰绰有余,不过处理的要求可一个都不会少。可以启用nginx的日志功能取代squid,这样做实时点击量统计时可以精确定位到url,不必要再用低效率的grep来过滤。由于nginx的负载能力高于squid,以是在用lvs分流时可以不必分得特殊均衡,涌现单点故障的几率比较低。nginx和squid合营搭建的web做事器前端系统架构:
前真个lvs和squid,按照安装方法,把epoll打开,配置文件照搬,基本上问题不多。
这个架构和app_squid架构的差异,也是关键点便是:加入了一级中层代理,中层代理的好处实在太多了:
gzip压缩:压缩可以通过nginx做,这样,后台运用做事器不管是apache、resin、lighttpd乃至iis或其他古怪做事器,都不用考虑压缩的功能问题。负载均衡和故障屏蔽:nginx可以作为负载均衡代理利用,并有故障屏蔽功能,这样,根据目录乃至一个正则表达式来制订负载均衡策略变成了小case。方便的运维管理,在各种情形下可以灵巧订定方案。权限清晰:这台机器便是不写程序的掩护职员卖力,程序员一样平常不须要管理这台机器,这样如果涌现故障,很随意马虎能找到精确的人。对付运用做事器和数据库做事器,最好是从掩护职员的视线中消逝,我的目标是,这些做事只要能跑得起来就可以了,其它的事情全部可以在外部处理掉。redis(看架构也可以考虑memcache)用户的要求,在nginx没有缓存相应的数据,那么会进入到redis缓存中,redis可以做到全量数据的缓存,通过水平扩展能够提升并发、高可用的能力
1、持久化机制:将redis内存中的数据持久化到磁盘中,然后可以定期将磁盘文件上传至S3(AWS)或者ODPS(阿里云)等一些云存储做事上去。
1)RDB
对redis中的数据实行周期性的持久化,每一刻持久化的都是全量数据的一个快照。对redis性能影响较小,基于RDB能够快速非常规复
2)AOF
以append-only的模式写入一个日志文件中,在redis重启的时候可以通过回放AOF日志中的写入指令来重新构建全体数据集。(实际上每次写的日志数据会先到linux os cache,然后redis每隔一秒调用操作系统fsync将os cache中的数据写入磁盘)。对redis有一定的性能影响,能够只管即便担保数据的完全性。redis通过rewrite机制来保障AOF文件不会太弘大,基于当前内存数据并可以做适当的指令重构。
如果同时利用RDB和AOF两种持久化机制,那么在redis重启的时候,会利用AOF来重新构建数据,由于AOF中的数据更加完全,建议将两种持久化机制都开启,用AO F来担保数据不丢失,作为数据规复的第一选择;用RDB来作不同程度的冷备,在AOF文件都丢失或破坏不可用的时候来快速进行数据的规复。
2、redis集群
1)replication
一主多从架构,主节点卖力写,并且将数据同步到其他salve节点(异步实行),从节点卖力读,紧张便是用来做读写分离的横向扩容架构。这种架构的master节点数据一定要做持久化,否则,当master宕机重启之后内存数据清空,那么就会将空数据复制到slave,导致所有数据消逝
2)sentinal哨兵
哨兵是redis集群架构中很主要的一个组件,卖力监控redis master和slave进程是否正常事情,当某个redis实例故障时,能够发送报警关照给管理员,当master node宕机能够自动转移到slave node上,如果故障转移发生来,会关照client客户端新的master地址。sentinal至少须要3个实例来担保自己的健壮性,并且能够更好地进行quorum投票以达到majority来实行故障转移。
前两种架构办法最大的特点是,每个节点的数据是相同的,无法存取海量的数据。因此哨兵集群的办法利用与数据量不大的情形
3)redis cluster
redis cluster支撑多master node,每个master node可以挂载多个slave node,如果mastre挂掉会自动将对应的某个slave切换成master。须要把稳的是redis cluster架构下slave节点紧张是用来做高可用、故障主备切换的,如果一定须要slave能够供应读的能力,修正配置也可以实现(同时也须要修正jedis源码来支持该情形下的读写分离操作)。
redis cluster架构下,master便是可以任意扩展的,直接横向扩展master即可提高读写吞吐量。slave节点能够自动迁移(让master节点只管即便均匀拥有slave节点),对全体架构过载冗余的slave就可以保障系统更高的可用性。
ehcachetomcat jvm堆内存缓存,紧张是抗redis涌现大规模灾害。如果redis涌现了大规模的宕机,导致nginx大量流量直接涌入数据生产做事,那么末了的tomcat堆内存缓存也可以处理部分要求,避免所有要求都直接流向DB。
具有以下特性:
1、快速轻量
过去几年,诸多测试表明Ehcache是最快的Java缓存之一。Ehcache的线程机制是为大型高并发系统设计的。大量性能测试用例担保Ehcache在不同版本间性能表现得同等性。很多用户都不知道他们正在用Ehcache,由于不须要什么特殊的配置。API易于利用,这就很随意马虎支配上线和运行。很小的jar包,Ehcache 2.2.3才668kb。最小的依赖:唯一的依赖便是SLF4J了。2、伸缩性
缓存在内存和磁盘存储可以伸缩到数G,Ehcache为大数据存储做过优化。大内存的情形下,所有进程可以支持数百G的吞吐。为高并发和大型多CPU做事器做优化。线程安全和性能总是一对抵牾,Ehcache的线程机制设计采取了Doug Lea的想法来得到较高的性能。单台虚拟机上支持多缓存管理器。通过Terracotta做事器矩阵,可以伸缩到数百个节点。3、灵巧性
Ehcache 1.2具备工具API接口和可序列化API接口。不能序列化的工具可以利用除磁盘存储外Ehcache的所有功能。除了元素的返回方法以外,API都是统一的。只有这两个方法不一致:getObjectValue和getKeyValue。这就使得缓存工具、序列化工具来获取新的特性这个过程很大略。支持基于Cache和基于Element的过期策略,每个Cache的存活韶光都是可以设置和掌握的。供应了LRU、LFU和FIFO缓存淘汰算法,Ehcache 1.2引入了最少利用和前辈先出缓存淘汰算法,构成了完全的缓存淘汰算法。供应内存和磁盘存储,Ehcache和大多数缓存办理方案一样,供应高性能的内存和磁盘存储。动态、运行时缓存配置,存活韶光、空闲韶光、内存和磁盘存放缓存的最大数目都是可以在运行时修正的。4、标准支持
Ehcache供应了对JSR107 JCACHE API最完全的实现。由于JCACHE在发布以前,Ehcache的实现(如net.sf.jsr107cache)已经发布了。实现JCACHE API有利于到未来其他缓存办理方案的可移植性。Ehcache的掩护者Greg Luck,正是JSR107的专家委员会委员。5、可扩展性
监听器可以插件化。Ehcache 1.2供应了CacheManagerEventListener和CacheEventListener接口,实现可以插件化,并且可以在ehcache.xml里配置。节点创造,冗余器和监听器都可以插件化。分布式缓存,从Ehcache 1.2开始引入,包含了一些权衡的选项。Ehcache的团队相信没有什么是万能的配置。实现者可以利用内建的机制或者完备自己实现,由于有完全的插件开拓指南。缓存的可扩展性可以插件化。创建你自己的缓存扩展,它可以持有一个缓存的引用,并且绑定在缓存的生命周期内。缓存加载器可以插件化。创建你自己的缓存加载器,可以利用一些异步方法来加载数据到缓存里面。缓存非常处理器可以插件化。创建一个非常处理器,在非常发生的时候,可以实行某些特定操作。6、运用持久化
在VM重启后,持久化到磁盘的存储可以复原数据。
Ehcache是第一个引入缓存数据持久化存储的开源Java缓存框架。缓存的数据可以在机器重启后从磁盘上重新得到。
根据须要将缓存刷到磁盘。将缓存条款刷到磁盘的操作可以通过cache.flush()方法来实行,这大大方便了Ehcache的利用。
7、分布式缓存
从Ehcache 1.2开始,支持高性能的分布式缓存,兼具灵巧性和扩展性。
分布式缓存的选项包括:
通过Terracotta的缓存集群:设定和利用Terracotta模式的Ehcache缓存。缓存创造是自动完成的,并且有很多选项可以用来调试缓存行为和性能。利用RMI、JGroups或者JMS来冗余缓存数据:节点可以通过多播或创造者手动配置。状态更新可以通过RMI连接来异步或者同步完成。Custom:一个综合的插件机制,支持创造和复制的能力。可用的缓存复制选项。支持的通过RMI、JGroups或JMS进行的异步或同步的缓存复制。可靠的分发:利用TCP的内建分发机制。节点创造:节点可以手动配置或者利用多播自动创造,并且可以自动添加和移除节点。对付多播壅塞的情形下,手动配置可以很好地掌握。分布式缓存可以任意韶光加入或者离开集群。缓存可以配置在初始化的时候实行勾引程序员。BootstrapCacheLoaderFactory抽象工厂,实现了BootstrapCacheLoader接口(RMI实现)。缓存做事端。Ehcache供应了一个Cache Server,一个war包,为绝大多数web容器或者是独立的做事器供应支持。缓存做事端有两组API:面向资源的RESTful,还有便是SOAP。客户端没有实现措辞的限定。RESTful缓存做事器:Ehcached的实现严格遵照RESTful面向资源的架构风格。SOAP缓存做事端:Ehcache RESTFul Web Services API暴露了单例的CacheManager,他能在ehcache.xml或者IoC容器里面配置。标准做事端包含了内嵌的Glassfish web容器。它被打成了war包,可以任意支配到支持Servlet 2.5的web容器内。Glassfish V2/3、Tomcat 6和Jetty 6都已经经由了测试。8、Java EE和运用缓存
为普通缓存场景和模式供应高质量的实现。
壅塞缓存:它的机制避免了复制进程并发操作的问题。
SelfPopulatingCache在缓存一些开销昂贵操作时显得特殊有用,它是一种针对读优化的缓存。它不须要调用者知道缓存元素若何被返回,也支持在不壅塞读的情形下刷新缓存条款。
CachingFilter:一个抽象、可扩展的cache filter。
SimplePageCachingFilter:用于缓存基于request URI和Query String的页面。它可以根据HTTP request header的值来选择采取或者不采取gzip压缩办法将页面发到浏览器端。你可以用它来缓存全体Servlet页面,无论你采取的是JSP、velocity,或者其他的页面渲染技能。
SimplePageFragmentCachingFilter:缓存页面片段,基于request URI和Query String。在JSP中利用jsp:include标签包含。
已经利用Orion和Tomcat测试过,兼容Servlet 2.3、Servlet 2.4规范。
Cacheable命令:这是一种老的命令行模式,支持异步辇儿动、容错。
兼容Hibernate,兼容Google App Engine。
基于JTA的事务支持,支持事务资源管理,二阶段提交和回滚,以及本地事务。
经典的缓存+数据库读写的模式1、读的时候,先读缓存,缓存没有的话,那么就读数据库,然后取出数据后放入缓存,同时返回相应
2、更新的时候,先删除缓存,然后再更新数据库
之以是更新的时候只是删除缓存,由于对付一些繁芜有逻辑的缓存数据,每次数据变更都更新一次缓存会造成额外的包袱,只是删除缓存,让该数据下一次被利用的时候再去实行读的操作来重新缓存,这里采取的是
举个例子,一个缓存涉及的表的字段,在1分钟内就修正了20次,或者是100次,那么缓存跟新20次,100次;但是这个缓存在1分钟内就被读取了1次,因此每次更新缓存就会有大量的冷数据,对付缓存符合28黄金法则,20%的数据,占用了80%的访问量
数据库和redis缓存双写不一致的问题1、最低级的缓存不一致问题以及办理方案
问题:如果先修正数据库再删除缓存,那么当缓存删除失落败来,那么会导致数据库中是最新数据,缓存中依旧是旧数据,造成数据不一致。
办理方案:可以先删除缓存,再修正数据库,如果删除缓存成功但是数据库修正失落败,那么数据库中是旧数据,缓存是空不会涌现不一致
2、比较繁芜的数据不一致问题剖析
问题:对付数据发生来变更,先删除缓存,然后去修正数据库,此时数据库中的数据还没有修正成功,并发的读要求到来去读缓存创造是空,进而去数据库查询到此时的旧数据放到缓存中,然后之前对数据库数据的修正成功来,就会造成数据不一致
办理方案:将数据库与缓存更新与读取操作进行异步串行化。当更新数据的时候,根据数据的唯一标识,将更新数据操作路由到一个jvm内部的行列步队中,一个行列步队对应一个事情线程,线程串行拿到行列步队中的操作一条一条地实行。当实行行列步队中的更新数据操作,删除缓存,然后去更新数据库,此时还没有完成更新的时候过来一个读要求,读到了空的缓存那么可以先将缓存更新的要求发送至路由之后的行列步队中,此时会在行列步队积压,然后同步等待缓存更新完成,一个行列步队中多个相同数据缓存更新要求串在一起是没故意义的,因此可以做过滤处理。等待前面的更新数据操作完成数据库操作之后,才会去实行下一个缓存更新的操作,此时会从数据库中读取最新的数据,然后写入缓存中,如果要求还在等待韶光范围内,不断轮询创造可以取到缓存中值就可以直接返回(此时可能会有对这个缓存数据的多个要求正在这样处理);如果要求等待事宜超过一定时长,那么这一次的要求直接读取数据库中的旧值
对付这种处理办法须要把稳一些问题:
读要求永劫壅塞:由于读要求进行来非常轻度的异步化,以是对超时的问题须要格外把稳,超过超时时间会直接查询DB,处理不好会对DB造成压力,因此须要测试系统高峰期QPS来调度机器数以及对应机器上的行列步队数终极决定合理的要求等待超时时间多实例支配的要求路由:可能这个做事会支配多个实例,那么必须担保对应的要求都通过nginx做事器路由到相同的做事实例上热点数据的路由导师要求的倾斜:由于只有在商品数据更新的时候才会清空缓存,然后才会导致读写并发,以是更新频率不是太高的话,这个问题的影响并不是特殊大,但是的确可能某些机器的负载会高一些后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注下~