首页 >> 大全

常见性能优化策略的总结

2022-06-21 大全 134 作者:考证青年

常见性能优化策略的总结

常见性能优化策略分类

代码

将代码放在首位的原因是它最容易被技术人员忽视。很多技术人员拿到一个性能优化需求后,一定会称之为缓存、异步、JVM等。其实第一步应该是分析相关代码,找到对应的瓶颈,然后再考虑具体的优化策略。有一些性能问题,完全是由于代码编写不合理造成的。问题可以直接修改代码解决,比如for循环太多,做很多不必要的条件判断,重复同样的逻辑很多次。

数据库

数据库调优一般分为以下三个部分:

SQL 调优

这个是最常用的,每个技术人员都应该掌握基本的SQL调优方法(包括方法、工具、辅助系统等)。这里以 MySQL 为例,最常见的方式是通过内置的慢查询日志或开源的慢查询系统定位具体有问题的 SQL,然后使用 , 等工具逐步调优,最终实现测试后的效果。在线的。这方面的详细内容请参考 MySQL 索引原理与慢查询优化。

架构级别调优

这类调优包括读写分离、多slave负载均衡、横向和纵向分库分表等。一般需要大改动,但频率不如SQL调优,而且一般要求DBA配合参与。那么这些事情什么时候需要做呢?我们可以通过内部监控和报警系统(例如)定期跟踪某些指标数据是否达到瓶颈。一旦达到瓶颈或警告值,就需要考虑这些事情。通常,DBA 也会定期监控这些指标值。

连接池调优

为了实现数据库连接的高效获取和数据库连接的限流,我们的应用通常采用连接池类型的方案,即每个应用节点对每个数据库管理一个连接池。随着业务访问量或数据量的增长,原有的连接池参数可能无法很好的满足需求。这时候就需要结合当前使用连接池的原理、具体的连接池监控数据和当前的业务量,在综合判断的基础上,通过多次反复调试得到最终的调优参数。

缓存

类别

本地缓存(/,, Guava Cache等),缓存服务(Redis/Tair/等)。

场景

什么时候适合使用缓存?考虑以下两种情况:

选择注意事项

设计要点

缓存什么时候更新?如何保证更新的可靠性和实时性?

更新缓存的策略需要具体问题具体分析。这里以store POI的缓存数据为例,说明缓存服务类型的缓存更新策略是什么。目前,大约有 100,000 个 POI 数据使用 Tair 作为缓存服务。具体更新策略有两种:

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

对于一个缓存服务,理论上,随着缓存数据的增多,在容量有限的情况下,缓存一天肯定会满的。如何应对?

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

②对于当前设置的容量,设置一个合适的警告值,比如10G缓存。当缓存数据达到8G时,会发出告警,提前排查问题或扩容。

③给一些不需要长期保存的key,尝试设置过期时间。

缓存是否允许未命中?万一丢了怎么办?

根据业务场景,判断是否允许丢失。如果不允许,则需要具有持久化功能的缓存服务来支持,例如 Redis 或 Tair。具体可以根据业务对丢失时间的容忍度,选择更具体的持久化策略,比如Redis的RDB或者AOF。

缓存“崩溃”的问题

对于一些设置了过期时间的key,如果这些key在某些时间点可能会被超高并发访问,那就是非常“热”的数据。这时需要考虑另外一个问题:缓存“击穿”的问题。

常见性能优化策略的总结

异步

场景

对于一些客户端请求,服务器可能需要为这些请求做一些辅助的事情。事实上,用户并不关心这些事情,或者用户不需要立即得到这些事情的处理结果。这种情况比较适合异步处理这些事情。

功能

常见做法

一种方法是打开额外的线程。这里可以采用多开一个线程或者使用线程池的做法,在IO线程以外的线程中处理相应的任务(处理请求响应),让IO线程中的第一个线程。返回。

如果为异步线程处理的任务设计的数据量很大,可以引入阻塞队列进一步优化。具体方法是让一批异步线程不断往阻塞队列中丢数据,然后再启动一个额外的处理线程从队列中批量取出一批预设大小的数据进行批量处理(比如发送一批远程服务)请求),这进一步提高了性能。

另一种方法是使用消息队列 (MQ) 中间件服务,它本质上是异步的。一些额外的任务可能不需要我的系统来处理,而是需要其他系统来处理。这时候可以先把它封装成一个消息,扔到消息队列中,通过消息中间件的可靠性将消息传递给关心它的系统,然后让系统做相应的处理。

比如C端完成提单后,可能需要其他终端做一系列的事情,但是这些事情的结果不会立即影响到C端用户,所以可以先响应向C端订单请求先返回给用户,再向MQ发送消息再返回。而这些事情不应该是C端的责任,所以这个时候用MQ的方式来解决这个问题是最合适的。

NoSQL

缓存和缓存的区别

首先,我解释一下,这里介绍的部分与缓存部分不同。虽然可能使用相同的数据存储方案(如 Redis 或 Tair),但使用方式不同。本节介绍它作为 DB 使用。如果作为DB使用,需要有效保证数据存储方案的可用性和可靠性。

场景

需要结合具体的业务场景,看这个业务涉及的数据是否适合NoSQL存储,数据操作方式是否适合NoSQL操作,或者NoSQL的一些附加特性(比如加减法等)。

如果业务数据不需要与其他数据关联,不需要事务或外键等支持,并且可能写入非常频繁,此时NoSQL(如HBase)更适合。

例如,美团点评有一个内部监控系统。如果应用系统出现严重故障,可能会在短时间内产生大量数据。如果此时选择 MySQL,MySQL 的瞬时写入压力会飙升。容易造成MySQL服务器性能急剧恶化、主从同步延迟等问题。这种场景比较适合Hbase这样的NoSQL存储。

JVM 调优

什么时候调整?

通过对机器的一些关键指标(gc time,gc count,每一代的内存大小变化,机器负载)也可以看gc log和jstat等命令的输出,结合在线JVM进程服务的一些关键接口的性能数据和请求体验,基本上可以发现有没有问题当前的 JVM 以及是否需要调整。

如何调音?

如果发现高峰期CPU使用率和Load值过大,此时可以观察一些JVM 和gc (可能主要是young gc )。一个历史经验值进行对比),基本可以确定young gc的频率太高了。这时候可以通过适当增加young区的大小或比例来解决。如果你发现关键接口的响应时间很慢,可以结合gc日志中的gc时间和stop the world time,看看整个应用的stop the world time是不是比较长。如果是,则可能需要减少总 gc 时间。具体可以从减少gc的次数和减少单次gc的时间两个维度来考虑。一般来说,这两个因素是一对相互排斥的因素。我们需要调整相应的参数(比如新生代与老年代的比例,eden与老年代的比例,MTT值,触发cms恢复的老区比例阈值,等)根据实际监测数据达到最优值。如果full gc或old cms gc出现的非常频繁,这种情况通常会导致STW时间相应增加,也会导致接口响应时间变慢。在这种情况下,“内存泄漏”的可能性很高。 Java中的内存泄漏意味着一些应该释放的对象没有被释放(并且引用正在拉它)。那么这些对象是如何创建的呢?为什么不发布?对应的代码有问题吗?问题的关键在于理解这一点,找到对应的代码,然后对症下药。所以问题的症结在于转化为找到这些对象。如何找到它?综合使用jmap和MAT,基本可以定位到具体的代码。

多线程和分布式

场景

离线任务、异步任务、大数据任务、长时间任务**的运行,如果使用得当,可以达到加速的效果。

注意:在线响应时间高的时候,尽量少用多线程,尤其是服务线程需要等待任务线程的时候(很多重大事故都与此息息相关)。如果一定要使用,可以给线程设置一个最大等待时间。

常见做法

如果单机的处理能力能够满足实际业务的需要,那么尽量使用单机多线程的处理方式,降低复杂度;否则,需要使用多机多线程的方式。

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

如果单机处理能力不能满足要求,此时应采用多机多线程的方式。这个时候需要一些分布式系统的知识。首先,必须引入一个单独的节点作为调度器,其他机器节点作为执行器节点。调度器负责拆分任务,将任务分发到合适的执行器节点;执行器节点以多线程方式(可能是单线程)执行任务。这时候,我们整个任务系统已经从一键式进化为集群系统,不同的机器节点扮演着不同的角色,各司其职,相互交互。这时,除了多线程、线程池等机制外,RPC、心跳等网络通信调用等机制也必不可少。后续我会想出一个简单的分布式调度框架。

测量系统(监控、警报、服务依赖管理)

测量系统严格来说不属于性能优化的范畴,但这方面与性能优化息息相关,可以说为性能优化提供了强有力的数据参考和支持。没有衡量系统,基本上无法定位系统的问题,也无法有效衡量优化的效果。很多人不关注这方面,但我认为这是系统稳定性和性能保障的基石。

关键流程

如果要设计系统,一般需要设计哪些关键流程?

①确定指标

②收集数据

③ 计算数据并存储结果

④ 演示与分析

需要监控和提醒哪些指标?需要注意哪些?

根据需要,主要需要两个指标:

接口性能是相关的,包括单个接口和所有的QPS、响应时间、调用量(统计时间维度越详细越好;最好可以从节点或者服务集群的角度来查看相关数据)。它还涉及服务依赖关系的管理。这时候就需要对单机节点使用服务依赖管理系统,包括CPU使用率、Load值、内存使用率、网卡流量等。如果节点是一些特殊类型的服务(如 MySQL、Redis、Tair),还可以监控这些服务特有的一些关键指标。

数据收集方法

通常采用异步上报的方式。具体方法有两种:第一种是发送到本地Flume端口,Flume进程收集远程集群或Storm集群进行操作;第二种方法是直接在本地执行操作后,使用异步和本地队列发送到监控服务器。

数据计算

可以使用离线计算(/Hive)或实时/准实时计算(Storm/Spark),计算结果可以存储在MySQL或HBase中;在某些情况下,可以直接采集并发送到监控服务器,无需计算。 .

显示和分析

提供统一的展示和分析平台,需要有报表(列表/图表)的监控和报警功能。

真实案例研究

案例一:业务与控制区域关系刷新工作

背景

这是一个每小时定期运行的作业,用于刷新商家与控制区域之间的关系。具体规则是根据商户的分布范围(多个)与控制区域是否有交集。如果有路口,则将商户置于此控制区域范围内。

业务需求

此过程需要尽可能短,最好在 20 分钟内。

优化过程

原代码的主要处理流程为:

获取所有商店的送货区域和控制区域的列表。遍历控制区域列表,针对每个控制区域:

一个。遍历商家的配送范围列表,找到与该控制区域相交的配送范围列表。

b.遍历上述商户配送范围列表,将其中的商户ID去重,保存到集合中。

c。根据上述商户ID集合批量获取对应的商户集合。

d。遍历上述商户集合,从中获取每个商户对象,并进行相应处理(根据是否已经是热门商户、自营、在线支付,判断是否需要插入或更新之前的商户和控制区域,等关系)。

e。删除此控制区域中不应存在的当前业务关系列表。

分析代码,找到步骤2中的步骤a和b,找出与某个控制区域相交的配送范围集,并对商户ID进行去重,可以使用R-tree空间索引进行优化。具体方法是:

本次优化已在第一阶段优化启动,整个流程时间从40多分钟缩短到20分钟以内。

第一阶段优化改成R-tree后,跑了一段时间。随着数据量的增加,性能开始逐渐恶化,一个月后已经恶化到50多分钟。于是我继续深入分析代码,找到了两个优化点,安排了第二阶段的优化并上线了。

两个优化点是:

发布后

通过日志观察,将执行时间从50多分钟缩短到15分钟以内。下图为一天四台机器的日志时间(单位:毫秒):

可以看出效果还是很明显的。

案例2:POI缓存设计与实现

背景

2014年Q4,数据库中POI(这里可以简单理解为外卖店)相关数据的读取流量急剧增加。虽然增加从节点可以解决一些问题,但毕竟节点的增加会达到极限是的,达到极限后,主从复制会达到瓶颈,这可能会导致数据不一致。因此,此时迫切需要引入新的技术方案来分担数据库的压力,减少数据库POI相关数据的读取流量。另外,任何场景下考虑添加DB从库都会造成一定的资源浪费。

实施计划

基于现有久经考验的技术方案,我选择了Tair作为缓存存储方案,帮助DB分担各种应用POI数据读取流量的压力。原因主要是从可用性、高性能、可扩展性、是否通过在线大数据和高并发流量的考验、是否有专业的运维团队、是否有成熟的工具等方面。

详细设计

初版设计

缓存的更新策略,根据业务的特点,现有的技术方案和实施成本,选择使用MQ接收POI变化的消息来触发缓存的更新,但是这个过程可能失败;过期策略,调用者会先判断是否过期。如果过期,它会从后端DB加载数据并设置回缓存,然后返回。缓存数据的可用性通过两方面的双重保险来保证。

第二版设计

第一版设计运行一段时间后,发现两个问题:

在某些情况下,无法保证数据的实时一致性(例如技术人员手动修改DB数据,使用MQ更新缓存失败)。这时候只能等待5分钟的过期时间,有些服务是不允许的。加上过期时间会导致另一个问题:Tair 会在缓存未命中的那一刻尝试从硬盘加载数据,如果硬盘没有去 DB 加载数据。这无疑会进一步延长Tair的响应时间,不仅会增加业务的超时率,还会导致Tair的业绩进一步恶化。

为了解决以上问题,我们从美团点评基础设施负责同事那里了解到,在某些情况下缓存数据不一致的问题是可以解决的,并且可以去掉过期时间机制,从而改进查询效率和避免tair in 查询硬盘未命中。并且为了防止单点故障影响我们的业务,我们保留了之前用MQ消息更新缓存的方案,做了一个切换,使用这个方案进行容错。整体架构如下:

常见性能优化策略的总结

发布后

上线后,通过持续的数据监测发现,随着调用次数的增加,到DB的流量明显减少,大大减轻了DB的压力。同时,这些数据接口的响应时间也显着降低。缓存更新的双重保障机制也基本保证了缓存数据的可用性。见下图:

常见性能优化策略的总结

常见性能优化策略的总结

案例3:业务运营后台相关页面的性能优化

背景

随着业务的快速发展,流量和数据量急剧上升。通过我们相应的监控系统,我们可以发现系统的某些页面的性能开始恶化。用户端的反馈也证明了这一点。这个时候就需要快速调度,敏捷开发,调优这些页面。

欢迎页面

常见性能优化策略的总结

组织页面

常见性能优化策略的总结

订单关联建筑页面

常见性能优化策略的总结

其他

除上述之外,优化还涉及到前端、分布式文件系统、CDN、全文索引、空间索引等,限于篇幅,留待以后再介绍。

郑重声明:本文版权归原作者所有,转载文章仅出于传播更多信息之目的。如果作者信息标注有误,请尽快联系我们修改或删除,谢谢。

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了