项目优化

“世界上并没有完美的程序,但我们并不因此而沮丧,因为写程序本来就是一个不断追求完美的过程”。对于项目优化这一句箴言也是完全适用的,没有不需要优化的项目,区别是有些项目亟待优化,而有些项目的优化工作可以慢慢进行。

项目优化涉及的知识面很广。优化的流程通常是根据项目的异常表现进行问题定位,模拟线上场景测试,对多次测试的结果进行综合评估得出合理的优化方案,进而优化再测试上线。项目优化不知是项目负责人需要掌握的内容,对于开发人员也需要了解优化方面的知识,让自己写的代码更加合理健壮。本文总结的项目优化方案是实际工作中积累的一些经验,希望能给有需要的朋友提供一些思路。

本文总结的优化涉及到一下五方面
项目优化_第1张图片

-----------------------------------------前端优化--------------------------------------

1. 使用分页加载、异步加载、分屏加载

  • 数据分步加载对于实现前端功能在是必不可少的。数据的分页展示可以使内容条理清晰,每页只展示定量的数据和数据总量,无论从库中做查询还是浏览器渲染数据都很轻松,而且只要在项目中引入PageHaper等分页插件即可。
  • 异步加载是页面渲染完成后执行方法实现特定效果,页面加载初期可以先渲染出整体轮廓,之后再加载详细内容。以京东官网为例,点击按钮后在1秒内最先加载出的内容包含logo、分类树、轮播图架子、推荐商品架子数据。对于用户来说1秒内看到轮廓,3-4秒内完成全部数据填充是可以接受的。但是如果是点击按钮后白屏4秒就才出现内容就该怀疑网站宕机了。
    项目优化_第2张图片
  • 分屏加载也是降低服务器压力的一个有效手段。还拿京东首页举例,如果用户不滚动屏幕,默认只加载一个屏幕内的内容,用户在滚动屏幕时触发方法进行内容加载。实现数据分屏加载可以参考JS控制html分屏加载

项目优化_第3张图片

2.精简高频访问页面

  • 高频访问页面是指项目主页、电商商品列表、登录页面、主站入口等用户访问频率较高的页面,高频页面往往是用户访问项目的必经之路。高频页面存在大量冗余代码,不仅会拖慢项目,而且会影响用户体验。为了减轻服务器的压力,建议尽量简洁的设计高频页面。在保证功能完整的前提下尽量减少与数据库的交互。对于页面上不太变更的内容,建议存在缓存数据里,或者以静态常量存在项目中。

3.优先使用第三方的静态资源

  • 电商平台在接入第三方供应商时需要在商品页面展示相应图片信息,对于不是必须要落地的数据建议优先使用第三方的静态资源。比如主图、小图、详情图可以在浏览器加载时直接访问第三方的图片地址,图片数据不落地可以节省服务器开销,而且在更新商品数据时也只需要修改商品表字段即可。这样做的缺点是数据的展示要受到第三方的制约,如果对方的图片服务器出现问题,就意味着用户看不到对应的信息。
  • 对于通过功能上架商品的供应商来说,商品的图片是必须要保存在服务器的。为了降低服务器压力,可以将图片做压缩处理,比如用户上架的商品主图为a.jpg,我们可以相应生成多个规格的小图,图片名称为200X200a.jpg、100X100.jpg,200X200即位商品尺寸,这样我们可以在列表展示200X200的图片,购物车和收藏里展示100X100的图片,而且数据在展示是只需要固定的字符串“200X200”+a.jpg即可,可以把"200X200"、"100X00"设置为静态变量供前端调用,而在商品详情页面可以展示主图。

-----------------------------------服务端优化---------------------------------------

1.服务化拆分

  • java应用从单点结构到服务化再到微服务化,是解决海量用户需求的探索历程。传统的单点应用无力应对高并发和大体量数据。对于项目中公用且访问频率高的模块可以以微服务的形式剥离出主应用。主应用与各服务之间的调用关系通过注册中心进行分配管理,这样做的好处是可以降低主应用的负载,而且项目模块逻辑也更加分明,各个服务只需要专注于自己的模块,把自己需要负责的业务模块以接口的形式暴露给其他应用。比如短信、邮件、检索、日志等模块是业务逻辑较少的内容,可以优先服务化。至于涉及业务逻辑较多的模块,就要评估拆分对整个项目的冲击,在进行合理规划后再做拆分。

2.使用消息队列

  • 对数据准确性要求较低的功能可以使用消息队列进行削峰填谷,比如订单支付后要对商品增加销量,商品修改后要更新检索系统的数据,对于这些功能可以维护一个消息队列去实现数据的延时处理,从而减少高峰期的应用压力。不过消息队列的使用会引发数据一致性、消息事物的问题,所以要在引入前就做好应对策略。

-------------------------------------操作系统优化---------------------------------

1. 网络速度和服务器性能

上行速率是指服务器给基站发送信息时的数据传输速率,下行速率是指基站向服务器发送信息时的传输速率。在生产环境中项目必不可少的要调取其他平台数据或者接口,例如调取短信运营商接口、调取供应商接口、调取物流接口等等。服务器作为项目的运行平台,网络速率自然会影响到项目访问效果和运行情况。

  • windows环境可以使用自带工具排查网络占用异常,打开资源管理器选择联网标签,在最下面列出了机器的所有网卡,包括虚拟网卡的线路速度和网络使用率:
    项目优化_第4张图片

  • 上图展示出本服务器有一个网络适配器(网卡),实时占用率为0%。点击性能后选择资源监视器按钮,在资源监视器面板选择网络页签即可查看即时网络活动情况:
    项目优化_第5张图片

  • 可以从‘网络活动的进程’看出当前有很多java应用在运行。可以勾选一个对应进程前的复选框即可看到这个应用的网络使用情况。

  • Linux下可以安装dstat工具进行统信息统计,安装命令为yum install -y dstat,安装完后就可以使用了,dstat非常强大,可以实时的监控cpu、磁盘、网络、IO、内存等使用情况。安装完成后输入‘dstat’即可查看cpu、disk、net、page、system信息。默认情况下,dstat每秒都会刷新数据。如果想退出dstat,你可以按"CTRL+C"键。
    项目优化_第6张图片

  • CPU状态:CPU的使用率。这项报告更有趣的部分是显示了用户,系统和空闲部分,这更好地分析了CPU当前的使用状况。如果你看到"wait"一栏中,CPU的状态是一个高使用率值,那说明系统存在一些其它问题。当CPU的状态处在"waits"时,那是因为它正在等待I/O设备(例如内存,磁盘或者网络)的响应而且还没有收到。

  • 磁盘统计(dsk):磁盘的读写操作,这一栏显示磁盘的读、写总数。

  • 网络统计(net):网络设备发送和接受的数据,这一栏显示的网络收、发数据总数。

  • 分页统计(paging):系统的分页活动。分页指的是一种内存管理技术用于查找系统场景,一个较大的分页表明系统正在使用大量的交换空间,或者说内存非常分散,大多数情况下你都希望看到page in(换入)和page out(换出)的值是0 0。

  • 系统统计(system):这一项显示的是中断(int)和上下文切换(csw)。这项统计仅在有比较基线时才有意义。这一栏中较高的统计值通常表示大量的进程造成拥塞,需要对CPU进行关注。你的服务器一般情况下都会运行运行一些程序,所以这项总是显示一些数值。

  • dstat的其他使用参数可以参考Linux服务器 dstat 监控工具

  • 通过对系统网络环境的排查可以定位出是否因为网络导致系统响应缓慢,网站业务量激增可能导致原本设定的带宽无法满足实际需求,对于频繁调用网络的模块可以考虑做集群处理或者增加带宽,也可以采用微服务的形式将此模块抽离出主系统。

2.web服务器代理优化

出于对服务器的保护,正式项目会采用web服务器代理请求。web服务器的模式设定会影响到项目响应速度。apache在并发100时会出现响应缓慢的情况,可以选择MPM处理并发。可以用一个简单的方法鉴定web服务器代理效果:在使用域名请求项目响应缓慢的情况下,通过内网服务器使用IP直接访问项目,如果IP访问响应明显快于域名访问,那么就需要针对web服务器做优化了。

----------------------------------数据库查询优化----------------------------------

  • 数据库的使用状况也会影响到项目响应时间,常见问题有:单表数据大、表锁死、表索引不合理、sql不合理、库的写入数据量不合理。单表数据大会是操作表的速度变慢,多个线程同时操作这一张表时会出现线程卡死的情况。针对数据量大的表可以采用定期备份清理,或者按照时间定期创建表。
-----SqlServer查询查询数据库中所有表数据量-----
DECLARE @SQL VARCHAR(MAX)  
SELECT @SQL=ISNULL(@SQL+'  
UNION ALL ','')+'SELECT '''+NAME+''' AS TB,COUNT(1) AS TOTAL FROM ['+NAME+']'  
FROM SYS.TABLES  
EXEC (@SQL) 
  • 针对表锁死、表索引不合理、sql不合理的情况在SqlServer下可以使用报表功能进行排查。打开SQL Server Management Studio选择相应数据库右键选择报表中的表准报表,选择相应事务选项找到当前较不合理的和较耗时的sql进行相应优化。
    项目优化_第7张图片

-------------------------------------JVM优化---------------------------------------

  • 由于代码不规范或者jvm参数设定不合理也会导致项目卡顿。代码不规范典型案例有:循环里new对象、死循环、不关闭输出流、多线程处理耗时逻辑、线程锁死。遇到这种情况需要针对表现定位问题所在,这些情况会导致服务器负载升高、CPU飙升,内存占用增大等现象。针对这种情况需要根据实际情况排查代码,比如定时器执行频繁时明显变慢了,那就对定时器模块仔细排查,调接口频率高变慢就针对性的排查接口模块代码。
  • 由于new对象过多或者jvm参数设定不合理导致的gc回收垃圾不及时,可以借助工具进行排查。windows环境建议使用jdk自带的jvisualvm工具,这个软件也可以远程查看Linux环境中的tomcat。这个工具包括对CPU、内存、线程、类都做了监控。在“工具”-》“插件”-》可用插件项中选择Visual GC并下载安装,选择项目使用的tomcat双击即可查看所有所有测量数据。切换到 “Visual GC"标签页
    项目优化_第8张图片
  • 整个区域分为三部分:spaces、graphs、histogram
  • 1 spaces区域:代表虚拟机内存分布情况。从图中可以看出,虚拟机被分为Perm、Old、Eden、S0、S1
  • 注意:如果对每个区域基本概念不是很熟悉的可以先了解下java虚拟机运行时数据区这篇文字。
  • 相关原理可以参考这篇博文《【转】Java内存与垃圾回收调优》
  • 1.1 perm:英文叫做Permanent Generation,我们称之为永久代。(根据深入java虚拟机作者说明,这里说法不是不是很正确,因为hotspot虚拟机的设计团队选择把GC分代收集扩展至此而已,正确的应该叫做方法区或者非堆)。
  • 1.1.1 通过VM Args:-XX:PermSize=128m -XX:MaxPermSize=256m 设置初始值与最大值
  • 1.2 heap:java堆(Java heap)。它包括老年代(图中Old区域)和新生代(图中Eden/S0/S1三个统称新生代,分为Eden区和两个Survivor区域),他们默认是8:1分配内存
  • 1.2.1 通过VM Args:-xms512m -Xmx512m -XX:+HeapDumpOnOutofMemoryError -Xmn100m -XX:SurvivorRatio=8 设置初始堆内存、最大堆内存、内存异常打印dump、新生代内存、新生代内存分配比例(8:1:1),因为Heap分为新生代跟老年代,所以512M-100M=412M,老年代就是412M(初始内存跟最大内存最好相等,防止内存不够时扩充内存或者Full GC,导致性能降低)
  • 2 Graphs区域:内存使用详细介绍
  • 2.1 Compile Time(编译时间):6368compiles 表示编译总数,4.407s表示编译累计时间。一个脉冲表示一次JIT编译,窄脉冲表示持续时间短,宽脉冲表示持续时间长。
  • 2.2 Class Loader Time(类加载时间): 20869loaded表示加载类数量, 139 unloaded表示卸载的类数量,40.630s表示类加载花费的时间
  • 2.3 GC Time(GC Time):2392collections表示垃圾收集的总次数,37.454s表示垃圾收集花费的时间,last cause表示最近垃圾收集的原因
  • 2.4 Eden Space(Eden 区):括号内的31.500M表示最大容量,9.750M表示当前容量,后面的4.362M表示当前使用情况,2313collections表示垃圾收集次数,8.458s表示垃圾收集花费时间
  • 2.5 Survivor 0/Survivor 1(S0和S1区):括号内的3.938M表示最大容量,1.188M表示当前容量,之后的值是当前使用情况
  • 2.6 Old Gen(老年代):括号内的472.625M表示最大容量,145.031M表示当前容量,之后的87.031表示当前使用情况,79collections表示垃圾收集次数 ,28.996s表示垃圾收集花费时间
  • 2.7 Perm Gen(永久代):括号内的256.000M表示最大容量,105.250M表示当前容量,之后的105.032M表示当前使用情况
  • 3 Histogram区域:survivor区域参数跟年龄柱状图
  • 3.1 Tenuring Threshold:表示新生代年龄大于当前值则进入老年代
  • 3.2 Max Tenuring Threshold:表示新生代最大年龄值。
  • 3.3 Tenuring Threshold与Max Tenuring Threshold区别:Max Tenuring Threshold是一个最大限定,所有的新生代年龄都不能超过当前值,而Tenuring Threshold是个动态计算出来的临时值,一般情况与Max Tenuring Threshold相等,如果在Suivivor空间中,相同年龄所有对象大小的总和大于Survivor空间的一半,则年龄大于或者等于该年龄的对象就都可以直接进入老年代(如果计算出来年龄段是5,则Tenuring Threshold=5,age>=5的Suivivor对象都符合要求),它才是新生代是否进入老年代判断的依据。
  • 3.4 Desired Survivor Size:Survivor空间大小验证阙值(默认是survivor空间的一半),用于Tenuring Threshold判断对象是否提前进入老年代。
  • 3.5 Current Survivor Size:当前survivor空间大小
  • 3.6 histogram柱状图:表示年龄段对象的存储柱状图
  • 3.7 如果显示指定-XX:+UseParallelGC --新生代并行、老年代串行收集器 ,则histogram柱状图不支持当前收集器
  • 根据数据表现进行相应参数调优。创造优质代码是没办法速成的,只有通过不断学习,慢慢打打磨自己的技能。

你可能感兴趣的:(项目优化)