ehcache缓存服务器(缓存服务器原理)「ehcache重启服务器缓存清空」

  本文要感谢我职级评定过程中的一位评委,他发起把之前所做的各种性能优化的案例和方案加以提炼、总结,以文档的情势沉淀下来,并在内部举行分享。力图到达如下结果:

  1.形成可实践、可鉴戒、可参考的各种性能优化的方案以及选型思量点,同时共同具体的真实案例,其他人碰到相似题目时,不消从零开始。

  2.有助于开阔视野,除了性能优化之外,也能提供通用的常见思绪以及方案选型的思量点,资助各人作育在方案选型时的意识、头脑以及做各种衡量的本领。

  文章在内部分享后,引起猛烈分享,得到了不少同事和朋侪的承认和好评,以为对一样平常的工作有很好的引导作用。思量到这些履历大概对业界偕行也有资助,以是在美团点评技能团队博客公开。

  常见性能优化战略分类

  代码

  之以是把代码放到第一位,是由于这一点最轻易引起技能职员的忽视。很多技能职员拿到一个性能优化的需求以后,言必称缓存、异步、JVM等。实际上,第一步就应该是分析相干的代码,找出相应的瓶颈,再来思量具体的优化战略。有一些性能题目,美满是由于代码写的不公道,通过直接修改一下代码就能办理题目的,比如for循环次数过多、作了很多无谓的条件判定、雷同逻辑重复多次等。

  数据库

  数据库的调优,总的来说分为以下三部分:

  SQL调优

  这是最常用、每一个技能职员都应该把握根本的SQL调优本领(包罗方法、工具、辅助体系等)。这里以MySQL为例,最常见的方式是,由自带的慢查询日记大概开源的慢查询体系定位到具体的出题目的SQL,然后利用explain、profile等工具来渐渐调优,末了颠末测试到达结果后上线。这方面的细节,可以参考MySQL索引原理及慢查询优化。

  架构层面的调优

  这一类调优包罗读写分离、多从库负载均衡、程度和垂直分库分表等方面,一样平常必要的改动较大,但是频率没有SQL调优高,而且一样平常必要DBA来共同参加。那么什么时间必要做这些事变?我们可以通过内部监控报警体系(比如Zabbix),定期跟踪一些指标数据是否到达瓶颈,一旦到达瓶颈大概警戒值,就必要思量这些事变。通常,DBA也会定期监控这些指标值。

  毗连池调优

  我们的应用为了实现数据库毗连的高效获取、对数据库毗连的限流等目标,通常会采取毗连池类的方案,即每一个应用节点都管理了一个到各个数据库的毗连池。随着业务访问量大概数据量的增长,原有的毗连池参数大概不能很好地满意需求,这个时间就必要连合当前利用毗连池的原理、具体的毗连池监控数据和当前的业务量作一个综合的判定,通过反复的反复调试得到终极的调优参数。

  缓存

  分类

  本地缓存(HashMap/ConcurrentHashMap、Ehcache、GuavaCache等),缓存服务(Redis/Tair/Memcache等)。

  利用场景

  什么环境适实用缓存?思量以下两种场景:

短时间内雷同数据重复查询多次且数据更新不频仍,这个时间可以选择先从缓存查询,查询不到再从数据库加载并回设到缓存的方式。此种场景较适实用单机缓存。

高并发查询热门数据,后端数据库不堪重负,可以用缓存来扛。

  选型思量

假如数据量小,而且不会频仍地增长又清空(这会导致频仍地垃圾采取),那么可以选择本地缓存。具体的话,假如必要一些战略的支持(比如缓存满的逐出战略),可以思量Ehcache;如不必要,可以思量HashMap;如必要思量多线程并发的场景,可以思量ConcurentHashMap。

其他环境,可以思量缓存服务。如今从资源的投入度、可运维性、是否能动态扩容以及配套办法来思量,我们优先思量Tair。除非如今Tair还不能支持的场合(比如分布式锁、Hash范例的value),我们思量用Redis。

  计划关键点

  什么时间更新缓存?怎样保障更新的可靠性和及时性?

  更新缓存的战略,必要具体题目具体分析。这里以门店POI的缓存数据为例,来阐明一下缓存服务型的缓存更新战略是怎样的?如今约10万个POI数据采取了Tair作为缓存服务,具体更新的战略有两个:

吸取门店变动的消息,准及时更新。

给每一个POI缓存数据设置5分钟的逾期时间,逾期后从DB加载再回设到DB。这个战略是对第一个战略的有力增补,办理了手动变动DB不发消息、接消息更新程序临时堕落等题目导致的第一个战略失效的题目。通过这种双保险机制,有效地包管了POI缓存数据的可靠性和及时性。

  缓存是否会满,缓存满了怎么办?

  对于一个缓存服务,理论上来说,随着缓存数据的日益增多,在容量有限的环境下,缓存肯定有一天会满的。怎样应对?

  ①给缓存服务,选择符合的缓存逐出算法,比如最常见的LRU。

  ②针对当前设置的容量,设置得当的警戒值,比如10G的缓存,当缓存数据到达8G的时间,就开始发出报警,提前排查问题大概扩容。

  ③给一些没有须要长期生存的key,只管设置逾期时间。

  缓存是否答应丢失?丢失了怎么办?

  根据业务场景判定,是否答应丢失。假如不答应,就必要带长期化功能的缓存服务来支持,比如Redis大概Tair。更细节的话,可以根据业务对丢失时间的容忍度,还可以选择更具体的长期化战略,比如Redis的RDB大概AOF。

  缓存被“击穿”题目

  对于一些设置了逾期时间的key,假如这些key大概会在某些时间点被超高并发地访问,是一种非常“热门”的数据。这个时间,必要思量别的一个题目:缓存被“击穿”的题目。

概念:缓存在某个时间点逾期的时间,恰幸亏这个时间点对这个Key有大量的并发哀求过来,这些哀求发现缓存逾期一样平常都会从后端DB加载数据并回设到缓存,这个时间大并发的哀求大概会刹时把后端DB压垮。

怎样办理:业界比力常用的做法,是利用mutex。简单地来说,就是在缓存失效的时间(判定拿出来的值为空),不是立即去loaddb,而是先利用缓存工具的某些带乐成操纵返回值的操纵(比如Redis的SETNX大概Memcache的ADD)去set一个mutexkey,当操纵返回乐成时,再举行loaddb的操纵并回设缓存;否则,就重试整个get缓存的方法。雷同下面的代码:

  publicStringget(key){Stringvalue=redis.get(key);if(value==null){//代表缓存值逾期//设置3min的超时,防止del操纵失败的时间,下次缓存逾期不停不能loaddbif(redis.setnx(key_mutex,1,3*60)==1){//代表设置乐成value=db.get(key);redis.set(key,value,expire_secs);redis.del(key_mutex);}else{//这个时间代表同时间的其他线程已经loaddb并回设到缓存了,这时间重试获取缓存值即可sleep(50);get(key);//重试}}else{returnvalue;}}

ehcache缓存服务器(缓存服务器原理) ehcache缓存服务器(缓存服务器原理)「ehcache重启服务器 缓存清空」 行业资讯

  异步

  利用场景

  针对某些客户端的哀求,在服务端大概必要针对这些哀求做一些附属的事变,这些事变着实用户并不关心大概用户不必要立即拿到这些事变的处理惩罚结果,这种环境就比力适实用异步的方式处理惩罚这些事变。

  作用

收缩接口相应时间,利用户的哀求快速返回,用户体验更好。

克制线程长时间处于运行状态,如许会引起服务线程池的可用线程长时间不敷用,进而引起线程池任务队列长度增大,从而壅闭更多哀求任务,使得更多哀求得不到技能处理惩罚。

线程长时间处于运行状态,大概还会引起体系Load、CPU利用率、呆板团体性能降落等一系列题目,乃至引发雪崩。异步的思绪可以在不增长呆板数和CPU数的环境下,有效办理这个题目。

  常见做法

  一种做法,是额外开辟线程,这里可以采取额外开辟一个线程大概利用线程池的做法,在IO线程(处理惩罚哀求相应)之外的线程来处理惩罚相应的任务,在IO线程中让response先返回。

  假如异步线程处理惩罚的任务计划的数据量非常巨大,那么可以引入壅闭队列BlockingQueue作进一步的优化。具体做法是让一批异步线程不绝地往壅闭队列里扔数据,然后额外起一个处理惩罚线程,循环批量从队列里拿预设巨细的一批数据,来举行批处理惩罚(比如发一个批量的长途服务哀求),如许进一步进步了性能。

  另一种做法,是利用消息队列(MQ)中心件服务,MQ天生就是异步的。一些额外的任务,大概不必要我这个体系来处理惩罚,但是必要其他体系来处理惩罚。这个时间可以先把它封装成一个消息,扔到消息队列内里,通过消息中心件的可靠性包管把消息投递到关心它的体系,然后让这个体系来做相应的处理惩罚。

ehcache缓存服务器(缓存服务器原理) ehcache缓存服务器(缓存服务器原理)「ehcache重启服务器 缓存清空」 行业资讯

  比如C端在完成一个提单动作以后,大概必要别的端做一系列的事变,但是这些事变的结果不会立即对C端用户产生影响,那么就可以先把C端下单的哀求相应先返回给用户,返回之前去MQ中发一个消息即可。而且这些事变理应不是C端的负责范围,以是这个时间用MQ的方式,来办理这个题目最符合。

  NoSQL

  和缓存的区别

  先阐明一下,这里先容的和缓存那一节不一样,固然大概会利用一样的数据存储方案(比如Redis大概Tair),但是利用的方式不一样,这一节先容的是把它作为DB来用。假如当作DB来用,必要有效包管数据存储方案的可用性、可靠性。

  利用场景

  必要连合具体的业务场景,看这块业务涉及的数据是否适实用NoSQL来存储,对数据的操纵方式是否适实用NoSQL的方式来操纵,大概是否必要用到NoSQL的一些额外特性(比如原子加减等)。

  假如业务数据不必要和其他数据作关联,不必要事件大概外键之类的支持,而且有大概写入会非常频仍,这个时间就比力适实用NoSQL(比如HBase)。

  比如,美团点评内部有一个对exception做的监控体系,假如在应用体系发生严峻故障的时间,大概会短时间产生大量exception数据,这个时间假如选用MySQL,会造成MySQL的刹时写压力飙升,轻易导致MySQL服务器的性能急剧恶化以及主从同步耽误之类的题目,这种场景就比力适实用Hbase雷同的NoSQL来存储。

  JVM调优

  什么时间调?

  通过监控体系(如没有现成的体系,本身做一个简单的上报监控的体系也很轻易)上对一些呆板关键指标(gctime、gccount、各个分代的内存巨细变革、呆板的Load值与CPU利用率、JVM的线程数等)的监控报警,也可以看gclog和jstat等下令的输出,再连合线上JVM进程服务的一些关键接口的性能数据和哀求体验,根本上就能定位出当前的JVM是否有题目,以及是否必要调优。

  怎么调?

假如发现高峰期CPU利用率与Load值偏大,这个时间可以观察一些JVM的threadcount以及gccount(大概重要是younggccount),假如这两个值都比以往偏大(也可以和一个汗青履历值尴尬刁难比),根本上可以定位是younggc频率过高导致,这个时间可以通过得当增大young区巨细大概占比的方式来办理。

假如发现关键接口相应时间很慢,可以连合gctime以及gclog中的stoptheworld的时间,看一下整个应用的stoptheworld的时间是不是比力多。假如是,大概必要镌汰总的gctime,具体可以从减小gc的次数和减小单次gc的时间这两个维度来思量,一样平常来说,这两个因素是一对互斥因素,我们必要根据实际的监控数据来调解相应的参数(比如新生代与老生代比值、eden与survivor比值、MTT值、触发cms采取的old区比率阈值等)来到达一个最优值。

假如发生fullgc大概oldcmsgc非常频仍,通常这种环境会诱发STW的时间相应加长,从而也会导致接口相应时间变慢。这种环境,大概率是出现了“内存泄漏”,Java里的内存泄漏指的是一些应该开释的对象没有被开释掉(尚有引用拉着它)。那么这些对象是怎样产生的呢?为啥不会开释呢?对应的代码是不是出题目了?题目的关键是搞明白这个,找到相应的代码,然后对症下药。以是题目的关键是转化成探求这些对象。怎么找?综合利用jmap和MAT,根本就能定位到具体的代码。

  多线程与分布式

  利用场景

  离线任务、异步任务、大数据任务、耗时较长任务的运行**,适本地利用,可到达加快的结果。

  留意:线上对相应时间要求较高的场合,只管少用多线程,尤其是服务线程必要等待任务线程的场合(很多庞大变乱就是和这个痛痒相干),假如肯定要用,可以对服务线程设置一个最大等待时间。

  常见做法

  假如单机的处理惩罚本领可以满意实际业务的需求,那么尽大概地利用单机多线程的处理惩罚方式,镌汰复杂性;反之,则必要利用多机多线程的方式。

  对于单机多线程,可以引入线程池的机制,作用有二:

进步性能,节流线程创建和烧毁的开销

限流,给线程池一个固定的容量,到达这个容量值后再有任务进来,就进入队罗列行列队,保障呆板极限压力下的稳固处理惩罚本领在利用JDK自带的线程池时,肯定要细致明白构造方法的各个参数的寄义,如corepoolsize、maxpoolsize、keepAliveTime、workerqueue等,在明白的底子上通过不绝地测试调解这些参数值到达最优结果。

  假如单机的处理惩罚本领不能满意需求,这个时间必要利用多机多线程的方式。这个时间就必要一些分布式体系的知识了。起首就必须引入一个单独的节点,作为调治器,其他的呆板节点都作为实行器节点。调治器来负责拆分任务,和分发任务到符合的实行器节点;实行器节点按照多线程的方式(也大概是单线程)来实行任务。这个时间,我们整个任务体系就由单击演变成一个集群的体系,而且差别的呆板节点有差别的脚色,各司其职,各个节点之间尚有交互。这个时间除了有多线程、线程池等机制,像RPC、心跳等网络通讯调用的机制也不可少。后续我会出一个简单的分布式调治运行的框架。

  度量体系(监控、报警、服务依靠管理)

  严格来说,度量体系不属于性能优化的范畴,但是这方面和性能优化痛痒相干,可以说为性能优化提供一个强有力的数据参考和支持。没有度量体系,根本上就没有办法定位到体系的题目,也没有办法有效衡量优化后的结果。很多人不器重这方面,但我以为它是体系稳固性和性能保障的基石。

  关键流程

  假如要计划这套体系,总体来说有哪些关键流程必要计划呢?

  ①确定指标

  ②收罗数据

  ③盘算数据,存储结果

  ④显现和分析

  必要监控和报警哪些指标数据?必要关注哪些?

  按照需求出发,重要必要二方面的指标:

接口性能相干,包罗单个接口和全部的QPS、相应时间、调用量(统计时间维度越细越好;最好是,既能以节点为维度,也可以以服务集群为维度,来查察相干数据)。此中还涉及到服务依靠关系的管理,这个时间必要用到服务依靠管理体系

单个呆板节点相干,包罗CPU利用率、Load值、内存占用率、网卡流量等。假如节点是一些特别范例的服务(比如MySQL、Redis、Tair),还可以监控这些服务特有的一些关键指标。

  数据收罗方式

  通常采取异步上报的方式,具体做法有两种:第一种,发到本地的Flume端口,由Flume进程网络到长途的Hadoop集群大概Storm集群来举行运算;第二种,直接在本地运算好以后,利用异步和本地队列的方式,发送到监控服务器。

  数据盘算

  可以采取离线运算(MapReduce/Hive)大概及时/准及时运算(Storm/Spark)的方式,运算后的结果存入MySQL大概HBase;某些环境,也可以不盘算,直吸取罗发往监控服务器。

  显现和分析

  提供同一的显现分析平台,必要带报表(列表/图表)监控和报警的功能。

  真实案例分析

  案例一:商家与控制区关系的革新job

  配景

  这是一个每小时定期运行一次的job,作用是用来革新商家与控制区的关系。具体规则就是根据商家的配送范围(多个)与控制区是否有交集,假如有交集,就把这个商家划到这个控制区的范围内。

  业务需求

  必要这个过程越短越好,最好保持在20分钟内。

  优化过程

  原有代码的重要处理惩罚流程是:

拿到全部门店的配送范围列表和控制区列表。

遍历控制区列表,针对每一个控制区:

  a.遍历商家的配送范围列表,找到和这个控制区相交的配送范围列表。

  b.遍历上述商家配送范围列表,对内里的商家ID去重,生存到一个聚集里。

  c.批量根据上述商家ID聚集,取到对应的商家聚集。

  d.遍历上述商家聚集,从中拿到每一个商家对象,举行相应的处理惩罚(根据是否已是热门商家、自营、在线付出等条件来判定是否必要插入大概更新之前的商家和控制区的关系)。

  e.删除这个控制区当前已有的,但是不应该存在的商家关系列表。

  分析代码,发现第2步的a步调和b步调,找出和某控制区相交的配送范围集归并对商家ID去重,可以采取R树空间索引的方式来优化。具体做法是:

任务开始先更新R树,然后利用R树的布局和匹配算法来拿到和控制区相交的配送范围ID列表。

再批量根据配送范围ID列表,拿到配送范围列表。

然后针对这一批配送范围列表(数量很小),用原始多边形相交匹配的方法做进一步过滤,而且对过滤后的商家ID去重。

  这个优化已经在第一期优化中上线,整个过程耗时由40多分钟收缩到20分钟以内。

  第一期优化改为R树以后,运行了一段时间,随着数据量增大,性能又开始渐渐恶化,一个月后已经恶化到50多分钟。于是继承深入代码分析,探求了两个优化点,安排第二期优化并上线。

  这两个优化点是:

第2步的c步调,原来是根据门店ID列表从DB批量获取门店,如今可以改成mget的方式从缓存批量获取(此时商家数据已被缓存);

第2步的d步调,根据是否已是热门商家、自营、在线付出等条件来判定是否必要插入大概更新之前的商家和控制区的关系。

  上线后结果

  通过日记观察,实行时间由50多分钟收缩到15分钟以内,下图是截取了一天的4台呆板的日记时间(单位:毫秒):

  

  可以看到,结果还是非常显着的。

  案例二:POI缓存计划与实现

  配景

  2014年Q4,数据库中关于POI(这里可以简单明白为外卖的门店)相干的数据的读流量急剧上升,固然说参加从库节点可以办理一部分题目,但是毕竟节点的增长是会到达极限的,到达极限后主从复制会到达瓶颈,大概会造成数据不同等。以是此时,急需引入一种新的技能方案来分担数据库的压力,低落数据库POI相干数据的读流量。别的,任何场景都思量加DB从库的做法,会对资源造成肯定的浪费。

  实现方案

  基于已有的颠末检验的技能方案,我选择Tair来作为缓存的存储方案,来帮DB分担来自于各应用端的POI数据的读流量的压力。来由重要是从可用性、高性能、可扩展性、是否颠末线上大规模数据和高并发流量的检验、是否有专业运维团队、是否有成熟工具等几个方面综合考量决定。

  具体计划

  第一版计划

  缓存的更新战略,根据业务的特点、已有的技能方案和实现本钱,选择了用MQ来吸取POI改变的消息来触发缓存的更新,但是这个过程有大概失败;同时启用了key的逾期战略,而且调用端会先判定是否逾期,如逾期,会从后端DB加载数据并回设到缓存,再返回。通过两个方面双保险确保了缓存数据的可用。

  第二版计划

  第一版计划运行到一段时间以后,我们发现了两个题目:

某些环境下不能包管数据的及时同等(比如技能职员手动改动DB数据、利用MQ更新缓存失败),这个时间只能等待5分钟的逾期时间,有的业务是不答应的。

参加了逾期时间导致别的一个题目:Tair在缓存不掷中的那一刻,会实行从硬盘中Load数据,假如硬盘没有再去DB中Load数据。这无疑会进一步延伸Tair的相应时间,如许不但使得业务的超时比率加大,而且会导致Tair的性能进一步变差。

  为了办理上述题目,我们从美团点评负责底子架构的同事那边相识到Databus可以办理缓存数据在某些环境下不同等的题目,而且可以去掉逾期时间机制,从而进步查询服从,克制tair在内存不掷中时查询硬盘。而且为了防止DataBus单点出现故障影响我们的业务,我们保存了之前接MQ消息更新缓存的方案,作了切换开关,利用这个方案作容错,团体架构如下:

  

  上线后结果

  上线后,通过连续地监控数据发现,随着调用量的上升,到DB的流量有了显着地镌汰,极大地减轻了DB的压力。同时这些数据接口的相应时间也有了显着地镌汰。缓存更新的双重保障机制,也根本包管了缓存数据的可用。见下图:

  

  

  案例三:业务运营背景相干页面的性能优化

  配景

  随着业务的快速发展,带来的访问量和数据量的急剧上升,通过我们相应的监控体系可以发现,体系的某些页面的性能开始出现恶化。从用户方的反馈,也证明白这点。此时如今,有须要敏捷排期,灵敏开辟,对这些页面举行调优。

  欢迎页

需求配景:欢迎页是地推职员以致总部各种脚色职员进入外卖运营背景的首页,会表现地推职员最想看到最关心的一些核心数据,其紧张性不问可知,以是该页面的性能恶化会严峻影响到用户体验。因此,起首必要优化的就是欢迎页。通过相应定位和分析,发现导致性能恶化的重要缘故起因有两个:数据接口层和盘算显现层。

办理方案:对症下药,分而治之。颠末细致排查、分析定位,数据接口层采取接口调用批量化、异步RPC调用的方式来举行有效优化,盘算显现层决定采取预先盘算、再把盘算好的结果缓存的方式来进步查询速率。此中,缓存方案根据业务场景和技能特点,选用Redis。定好方案后,快速开辟上线。

上线结果:上线后性能对比图,如下:

  

构造架构页

需求配景:构造架构页,采取了四层树形布局图,一起出现加载,第一版上线后发现性能非常差。用户急迫盼望对这个页面的性能举行调优。

办理方案:经太过析代码,定位到一个比力经典的题目:内里实行了太多次小数据量的SQL查询。于是采取多个SQL归并成大SQL的方式,然后利用本地缓存来缓存这些数据,公道预估数据量和性能,充实测试后上线。

上线结果:上线后性能对比图,如下:

订单关联楼宇页

需求配景:随着订单量日益增大,订单表积聚的数据日益增多,订单关联楼宇页的性能也日益变差(相应时间线性上升)。而这个页面和地推职员的业绩痛痒相干,以是地推职员利用该页面的频率非常高,性能日益恶化极大地影响了地推职员的用户体验。

办理方案:经太过析与计划,决定采取当时已有的订单二级索引月分表来代替原始的订单表来供前端的查询哀求;而且限定住筛选的时间条件,使得筛选的开始时间和竣事时间不能跨月(事先和用户沟通过,可以担当,能满意用户的根本需求),如许就只需一个月分索引表即可,通过得当的功能限定来到达性能的调优。如许从二级索引月分表中根据各种查询条件查到终极的分页的订单ID聚集,然后再根据订单ID从订单库来查出相应的订单数据聚集。

上线结果:上线后发如今调用量险些没怎么变的环境下,性能提拔显着,如下图:

  其他

  除了上面先容的之外,优化还涉及前端、分布式文件体系、CDN、全文索引、空间索引等几方面。限于篇幅,我们留到将来再做先容。

  图片来自RoadandTrack

  查察文章原网址可点击“阅读原文”。

  更多技能博客:美团点评技能博客。

  PS:正文中标绿的名词均为参考链接,可点击查询。

  美团点评

  技能团队

  https://tech.meituan.com

  长按二维码关注我们

客户评论

我要评论