,身为一个程序员,遇到线上问题那都是家常便饭的事儿。,如果你在深夜看到一群同事围在一起,他们是在共同探讨什么哲学问题么?非也,他们一定是遇到了线上BUG。,线上问题只要影响到了核心业务流程那便是事故,所以一旦事故发生,无论你在约会,还是周末打游戏,甚至是在睡觉,只要接到了来自公司的电话,那只能赶紧连上公司网络加班了。,
,线上问题是复杂多变的,我们一般将bug分为系统级别和业务级别bug。,业务部署在整套系统上运行,一旦出现系统级别bug则业务会被严重拖垮。如CPU爆满、服务不可用、甚至服务器宕机等都属于系统级别的bug。,如果是CPU100%,那是由哪个线程,哪个类,甚至是哪个方法导致的?,若是业务流程正常但是部分服务性能拉跨,那么如何快速定位到问题在哪儿?,因为是线上发生的事儿,所以重点在于如何迅速解决。,以下分享我最常用的一些问题排查工具。,perf是linux的性能分析工具,核心作用之一就是用来查看热点函数的分布情况。,用它可以生成火焰图查看到函数的资源占用情况,函数的调用栈越深火焰就越高。所以对于异常的函数一眼就能看出。,
,如上图通过调用栈你可以看出Monitor管程在反复调用enter和wait,这种情况下就可以判断出该程序已经发生死锁且存在性能问题。假设有大量线程请求这段代码,那么CPU资源将被迅速打满!,在著名的“713B站事故”里技术团队在事故发生时就用到了当前工具生成了火焰图,快速地分析出了事故的根因也就是导致CPU100%的lua热点函数。,ps命令:,我们项目部署的服务器里在跑的进程老多了,java进程、nginx进程、redis、消息队列进程等等。,举个例子,假设在某一流量高峰期系统监控到整个服务性能下降5倍,业务被严重拖垮,在确定没有业务层面bug的情况下大概率就是因为服务性能达到瓶颈了。如何确定瓶颈在哪儿?,大部分情况下通过系统告警就可以知道大概问题所在。如发生消息堆积我们就该怀疑消息生产者和消费者的状态,这个时候就要具体去查看消息队列这一进程。,可以使用一些轻量级的linux命令,如ps:,该命令还可以用于对进程的资源使用情况进行排序:,vmstat命令:,vmstat是Virtual Meomory Statistics(虚拟内存统计)的缩写。,它是一个用于监控内存和磁盘使用情况的工具,但是也可以用来查看CPU的一些指标,如中断次数等。使用它可以查看内存使用的详细信息和磁盘的读/写情况。,
,以上表头字段的说明如下:,从以上命令就可以很清晰地看出服务器的各方面性能情况。除此之外还有以下命令也可以在排查或者调优中使用:,
,出现了业务bug那就纯纯的是开发或测试的锅了。,bug确定后第一步一定是先看日志,只要你写需求的时候日志打的全,一般出现了问题日志或者告警都会第一时间推送。,通过日志我们可以定位到bug对应代码的位置,但这仅仅是第一步,因为你只知道哪里出了问题,并不知道代码出了什么问题(除非一眼就能看出)。,所以下一步,看数据,数据是业务应用的核心。若通过日志和页面表现查看到你的主流程是没有问题的,那么下一步就是要确定表的数据是否有问题,数据存在bug的表现会是各方面的,可能是用户反馈,也可能是流程错误,这要取决于你表的设计。,切记!!线上数据是重中之重,当你决定要修复数据,在处理之前一定要做好备份,这样起码可以保证事情不会变的更糟。一般情况下修改线上数据这种活都需要你写好SQL,然后经过leader审批再交给DBA来操作,一定不要干出删库跑路这种事哟。,假设验证了你数据是OK的,那么问题就极大可能出现在了代码层面。,当代程序员最难过的瞬间无非就是有一个非常紧急的线上bug需要你来解决,但是摆在你面前的却是一堆屎山代码!!,修改业务bug最重要的是要将bug点修改掉并且保证其它业务还能正常运行,这是牵一发而动全身的事情,否则bug只会越改越多。,所以平时应该预知到这些风险,做好代码设计。总结一下定位业务bug的正确步骤:,
,一般公司都有自己的代码设计规范。比如由外到里包装代码,每一个方法都要有对应的职责,并且一个方法不要超过100行,一个类不要超过1000行代码等。清晰的结构可以让你和他人更好地review代码,避免看起来一头雾水。,写业务逻辑有两种方式,一种就是简洁明了的线性逻辑,另一种就是通过封装代码来减少代码耦合提高内聚性,也就是我们说的设计模式的使用。两种方式各有优缺点,但是工作多年了咱写的代码也不能直里直气的,多少得带点”艺术“对吧?推荐一下我经常使用但是也不会特别复杂的设计模式。,这是最常使用的设计模式之一。,工厂模式分为简单工厂模式、工厂方法模式和抽象工厂模式。我们这里讲解简单工厂模式,因为后两个都是以其为基础做改进的。,其结构如下:,通过定义一个用以创建对象的接口, 让子类决定实例化哪个类。,所以其实质就是由一个工厂类根据传入的参数,动态决定应该创建哪一个产品类(这些产品类继承自一个父类或接口)的实例。,其包含以下角色:,
,当遇到需要根据某个前提条件创建不同的类实现时, 可以使用工厂模式。,它是在不必改变原类结构和继承体系的情况下,动态地扩展一个对象的功能。通过创建一个包装对象来实现对功能的扩展,动态的给一个对象添加一些额外的职责。,所以装饰者模式分为主体和装饰者。,其包含角色如下:,
,以上两种设计模式都有着”高扩展性“的特点,我们应该根据业务灵活设计接口,避免需求迭代导致的一坨坨又臭又长的代码。但是设计模式切勿用来炫技,一些较为冷门或者复杂的设计模式不推荐使用,否则当一套代码只有你能维护时,那将会是非常痛苦的。。,当然了这也能够体现出你在公司的不可替代性!,
,
,和减少单一服务故障对整体系统的影响。,
,
,都说小事故伤身,大事故提桶。。一般发生事故后写一张事故单是不可避免的。除了详细描述好事故发生的经过,背锅人,解决方案,后续的事故跟进也是一系列流程的事,多则需要数周去跟进。事故的发生对于团队的技术发展和成型往往起着积极推进作用,所以对于每一个团队来说事故一定是不可避免的。每次事故发生我们都要思考如何完善系统,打破技术壁垒。并且遇到事儿也不要慌,如果是大问题,那么首先背锅的一定是leader!,其实呢一般公司最喜欢的是能快速解决问题的员工,即便这些问题可能是由你创造的。
© 版权声明
文章版权归作者所有,未经允许请勿转载。