阿里妹导读:有哪些常见的线上故障?如何快速定位问题?本文详细总结工作中的经验,从服务器、Java应用、数据库、Redis、网络和业务六个层面分享线上故障排查的思路和技巧。较长,同学们可收藏后再看。
文末福利:轻量应用服务器优惠,新用户专享。
java.io.IOException: 磁盘空间不足
df -h
du -sh *
ls -lh
top
TopicNewController.getTopicSoftList() error="Java heap space
From class java.lang.OutOfMemoryError"appstore_apitomcat
/data/program/jdk/bin/jmap -dump:live,format=b,file=/home/www/jmaplogs/jmap-8001-2.bin 18760
ps -ef|grep store.cn.xml|grep -v grep|awk '{print $2}'|xargs /data/program/jdk-1.8.0_11/bin/jmap -dump:live,format=b,file=api.bin
.bin.tgz---.bin.tar--.bin
java.lang.Object[810325] @ 0xb0e971e0
虚拟机栈(栈桢中的本地变量表)中的引用的对象,就是平时所指的java对象,存放在堆中。
方法区中的类静态属性引用的对象,一般指被static修饰引用的对象,加载类的时候就加载到内存中。
方法区中的常量引用的对象。
本地方法栈中JNI(native方法)引用的对象。
(3)GC算法
串行只使用单条GC线程进行处理,而并行则使用多条。
多核情况下,并行一般更有执行效率,但是单核情况下,并行未必比串行更有效率。
STW会暂停所有应用线程的执行,等待GC线程完成后再继续执行应用线程,从而会导致短时间内应用无响应。
Concurrent会导致GC线程和应用线程并发执行,因此应用线程和GC线程互相抢用CPU,从而会导致出现浮动垃圾,同时GC时间不可控。
新生代算法都是基于Coping的,速度快。
Parallel Scavenge:吞吐量优先。
吞吐量=运行用户代码时间 /(运行用户代码时间 + 垃圾收集时间)
# 内存OOM时,自动生成dump文件
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/
2020-09-23T01:45:05.487+0800: 126221.918: [GC (Allocation Failure) 2020-09-23T01:45:05.487+0800: 126221.918: [ParNew: 1750755K->2896K(1922432K), 0.0409026 secs] 1867906K->120367K(4019584K), 0.0412358 secs] [Times: user=0.13 sys=0.01, real=0.04 secs]
2020-10-27T20:27:57.733+0800: 639877.297: [Full GC (Heap Inspection Initiated GC) 2020-10-27T20:27:57.733+0800: 639877.297: [CMS: 165992K->120406K(524288K), 0.7776748 secs] 329034K->120406K(1004928K), [Metaspace: 178787K->178787K(1216512K)], 0.7787158 secs] [Times: user=0.71 sys=0.00, real=0.78 secs]
首先利用 printf "%x \n" 将tid换为十六进制:xid。
再利用 jstack | grep nid=0x -A 10 查询线程信息(若进程无响应,则使用 jstack -f ),信息如下:
Deadlock found when trying to get lock; try restarting transaction ;
(rollbackFor = Exception.class)
void saveOrUpdate(MeetingInfo info) {
// insert ignore into table values (...)
int result = mapper.insertIgnore(info);
if (result>0) {
return;
}
// update table set xx=xx where id = xx
mapper.update(info);
}
SQL不走索引或扫描行数过多等致使执行时长过长。
SQL没问题,只是因为事务并发导致等待锁,致使执行时长过长。
-- 当前运行的所有事务
select * from information_schema.innodb_trx;
-- 当前出现的锁
SELECT * FROM information_schema.INNODB_LOCKS;
-- 锁等待的对应关系
select * from information_schema.INNODB_LOCK_WAITS;
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`salary` int(10) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `idx_name` (`name`(191)) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;
kill 105853
通过set global max_connections=XXX增大最大连接数。
先利用show processlist获取连接信息,然后利用kill杀死过多的连。
排序数据库连接的数目
mysql -h127.0.0.0.1 -uabc_test -pXXXXX -P3306 -A -e 'show processlist'| awk '{print $4}'|sort|uniq -c|sort -rn|head -10
叶子节点data域保存了完整的数据的地址。
主键与数据全部存储在一颗树上。
Root节点常驻内存。
每个非叶子节点一个innodb_page_size大小,加速磁盘IO。
磁盘的I/O要比内存慢几百倍,而磁盘慢的原因在于机械设备寻找磁道慢,因此采用磁盘预读,每次读取一个磁盘页(page:计算机管理存储器的逻辑块-通常为4k)的整倍数。
如果没有主键,MySQL默认生成隐含字段作为主键,这个字段长度为6个字节,类型为长整形。
辅助索引结构与主索引相同,但叶子节点data域保存的是主键指针。
InnoDB以表空间Tablespace(idb文件)结构进行组织,每个Tablespace 包含多个Segment段。
每个段(分为2种段:叶子节点Segment&非叶子节点Segment),一个Segment段包含多个Extent。
一个Extent占用1M空间包含64个Page(每个Page 16k),InnoDB B-Tree 一个逻辑节点就分配一个物理Page,一个节点一次IO操作。
一个Page里包含很多有序数据Row行数据,Row行数据中包含Filed属性数据等信息。
select * from table where id = 1
select * from table where name = 'a'
show variables like 'tx_isolation';
Repeatable read不存在幻读的问题,RR隔离级别保证对读取到的记录加锁 (记录锁),同时保证对读取的范围加锁,新的满足查询条件的记录不能够插入 (间隙锁),不存在幻读现象。
在MYSQL的事务引擎中,INNODB是使用范围最广的。它默认的事务隔离级别是REPEATABLE READ(可重复读),在标准的事务隔离级别定义下,REPEATABLE READ是不能防止幻读产生的。INNODB使用了next-key locks实现了防止幻读的发生。
在默认情况下,mysql的事务隔离级别是可重复读,并且innodb_locks_unsafe_for_binlog参数为OFF,这时默认采用next-key locks。所谓Next-Key Locks,就是Record lock和gap lock的结合,即除了锁住记录本身,还要再锁住索引之间的间隙。可以设置为ON,则RR隔离级别时会出现幻读。
select * from table where ?;
select * from table where ? lock in share mode; 加S锁 (共享锁)
-- 下面的都是X锁 (排它锁)
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
-- READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ/SERIALIZABLE
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`salary` int(11) DEFAULT NULL,
KEY `IDX_ID` (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of employee
-- ----------------------------
INSERT INTO `employee` VALUES ('10', '1s', '10');
INSERT INTO `employee` VALUES ('20', '2s', '20');
INSERT INTO `employee` VALUES ('30', '3s', '30');
DROP TABLE IF EXISTS `employee`;
CREATE TABLE `employee` (
`id` int(11) NOT NULL,
`name` varchar(50) NOT NULL,
`salary` int(11) DEFAULT NULL,
KEY `IDX_ID` (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of employee
-- ----------------------------
INSERT INTO `employee` VALUES ('10', '1s', '10');
INSERT INTO `employee` VALUES ('20', '2s', '20');
INSERT INTO `employee` VALUES ('30', '3s', '30');
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp` (
`id` int(11) NOT NULL,
`salary` int(11) DEFAULT NULL,
KEY `IDX_ID` (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES ('10', '10');
INSERT INTO `emp` VALUES ('20', '20');
INSERT INTO `emp` VALUES ('30', '30');
表锁的优势:开销小;加锁快;无死锁。
表锁的劣势:锁粒度大,发生锁冲突的概率高,并发处理能力低。
加锁的方式:自动加锁。查询操作(SELECT),会自动给涉及的所有表加读锁,更新操作(UPDATE、DELETE、INSERT),会自动给涉及的表加写锁。也可以显示加锁。
共享读锁:lock table tableName read
独占写锁:lock table tableName write
批量解锁:unlock tables
step1:判断表是否已被其他事务用表锁锁表
step2:判断表中的每一行是否已被行锁锁住。
step1:不变
step2:发现表上有意向共享锁,说明表中有些行被共享行锁锁住了,因此,事务B申请表的写锁会被阻塞。
-- select操作均不加锁,采用的是快照读,因此在下面的讨论中就忽略了
SQL1:select * from t1 where id = 10;
SQL2:delete from t1 where id = 10;
Repeatable Read隔离级别下,id列上有一个非唯一索引,对应SQL:delete from t1 where id = 10; 首先,通过id索引定位到第一条满足查询条件的记录,加记录上的X锁,加GAP上的GAP锁,然后加主键聚簇索引上的记录X锁,然后返回;然后读取下一条,重复进行。直至进行到第一条不满足条件的记录[11,f],此时,不需要加记录X锁,但是仍旧需要加GAP锁,最后返回结束。
什么时候会取得gap lock或nextkey lock 这和隔离级别有关,只在REPEATABLE READ或以上的隔离级别下的特定操作才会取得gap lock或nextkey lock。
# status代表当前系统的运行状态,只能查看,不能修改
show status like '%abc%';
show variables like '%abc%';
performance_schema.global_variables
performance_schema.session_variables
performance_schema.variables_by_thread
performance_schema.global_status
performance_schema.session_status
performance_schema.status_by_thread
performance_schema.status_by_account
performance_schema.status_by_host
performance_schema.status_by_user
INFORMATION_SCHEMA.GLOBAL_VARIABLES
INFORMATION_SCHEMA.SESSION_VARIABLES
INFORMATION_SCHEMA.GLOBAL_STATUS
INFORMATION_SCHEMA.SESSION_STATUS
# 查询慢SQL查询是否开启
show variables like 'slow_query_log';
# 查询慢SQL的时间
show variables like 'long_query_time';
# 查看慢SQL存放路径,一般:/home/mysql/data3016/mysql/slow_query.log
show variables like 'slow_query_log_file';
# 查看数据库的事务隔离级别,RDS:READ-COMMITTED Mysql:Repeatable read
show variables like 'tx_isolation';
# innodb数据页大小 16384
show variables like 'innodb_page_size';
show status like 'innodb_row_%';
# 查看慢SQL
SHOW SLOW limit 10;
show full slow limit 10;
# 查看autocommit配置
select @@autocommit;
# 同上
show variables like 'autocommit';
#设置SQL自动提交模式 1:默认,自动提交 0:需要手动触发commit,否则不会生效
set autocommit=1;
# 查看默认的搜索引擎
show variables like '%storage_engine%';
# 设置事务隔离级别
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
nb_soft_nature:小表
nb_soft:大表
package_name:都是索引
OOM command not allowed when used memory
maxmemory xxxxxx
config set maxmemory xxxxx
maxmemory-policy allkeys-lru
/data/program/dbatools-master/redisTools/redis-cli-new -h <ip> -p <port> --bigkeys --bigkey-numb 3
Sampled 122114 keys in the keyspace!
Total key length in bytes is 3923725 (avg len 32.13)
Biggest string Key Top 1 found 'xx1' has 36316 bytes
Biggest string Key Top 2 found 'xx2' has 1191 bytes
Biggest string Key Top 3 found 'xx3' has 234 bytes
Biggest list Key Top 1 found 'x4' has 204480 items
Biggest list Key Top 2 found 'x5' has 119999 items
Biggest list Key Top 3 found 'x6' has 60000 items
Biggest set Key Top 1 found 'x7' has 14205 members
Biggest set Key Top 2 found 'x8' has 292 members
Biggest set Key Top 3 found 'x,7' has 21 members
Biggest hash Key Top 1 found 'x' has 302939 fields
Biggest hash Key Top 2 found 'xc' has 92029 fields
Biggest hash Key Top 3 found 'xd' has 39634 fields
/usr/local/redis-3.0.5/src/redis-cli -c -h <ip> -p <port> --bigkeys
rdb -c memory dump.rdb -t list -f dump-formal-list.csv
redisTools]# redis-memory-for-key -s <ip> -p <port> x
Key x
Bytes 4274388.0
Type hash
Encoding hashtable
Number of Elements 39634
Length of Largest Element 29
debug object key
# 执行时间大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的查询进行记录。
slowlog-log-lower-than 1000
# 最多能保存多少条日志
slowlog-max-len 200
# 配置查询时间超过1毫秒的, 第一个参数单位是微秒
config set slowlog-log-lower-than 1000
# 保存200条慢查记录
config set slowlog-max-len 200
slowlog get
maxclients 10000
config set maxclients xxx
~]$ /data/program/redis-3.0.3/bin/redis-cli -c -h <ip> -p <port>
ip:port> cluster nodes
9f194f671cee4a76ce3b7ff14d3bda190e0695d5 m1 master - 0 1550322872543 65 connected 10923-16383
a38c6f957f2706f269cf5d9b628586a9372265e9 s1 slave 9f194f671cee4a76ce3b7ff14d3bda190e0695d5 0 1550322872943 65 connected
77ce43ec23f25f77ec68fe71ae3cb799e7300c6d s2 slave 03d72a3a5050c85e280e0bbeb687056b84f10077 0 1550322873543 63 connected
03d72a3a5050c85e280e0bbeb687056b84f10077 m2 master - 0 1550322873343 63 connected 5461-10922
5799070c6a63314296f3661b315b95c6328779f7 :0 slave,fail,noaddr 6147bf416ef216b6a1ef2f100d15de4f439b7352 1550320811474 1550320808793 49 disconnected
6147bf416ef216b6a1ef2f100d15de4f439b7352 m3 myself,master - 0 0 49 connected 0-5460
ip:port> cluster forget 61c70a61ad91bbac231e33352f5bdb9eb0be6289
CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点
[rgp@iZ23rjcqbczZ ~]$ /data/program/redis-3.0.3/bin/redis-trib.rb del-node m3 b643d7baa69922b3fdbd1e25ccbe6ed73587b948
> Removing node b643d7baa69922b3fdbd1e25ccbe6ed73587b948 from cluster m3
> Sending CLUSTER FORGET messages to the cluster...
> SHUTDOWN the node.
[ERR] Node s3 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.
/data/program/redis-3.0.3/bin/redis-server /data/program/redis-3.0.3/etc/7001/redis.conf &
rgp]# /data/program/redis-3.0.3/bin/redis-trib.rb add-node --slave --master-id 6147bf416ef216b6a1ef2f100d15de4f439b7352 s3 m3
Adding node s3 to cluster m3
Performing Cluster Check (using node m3)
M: 6147bf416ef216b6a1ef2f100d15de4f439b7352 m3
slots:0-5460 (5461 slots) master
0 additional replica(s)
M: 9f194f671cee4a76ce3b7ff14d3bda190e0695d5 m1
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: a38c6f957f2706f269cf5d9b628586a9372265e9 s1
slots: (0 slots) slave
replicates 9f194f671cee4a76ce3b7ff14d3bda190e0695d5
S: 77ce43ec23f25f77ec68fe71ae3cb799e7300c6d s2
slots: (0 slots) slave
replicates 03d72a3a5050c85e280e0bbeb687056b84f10077
M: 03d72a3a5050c85e280e0bbeb687056b84f10077 m2
slots:5461-10922 (5462 slots) master
1 additional replica(s)
All nodes agree about slots configuration.
Check for open slots...
Check slots coverage...
All 16384 slots covered.
Send CLUSTER MEET to node s3 to make it join the cluster.
Waiting for the cluster to join..
Configure node as replica of m3.
New node added correctly.
s3:本次待添加的从节点ip:port
m3:主节点的ip:port
6147bf416ef216b6a1ef2f100d15de4f439b7352:主节点编号
netstat -n|grep SYN_RECV
netstat -anoe|grep 8000|wc -l 查看8000
netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'
netstat -n|grep TIME_WAIT|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -10
所谓"已失效的连接请求报文段"是这样产生的。正常来说,客户端发出连接请求,但因为连接请求报文丢失而未收到确认。于是客户端再次发出一次连接请求,后来收到了确认,建立了连接。数据传输完毕后,释放了连接,客户端一共发送了两个连接请求报文段,其中第一个丢失,第二个到达了服务端,没有"已失效的连接请求报文段"。
netstat -nap | grep SYN_RECV
<property name="METRICS_LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS}|${APP_NAME}|%X{className}|%X{methodName}|%X{responseStatus}|%X{timeConsume}|%X{traceId}|%X{errorCode}|%msg%n"/>
<property name="ERROR_LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{traceId}|${APP_NAME}|%serverIp|%X{tenantId}|%X{accountId}|%thread|%logger{30}|%msg%n"/>
<!--日志格式 时间|级别|链路id|应用名|服务器ip|租户id|用户id|线程名称|logger名称|业务消息 -->
<property name="BIZ_LOG_PATTERN"
value="%d{yyyy-MM-dd HH:mm:ss.SSS}|%-5level|%X{traceId}|${APP_NAME}|%serverIp|%X{tenantId}|%X{accountId}|%thread|%logger{30}|%msg%n"/>
cat error.log|grep -n " java.lang.reflect.InvocationTargetException"
cat biz.log |grep -n '489d71fe-67db-4f59-a916-33f25d35cab8'
欢迎各路技术同路人加入乌鸫科技,我们是阿里巴巴全资子公司,为政府、企业提供全方位数字化服务和解决方案,打通政府、企业与民众的连接,助力政府的治理现代化,加速企业的数字化转型,团队招聘高级研发工程师/技术专家(Java),base杭州,内推直达邮箱 hxf240223@alibaba-inc.com、longhui.clh@alibaba-inc.com,快速响应你的面试安排。
岗位要求:Java基础扎实,对JVM原理有一定的了解;对于用过的开源框架,了解到它的原理和机制;熟悉分布式系统的设计和应用,有高并发应用开发经验;较强的工作责任心和良好的沟通协调能力,能在压力下独立解决问题。
阿里云开发者成长计划面向全年龄段开发者,依托免费资源、免费体验、免费学习、免费实践 4 大场景,全面助力开发者轻松掌握云上技能。新用户专享轻量应用服务器,内置WordPress等8种主流环境,5M峰值带宽,40GBSSD云盘,1000G流量包,轻松满足学习、搭建应用等场景!
识别下方二维码,或点击 “阅读原文” ,快去优惠购买吧~