sql 2008服务器内存一直居高不下_服务器监控及问题定位排除

本文介绍了如何监控和排查SQL 2008服务器内存问题,包括CPU、数据源连接池、内存占用、磁盘、线程和网络连通性的监控方法,提供异常定位思路,帮助解决服务器性能异常。
摘要由CSDN通过智能技术生成

作者简介:null为90后,从事互联网系统开发6年时间,现专注于系统架构的解决方案,以及新技术的研究实践等相关工作,技术能力突出,创新能力强。在多个项目中担任架构师,各种疑难杂症的克星。 

服务器监控及问题定位排除

一、前言

生产环境除了因业务代码缺陷导致的服务不可用之外,还会因服务器性能或网络环境等原因导致服务异常,更多的时候生产系统故障是多种原因共同作用的结果。

在异常发生时,要快速分析定位异常的原因,并争取在短时间内恢复服务或将异常影响降到最低。这就需要开发和运维人员掌握一些常用的服务器监控手段,并了解生产环境问题排除的基本思路和方法。

下面分别就常用服务器监控手段和问题定位排除思路进行介绍和分享。

二、服务器监控与异常定位

日常关注的服务器监控指标主要包括CPU负载、数据源连接池、内存占用、磁盘占用、线程状况、网络连通性等几个方面,对于监控体系不是很完善的系统,还需要登入服务器后台操作。下面分别介绍各指标对应的常用的监控方法及异常定位方法。

2.1.CPU占用

CPU负载是最能直观反映服务器当前的运行状况的指标,CPU负载过高会导致服务响应变慢甚至服务不可用,可通过登入服务器后台执行命令来监控CPU负载情况。

top命令

top命令是最常用的服务器性能监控命令,登入后台执行top命令后,会定时刷新输出服务器资源占用情况。如下图所示:

03bfc4c9618be46c44caed66929872d4.png

图2-1 top命令监控服务器CPU负载

关于top命令的高级用法和输出参数的具体含义,可参考以下博客中的介绍:

f8702fcb24655b74df7240ca8fdd5f3f.png

针对CPU负载,我们一般只需要关注两处参数,load average和进程占用CPU时间比。

load average即系统负载,输出了1分钟、5分钟、15分钟前到现在的任务队列平均值,一般情况下load average值不超过服务器CPU线程数,就说明进程没有排队现象,如超过CPU线程数量,则说明服务器压力偏高,会出现服务响应慢或不可用的现象(比如4C8G的服务器,如果load average值超过4,则说明服务器压力偏高)。

查看服务器线程数可使用以下命令:

cat /proc/cpuinfo |grep "processor"|sort -u|wc -l

如果监控到服务器load average过高,需要进一步定位是哪些进程和线程占用CPU资源高,这时可先观察各进程占用的CPU时间比。执行top命令后,再键入大写P,进程列表就会根据%CPU列排序,可以获取到占用CPU资源多的进程PID。

获取到进程PID后,执行ps -mp PID -o THREAD,tid,time命令,根据TIME列找到最占用CPU时间的线程,记录下线程号TID。

839b76fbc50f9d45823d685cd1f31c38.png

图2-2 定位异常线程

之后执行printf "%x\n" TID命令,将线程ID转换为16进制。

770117be1ac369f8c393c010ca7c56c7.png

图2-3 线程号转换进制

最后执行命令jstack PID | grep TID打印出异常线程的堆栈信息(注意,需使用服务启动用户执行执行jstack命令)。

62b8e9281901c9a4c0d729d5517ef1d1.png

图2-4 输出异常线程堆栈

vmstat命令

vmstat命令与top命令类似,可以输出给定时间间隔的服务器的状态值,包括服务器的CPU使用率、内存使用率、虚拟内存使用情况、IO等。vmstat 1表示间隔1秒采集输出,执行结果如下图所示:

910443272c57339c650b6edb3fc14f36.png

图2-5 vmstat执行结果

对于CPU负载监控,我们一般只需要关注前两列r b,以及最后的us sy id列。

r:表示CPU任务队列,即等待执行的进程数,此值与load average值类似,如超过CPU线程数,则说明进程出现排队,服务器压力偏高。

b:阻塞的进程数,如果此值恒不为0,则说明中间件有进程阻塞,需要进一步排查。

us:用户CPU占用时间。

sy:系统CPU占用时间。

id:系统CPU空闲时间。

us+sy+id=100,故如果us或sy值很高,说明服务器压力很大。

更多vmstat命令介绍可参考以下博客内容:

a1967391301ffd7077aa6bab22ffc1e6.png

2.2.数据源连接池

数据库连接是珍贵且重要的资源,故数据源连接池也是经常关注的服务器监控指标。开发和运维人员可以通过中间件的监控功能监控数据源健康状况。

数据源监视页面我们需要关注的指标包括活动连接平均计数、当前活动连接计数、最大活动连接计数、当前容量等。下面分别说明各指标含义。

活动连接平均计数:

顾名思义,为数据源实例在当前Server的平均活动连接计数,它一定程度上代表了SQL执行效率,如果此值常大于1,则说明可能存在慢SQL导致数据源连接未能及时释放,或存在线程阻塞情况,需要进一步分析线程堆栈并进行优化。分析线程堆栈的方法详见2.5节。

当前活动连接计数:

最直观的数据库连接数指标,对于Spring管理数据源连接的工程,即使是请求热点时间,多次刷新此值也不应一直大于1,如活动连接数一直维持不下降,则大概率是出现了线程阻塞,需要分析线程堆栈找出STUCK的线程及数据源的调用点。

最大活动连接计数:

反应了数据源连接池曾经达到过的最大活动连接计数,如果此值达到或接近连接池设置的最大连接数限制,则需要警惕是否出现了SQL效率问题或数据库连接泄露,之后通过SQL优化或连接池扩容等手段缓解连接池压力。

当前容量:

当前容量代表了连接池中所有的数据库连接,当前容量-当前活动连接计数=非活动连接计数,此值一般在统计某台服务器的数据源活动、非活动连接时用到。

2.3.内存占用

内存溢出是生产Server最常见的宕机原因,对于内存使用率的监控一般通过命令和gclog配合实现。

free -m命令

free命令可以显示服务器当前内存使用情况,-m代表以兆字节为单位显示。执行后结果如下图所示:

d842c73711f6a5f3624a268cd642cc51.png

图2-6 执行free命令观察内存使用情况

第一行Mem含义:

total 总内存

used 已经使用内存

free 空闲内存

shared 共享内存

buffers Buffer 缓冲区内存

cached Page 高速缓存

第二行(-/+ buffers/cache):

used 应用实际使用的内存(第一行used-buffers-cached)

free 实际可分配的内存(第一行free+buffers+cached)

第三行Swap(交换区,即虚拟内存):

total 交换区总空间

used 已用的交换区空间

free 剩余的交换区空间

我们一般关注第二行的used和free指标,即排除缓存区的内存占用情况。

当第二行的free已经很少,且Swap区的used很多时,就说明服务器内存不足,需要进行内存调优或内存扩容。

更多free命令介绍可参考以下博客内容:

f9647e5fd542c43d82f6e7147c2646bf.png

jmap命令

对于JVM堆栈的内存分析,可以通过jmap命令实现(注意,需使用服务启动用户执行执行jmap命令)。

最常用的命令是jmap -histo:live pid,用来输出堆内对象的内存占用情况。执行结果示例如下:

95258b468aafb1f622d5aca4b14ba28f.png

图2-7 jmap命令分析内存泄露

可以在输出的列表中观察到堆内对象的名称(class name)、创建实例数(instances)、占用内存(bytes),如果某类的内存占用特别多,则可推测有内存泄露。

更多内存调优命令介绍,可参考以下博客内容:

8d623ecc18b89c894c9e21fe75091aab.png

gclog分析

除了通过命令观察服务器内存占用情况之外,输出的JVM gclog也是判断内存是否需优化的重要依据。gclog示例如下:

883494e44458ddb0205f6d35bdf075b4.png

图2-8 gclog输出

第一列是时间戳,从堆创建时开始计时。

第二列是垃圾收集类型,一般的gclog输出包括GC和Full GC两种(也有部分gclog输出的是YC和OC,含义一样),分别代表年轻态和老年态垃圾收集。

第三列表示垃圾收集前后对应栈区的内存占用,括号内是堆总内存占用。

最后一列是系统中断时长。

正常情况下,垃圾收集多是年轻态的垃圾收集,特点是速度快,系统中断时间短,耗时一般在毫秒级。

而Full GC,即老年态垃圾收集的耗时就比较长,一般是秒级。

如果gclog中短时间内出现大量Full GC,且系统中断时间都较长(十几秒或几十秒),则说明当前堆有内存溢出风险,需要马上进行处理释放内存。

更多Java GC相关介绍可参阅以下博客:

86142745e28fe7b912dbf16d351da545.png

hprof文件分析

对于生产环境的内存溢出问题,一般没有时间去仔细分析问题原因,多会选择直接重启处理。在重启之前可以生成heap hprof文件,后续通过工具分析堆栈快照来定位问题。

生成hprof文件的方法有多种:

一种是手动执行命令生成,根据JDK版本选择堆栈输出命令:

jmap -dump:format=b,file=mydump.hprof PID

jrcmd PID hprofdump filename=mydump.hprof

另一种是在JVM参数增加如下配置:

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=.mydump.hprof

配置完成后,在OOM时JVM会自动生成hprof文件到指定目录。

获取hprof文件后,可以选择使用内存分析工具MAT(Memory Analyzer Tool)来分析堆栈文件。

MAT下载地址和简介可到官网获取:

dca4fec0767ea39a388c43abd495fd52.png

MAT简单教程可参考以下博客地址:

afc0c5a8fe8eaf364bff086b96336eba.png

使用MAT打开堆栈文件后,可以在Overview视图中观察到各对象的内存占用概况。如下图所示:

bc71026456fca8127a2ccb59ee2f2f1b.png

图2-9 MAT Overview视图

之后进入Dominator tree视图,可以看到所有的活动对象,并可按照内存占用大小排序。如下图所示:

a31723f09341d4c0fc64981f853adee5.png

图2-10 MAT Dominator tree视图

选取可能出现内存泄露的对象,然后右键点击List objects with outgoing references,查看这个对象持有的外部对象引用。如下图所示:

905803cd4286b5bd9bec4ec8f6f917c6.png

图2-11 MAT 打开外部对象引用视图

可以在外部对象引用列表中找到疑似造成内存溢出的调用点。

bf2720ba85484d8bbcb2573660ac1456.png

图2-12 MAT 外部对象引用视图

之后按照内存占用大小排序,逐步找出占用较多内存的对象。

8b73e23ef4b204e143ea5e409b0de862.png

图2-13 MAT 定位内存溢出点

到这里已经可以大致定位造成内存溢出的点。

2.4.磁盘占用

磁盘空间也是需要定时关注的服务器监控指标之一,尤其是对于一些基于文件存储的服务,如影像存储服务器和缓存服务器。

查看磁盘空间常用的命令是df和du,下面分别进行介绍。

df命令

如果要查看服务器磁盘空间使用率,可以通过df -h命令,执行结果示例如下:

5d3ede464a7543bbbcce2b78ea4ec187.png

图2-14 查看磁盘分区

此命令会列出文件系统所有磁盘分区的大小和使用占比,如果目标目录的磁盘使用率(Use%)超过80%,则需要尽快进行磁盘空间清理或扩容。

du命令

如果要查看目录下各文件夹和文件的大小,可以进到对应目录下,然后执行du -sh *命令,执行结果示例如下:

3355fcb61a167f9572cbc3528b81d593.png

图2-15 查看文件和文件夹大小

之后可以根据需要执行rm -rf命令删除部分占用空间的文件夹和文件。

2.5.线程占用

线程阻塞和线程不足也是常见的造成服务不可用的原因,尤其是对于包含异步线程逻辑的系统,更应该关注线程的使用情况。

线程数限制

生产服务器一般会设置用户的最大线程数限制,如果用户创建的线程数超过此限制,就会报出OutOfMemoryError:unable to create new native thread错误(OutOfMemoryError有多种类型,不一定都是堆内存溢出)。

查看用户线程数限制可执行ulimit -a命令(文件打开数限制open files也可以看到):

085290707f82c3a6fdf6224e68fcf972.png

图2-16 查看线程数限制

查看当前线程数可通过pstree -p | wc -l命令:

d97713f7b62c5b7ee81b2c4155570676.png

图2-17 查看当前线程数

查看线程堆栈详情可以通过执行jstack PID命令,或在Weblogic控制台中转储线程堆栈。在输出的线程详情中可以找出异常的活动线程、异步线程,或者阻塞的线程。

jstack命令执行示例如下:

623b97176d39446eb42603cbb51b293b.png

图2-18 查看线程堆栈

Weblogic转储线程堆栈的方法示例如下:

7483fc39085754077b17b33a80ea6af5.png

图2-19 转储线程堆栈

转储线程堆栈结果示例如下:

a0a3fad7c7190f4f327fe6d9443ffd87.png

图2-20 转储线程堆栈结果

线程阻塞定位

在发生线程阻塞时,需要在堆栈中快速定位STUCK的线程。可以通过jstack命令搜索,或在Weblogic控制台中转储线程堆栈搜索。

执行jstack PID | grep STUCK找到阻塞的线程,命令示例如下:

ad88791dd5a1c382cfacb85bee4ef86b.png

图2-21 查找阻塞线程

Weblogic控制台中转储线程堆栈后,可直接在浏览器中Ctrl+f搜索STUCK关键字,找到阻塞的线程。

2.6.网络连通性

一些服务需要调用外部系统的接口,有些接口地址还需要配置网络跨区访问,所以针对一些新增的接口地址要提前进行网络连通性检测,尤其是新增的服务器,要根据权限配置清单逐一验证网络连通性。下面介绍几种常用的网络连通性验证方法。

telnet命令

telnet命令是最常用的网络连通性检测命令(由于很多服务器都对ping命令做了限制,且ping命令不能指定端口,故建议使用telnet,不过ping命令还是有很多用处的,比如查看域名解析的IP,或者查看网络延迟和丢包率),用于检测到目标IP:Port的网络是否连通。命令格式为:telnet IP Port,执行结果如下图所示:

99c9e7a6646146a4c9ae53c0d8f4f7a6.png

图2-22 telnet检测网络连通性

如果提示Connected则说明网络是连通的,如果一直Trying就说明网络不通。检测完毕后ctrl+]+quit退出。

有些服务器没有安装telnet,这时可以利用ssh远程登录口令测试网络连通性。命令格式为:ssh -p Port -v root@IP,执行结果如下图所示:

6e6f38a3dbe1b740e5923bd5785cb200.png

图2-23 ssh检测网络连通性

如果提示connection established,则说明网络是连通的。

curl命令

对于外部接口的检测,有时候仅确认网络连通是不够的,还需要检测接口是否可用,这时可以利用curl命令测试接口可用性。

curl支持模拟Get和Post调用,对于Get调用或不带参数的接口,可以直接执行curl URL测试接口可用性。示例如下:

3909f1cdcea63e46017c552acc998d6f.png

图2-24 curl测试接口可用性(get)

对于参数在Header里的Post请求,命令格式为:

curl -d "args1=a&args2=b" URL

对于参数在Body里的Post请求,可以指定Content-type,命令格式为:

echo 'XML'|curl -X POST -H 'Content-type:text/xml' -d @- URL

netstat命令

服务器偶尔会报出无法建立连接或too many open files的错误,这时除了要考虑网络问题和文件打开数限制(此处的文件打开数是习惯叫法,更准确的描述是句柄限制,建立网络连接同样需要消耗句柄)之外,还需要考虑是否有未及时关闭的连接,即是否有大量的TIME_WAIT和CLOSE_WAIT连接。

关于TIME_WAIT和CLOSE_WAIT和介绍可参考以下博客:

748b087ad3f07f13b36cd5e09345c372.png

可以通过netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'命令查看服务器的连接状态,执行结果示例如下:

73ecb180bdf686cec11eff2e4cd7deb2.png

图2-25 netstat查看连接状态

如果TIME_WAIT或CLOSE_WAIT数量偏高且持续增长,则说明程序中可能出现了socket句柄泄露,需要通过代码扫描等手段检查是否有未及时释放的资源。

对于未释放的连接,可以通过ss | grep HostIP的命令查找具体未释放的目标IP和端口,HostIP指本地IP。

三、问题解决思路

引发生产环境故障的问题虽种类繁多但也可大致归类,通过每次的问题解决过程也能积累一些经验和教训。这里整理出一些问题解决的原则,并针对不同的问题场景梳理出对应的解决思路,尽可能使后续解决问题的过程中少走弯路。

3.1问题解决原则

下面是根据以往的问题解决经验整理出的一些问题解决原则:

1第一时间确认影响范围

在问题报出后,要借助运维反馈或观察后台等手段,第一时间确认问题的影响范围。这有助于判断问题发生的原因,并方便后续的问题排除操作。

2日志输出永远是关键

对于服务端的异常定位,后台日志永远是最主要的依据。大部分异常发生的原因都可以通过后台日志输出直接定位到,而且我们还可以通过观察后台日志来评估当前服务器状态和问题是否解决。

3找到对应的人

生产环境某功能或模块出现异常后,要尽快找到该功能或模块对应的开发人员、报出问题的测试或运维人员、对此业务熟悉的人、有权做出决策的人、能解决问题的人。有时定位问题的方法再科学,也不如熟悉此项业务的人定位问题快,尽量避免浪费时间。

4尽可能减小影响范围

对于短时间无法解决的问题,要尝试减小问题影响范围。如果出问题的功能模块已预设了开关就迅速关闭开关;如果无论如何都会造成影响,那就选择影响最小的解决方案,有丢车保帅的机会要果断保全重要的和多数的功能。

5一切都是可怀疑的

在定位生产问题的过程中,经常会有“应该不是某某的原因”、“这块代码应该上了”、“这个开关没人动”、“我的某某功能绝对不会出问题”类似的想法,要摒弃这种想法。在有确实证据前,一切都是可怀疑的,避免因主观臆断错失解决问题的时机。

6尽量不重启

在生产系统发生问题时,我们可能首先想到的解决方案是重启服务。诚然,重启的确可以处理大部分类型的异常,但重启的成本是非常高的,包括时间成本和重启后的二次风险成本,如果遇到的问题是重启不能解决的,很可能会出现重复重启的恶性循环。

所以除非确认重启可以解决问题,否则不要轻易重启。

7故障排除过程中做好记录

解决生产问题的过程往往是忙乱的,为了避免问题解决后下次遇到同样问题走弯路,要尽量在故障排除的过程中做好记录,比如保留各时间点的日志和堆栈信息,对各项参数指标截图保存等,方便后续针对该问题的复盘和分析。

8善用头脑风暴

个人的经验再丰富也无法应对所有的问题,尤其是当生产环境出问题时,负责定位和解决问题的同事往往会承担很大压力,很容易陷入思维定式,影响解决问题时效。因此在问题发生时,要尽量召集所有相关人员,进行短时间的头脑风暴,这更有助于快速定位和解决问题,也能增加大家解决问题的经验和意识。

3.2常见问题场景及应对思路

下面列出几种常见的问题场景及应对思路。

1某接口功能报错

接口功能报错是最常见的问题场景,定位问题的思路一般是首先确定影响范围,然后定位报错代码,之后分析报错原因。

确定影响范围一般是通过运维同事反馈和观察后台日志输出,其目的是大概判断问题是由某个功能的程序代码导致的,还是程序外因素导致的。

之后开始定位报错代码。对于集成了日志链路跟踪的工程来说,这项工作比较简单,因为接口在报错后会返给客户端一个唯一的请求编码,根据请求编码可以比较容易地跟踪到请求链路。而对于没有请求编码的异常,需要根据关键字到后台依赖脚本搜出报错代码,如果搜索实在困难,再考虑依赖独立环境重现等方法截取报错信息。

获取报错信息和堆栈后,其实已经很容易判断报错原因,之后再根据具体情况,选择关闭开关、关闭功能、升级补丁版本等方式解决问题。

2数据库连接池报警

数据库连接池报警一般是由两类原因导致,一是数据库连接因为某种原因没有及时释放;二是应用程序无效率问题,但是请求量过大,数据库连接池容量不足。

因请求量过大(如DoS攻击)导致的数据库连接池报警比较罕见,我们可以通过微服务监控中心查看当前服务并发量,或直接观察后台的请求量和响应时间判断是不是请求量过大。

大部分的数据库连接池报警还是由于数据库连接没有及时释放导致的,没有及时释放的原因又分以下几种:

①数据库连接打开后未关闭:这个问题多见于老系统DBPool和DBManager的调用方式,数据源open后未在finally中close就容易造成数据库连接泄露。此问题如果已经发生,没有很好的方法定位,因此需要在代码上线之前就依赖Sonar等代码扫描工具对代码进行漏洞扫描,避免数据源连接泄露的问题。

②线程未及时结束:这是针对Spring架构数据库连接与Spring线程绑定的情况,由于数据库连接的打开和关闭由Spring统一管理,Spring线程不结束,数据库连接就不会主动关闭(除非有commit操作)。所以当程序中出现死循环、线程阻塞、调用外部系统超时、服务器负载过高等导致线程无法及时结束的情况,就会造成数据库连接无法及时释放,数据库连接池资源会迅速耗尽。可以通过观察后台日志、线程堆栈和服务器负载来定位是否此原因。

③慢SQL或数据库锁:有些数据库连接池报警是由于执行SQL时线程阻塞造成的,比如执行一些有效率问题的SQL或者存在数据库锁。此类原因一般可通过观察线程堆栈找出阻塞线程,或请DBA协助定位是否存在慢SQL和数据库锁来确认。

④不健康的数据库连接:此类问题比较罕见,多发生在数据库故障或网络故障导致的数据源连接不可用后。如果数据库故障或网络故障一直未恢复,那么数据库连接就会一直报错,只能等待恢复;但这里还有一种情况是数据库和网络已恢复,数据库连接依然报错,这种一般是由于数据库连接池中存在不健康的连接导致的,需要配置连接池的定时检测策略,以及时剔除不健康的数据库连接。Weblogic数据库连接池的连接检测策略示例配置如下:

41b415326c5af421096d27329cabbbaf.png

图3-1 Weblogic数据源定时检测配置

3接口响应慢或不可用

此类问题是比较难定位的问题,因为造成服务不可用的原因非常多,很多造成问题的原因又互为因果,所以需要逐步排查问题发生的原因。

问题出现后,首先还是应该判断影响范围,是所有接口都不可用,还是某些接口不可用。如果是某些接口不可用,那可以根据该接口功能和在后台搜索堆栈信息判断原因,一般的原因有SQL执行失败、外部系统调用失败、代码死循环、异常被catch未抛出等。如果是全部接口或功能都响应慢或不可用,那可以推测是服务器层面的问题。

服务器层面的问题,首先可以通过观察后台日志输出,排除服务器宕机的情况。一般的接口响应慢或不可用的直接原因,还是服务器CPU负载高,而CPU负载高的原因,除了程序中出现了死循环,多是由于服务器出现了资源争抢。

这里的资源争抢包括:内存不足、线程阻塞或活动线程过多导致的线程不足、数据库连接不足、磁盘IO或网络IO过高导致的句柄不足等等。我们可以通过第二章中介绍的服务器监控和异常定位手段,逐步分析定位到问题根本原因。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值