九色国产,午夜在线视频,新黄色网址,九九色综合,天天做夜夜做久久做狠狠,天天躁夜夜躁狠狠躁2021a,久久不卡一区二区三区

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
線上故障如何快速排查?來看這套技巧大全

文末福利:輕量應(yīng)用服務(wù)器優(yōu)惠,新用戶專享


前言

線上定位問題時(shí),主要靠監(jiān)控和日志。一旦超出監(jiān)控的范圍,則排查思路很重要,按照流程化的思路來定位問題,能夠讓我們?cè)诙ㄎ粏栴}時(shí)從容、淡定,快速的定位到線上的問題。

線上問題定位思維導(dǎo)圖

一  服務(wù)器層面

1.1  磁盤

1.1.1  問題現(xiàn)象

當(dāng)磁盤容量不足的時(shí)候,應(yīng)用時(shí)常會(huì)拋出如下的異常信息:

java.io.IOException: 磁盤空間不足

或是類似如下告警信息:


1.1.2  排查思路

1.1.2.1  利用 df 查詢磁盤狀態(tài)

利用以下指令獲取磁盤狀態(tài):

df -h

結(jié)果是:


可知 / 路徑下占用量最大。

1.1.2.2  利用 du 查看文件夾大小

利用以下指令獲取目錄下文件夾大小:

du -sh *

結(jié)果是:


可知root文件夾占用空間最大,然后層層遞推找到對(duì)應(yīng)的最大的一個(gè)或數(shù)個(gè)文件夾。

1.1.2.3  利用 ls 查看文件大小

利用以下指令獲取目錄下文件夾大?。?/span>

ls -lh

結(jié)果是:


可以找到最大的文件是日志文件,然后使用rm指令進(jìn)行移除以釋放磁盤。

1.1.3  相關(guān)命令

1.1.3.1  df

主要是用于顯示目前在 Linux 系統(tǒng)上的文件系統(tǒng)磁盤使用情況統(tǒng)計(jì)。

(1)常用參數(shù)

啟動(dòng)參數(shù):


(2)結(jié)果參數(shù)



1.1.3.2  du

主要是為了顯示目錄或文件的大小。

(1)常用參數(shù)

啟動(dòng)參數(shù):


(2)結(jié)果參數(shù)


1.1.3.3  ls

主要是用于顯示指定工作目錄下的內(nèi)容的信息。

(1)常用參數(shù)

啟動(dòng)參數(shù):


(2)結(jié)果參數(shù)


1.2  CPU過高

1.2.1  問題現(xiàn)象

當(dāng)CPU過高的時(shí)候,接口性能會(huì)快速下降,同時(shí)監(jiān)控也會(huì)開始報(bào)警。

1.2.2  排查思路

1.2.2.1  利用 top 查詢CPU使用率最高的進(jìn)程

利用以下指令獲取系統(tǒng)CPU使用率信息:

top

結(jié)果是:


從而可以得知pid為14201的進(jìn)程使用CPU最高。

1.2.3  相關(guān)命令

1.2.3.1  top

(1)常用參數(shù)

啟動(dòng)參數(shù):


top進(jìn)程內(nèi)指令參數(shù):


(2)結(jié)果參數(shù)



二  應(yīng)用層面

2.1  Tomcat假死案例分析

2.1.1  發(fā)現(xiàn)問題

監(jiān)控平臺(tái)發(fā)現(xiàn)某個(gè)Tomcat節(jié)點(diǎn)已經(jīng)無法采集到數(shù)據(jù),連上服務(wù)器查看服務(wù)器進(jìn)程還在,netstat -anop|grep 8001端口也有監(jiān)聽,查看日志打印時(shí)斷時(shí)續(xù)。


2.2.2  查詢?nèi)罩?/span>

查看NG日志,發(fā)現(xiàn)有數(shù)據(jù)進(jìn)入到當(dāng)前服務(wù)器(有8001和8002兩個(gè)Tomcat),NG顯示8002節(jié)點(diǎn)訪問正常,8001節(jié)點(diǎn)有404錯(cuò)誤打印,說明Tomcat已經(jīng)處于假死狀態(tài),這個(gè)Tomcat已經(jīng)不能正常工作了。

過濾Tomcat節(jié)點(diǎn)的日志,發(fā)現(xiàn)有OOM的異常,但是重啟后,有時(shí)候Tomcat掛掉后,又不會(huì)打印如下OOM的異常:

TopicNewController.getTopicSoftList() error='Java heap space From class java.lang.OutOfMemoryError'appstore_apitomcat

2.2.3  獲取內(nèi)存快照

在一次OOM發(fā)生后立刻抓取內(nèi)存快照,需要執(zhí)行命令的用戶與JAVA進(jìn)程啟動(dòng)用戶是同一個(gè),否則會(huì)有異常:

/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

內(nèi)存dump文件比較大,有1.4G,先壓縮,然后拉取到本地用7ZIP解壓。

linux壓縮dump為.tgz。

在windows下用7zip需要經(jīng)過2步解壓:

.bin.tgz---.bin.tar--.bin

2.2.4  分析內(nèi)存快照文件

使用Memory Analyzer解析dump文件,發(fā)現(xiàn)有很明顯的內(nèi)存泄漏提示。


點(diǎn)擊查看詳情,發(fā)現(xiàn)定位到了代碼的具體某行,一目了然:


查看shallow heap與retained heap能發(fā)現(xiàn)生成了大量的Object(810325個(gè)對(duì)象),后面分析代碼發(fā)現(xiàn)是上報(bào)softItem對(duì)象超過300多萬個(gè)對(duì)象,在循環(huán)的時(shí)候,所有的數(shù)據(jù)全部保存在某個(gè)方法中無法釋放,導(dǎo)致內(nèi)存堆積到1.5G,從而超過了JVM分配的最大數(shù),從而出現(xiàn)OOM。


java.lang.Object[810325] @ 0xb0e971e0


2.2.5  相關(guān)知識(shí)

2.2.5.1  JVM內(nèi)存


2.2.5.2  內(nèi)存分配的流程


如果通過逃逸分析,則會(huì)先在TLAB分配,如果不滿足條件才在Eden上分配。

2.2.4.3  GC


(1)GC觸發(fā)的場(chǎng)景


(2)GC Roots

GC Roots有4種對(duì)象:

  • 虛擬機(jī)棧(棧楨中的本地變量表)中的引用的對(duì)象,就是平時(shí)所指的java對(duì)象,存放在堆中。


  • 方法區(qū)中的類靜態(tài)屬性引用的對(duì)象,一般指被static修飾引用的對(duì)象,加載類的時(shí)候就加載到內(nèi)存中。


  • 方法區(qū)中的常量引用的對(duì)象。


  • 本地方法棧中JNI(native方法)引用的對(duì)象。

(3)GC算法 


  • 串行只使用單條GC線程進(jìn)行處理,而并行則使用多條。


  • 多核情況下,并行一般更有執(zhí)行效率,但是單核情況下,并行未必比串行更有效率。



  • STW會(huì)暫停所有應(yīng)用線程的執(zhí)行,等待GC線程完成后再繼續(xù)執(zhí)行應(yīng)用線程,從而會(huì)導(dǎo)致短時(shí)間內(nèi)應(yīng)用無響應(yīng)。


  • Concurrent會(huì)導(dǎo)致GC線程和應(yīng)用線程并發(fā)執(zhí)行,因此應(yīng)用線程和GC線程互相搶用CPU,從而會(huì)導(dǎo)致出現(xiàn)浮動(dòng)垃圾,同時(shí)GC時(shí)間不可控。


(4)新生代使用的GC算法


  • 新生代算法都是基于Coping的,速度快。


  • Parallel Scavenge:吞吐量?jī)?yōu)先。

  • 吞吐量=運(yùn)行用戶代碼時(shí)間 /(運(yùn)行用戶代碼時(shí)間 + 垃圾收集時(shí)間)


(5)老年代使用的GC算法


Parallel Compacting


Concurrent Mark-Sweep(CMS)

(6)垃圾收集器總結(jié)


(7)實(shí)際場(chǎng)景中算法使用的組合


(8)GC日志格式

(a)監(jiān)控內(nèi)存的OOM場(chǎng)景

不要在線上使用jmap手動(dòng)抓取內(nèi)存快照,其一系統(tǒng)OOM時(shí)手工觸發(fā)已經(jīng)來不及,另外在生成dump文件時(shí)會(huì)占用系統(tǒng)內(nèi)存資源,導(dǎo)致系統(tǒng)崩潰。只需要在JVM啟動(dòng)參數(shù)中提取設(shè)置如下參數(shù),一旦OOM觸發(fā)會(huì)自動(dòng)生成對(duì)應(yīng)的文件,用MAT分析即可。

# 內(nèi)存OOM時(shí),自動(dòng)生成dump文件 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/logs/

如果Young GC比較頻繁,5S內(nèi)有打印一條,或者有Old GC的打印,代表內(nèi)存設(shè)置過小或者有內(nèi)存泄漏,此時(shí)需要抓取內(nèi)存快照進(jìn)行分享。

(b)Young Gc日志

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]


(c)Old GC日志

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] 


2.2  應(yīng)用CPU過高

2.2.1  發(fā)現(xiàn)問題

一般情況下會(huì)有監(jiān)控告警進(jìn)行提示:


2.2.2  查找問題進(jìn)程

利用top查到占用cpu最高的進(jìn)程pid為14,結(jié)果圖如下:


2.2.3  查找問題線程

利用 top -H -p  查看進(jìn)程內(nèi)占用cpu最高線程,從下圖可知,問題線程主要是activeCpu Thread,其pid為417。


2.2.4  查詢線程詳細(xì)信息

  • 首先利用 printf '%x \n' 將tid換為十六進(jìn)制:xid。


  • 再利用 jstack | grep nid=0x -A 10 查詢線程信息(若進(jìn)程無響應(yīng),則使用 jstack -f ),信息如下:



2.2.5  分析代碼

由上一步可知該問題是由 CpuThread.java 類引發(fā)的,故查詢項(xiàng)目代碼,獲得如下信息:


2.2.6  獲得結(jié)論

根據(jù)代碼和日志分析,可知是由于限制值max太大,致使線程長(zhǎng)時(shí)間循環(huán)執(zhí)行,從而導(dǎo)致問題出現(xiàn)。

三  Mysql

3.1  死鎖

3.1.1  問題出現(xiàn)

最近線上隨著流量變大,突然開始報(bào)如下異常,即發(fā)生了死鎖問題:

Deadlock found when trying to get lock; try restarting transaction ;

3.1.2  問題分析

3.1.2.1  查詢事務(wù)隔離級(jí)別

利用 select @@tx_isolation 命令獲取到數(shù)據(jù)庫隔離級(jí)別信息:


3.1.2.2  查詢數(shù)據(jù)庫死鎖日志

利用 show engine innodb status 命令獲取到如下死鎖信息:



由上可知,是由于兩個(gè)事物對(duì)這條記錄同時(shí)持有S鎖(共享鎖)的情況下,再次嘗試獲取該條記錄的X鎖(排它鎖),從而導(dǎo)致互相等待引發(fā)死鎖。

3.1.2.3  分析代碼

根據(jù)死鎖日志的SQL語句,定位獲取到如下偽代碼邏輯:

@Transactional(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);}

3.1.2.4  獲得結(jié)論

分析獲得產(chǎn)生問題的加鎖時(shí)序如下,然后修改代碼實(shí)現(xiàn)以解決該問題。


3.2  慢SQL

3.1.1  問題出現(xiàn)

應(yīng)用TPS下降,并出現(xiàn)SQL執(zhí)行超時(shí)異?;蛘叱霈F(xiàn)了類似如下的告警信息,則常常意味著出現(xiàn)了慢SQL。


3.1.2  問題分析

分析執(zhí)行計(jì)劃:利用explain指令獲得該SQL語句的執(zhí)行計(jì)劃,根據(jù)該執(zhí)行計(jì)劃,可能有兩種場(chǎng)景。

  • SQL不走索引或掃描行數(shù)過多等致使執(zhí)行時(shí)長(zhǎng)過長(zhǎng)。


  • SQL沒問題,只是因?yàn)槭聞?wù)并發(fā)導(dǎo)致等待鎖,致使執(zhí)行時(shí)長(zhǎng)過長(zhǎng)。


3.1.3 場(chǎng)景一 

3.1.3.1 優(yōu)化SQL

通過增加索引,調(diào)整SQL語句的方式優(yōu)化執(zhí)行時(shí)長(zhǎng), 例如下的執(zhí)行計(jì)劃:


該SQL的執(zhí)行計(jì)劃的type為ALL,同時(shí)根據(jù)以下type語義,可知無索引的全表查詢,故可為其檢索列增加索引進(jìn)而解決。


3.1.4  場(chǎng)景二

3.1.4.1  查詢當(dāng)前事務(wù)情況

可以通過查看如下3張表做相應(yīng)的處理:

-- 當(dāng)前運(yùn)行的所有事務(wù)select * from information_schema.innodb_trx;-- 當(dāng)前出現(xiàn)的鎖SELECT * FROM information_schema.INNODB_LOCKS;-- 鎖等待的對(duì)應(yīng)關(guān)系select * from information_schema.INNODB_LOCK_WAITS;

(1)查看當(dāng)前的事務(wù)有哪些:


(2)查看事務(wù)鎖類型索引的詳細(xì)信息:


lock_table字段能看到被鎖的索引的表名,lock_mode可以看到鎖類型是X鎖,lock_type可以看到是行鎖record。

3.1.4.2  分析

根據(jù)事務(wù)情況,得到表信息,和相關(guān)的事務(wù)時(shí)序信息:

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;

A事物鎖住一條記錄,不提交,B事物需要更新此條記錄,此時(shí)會(huì)阻塞,如下圖是執(zhí)行順序:


3.1.4.3  解決方案

(1)修改方案

由前一步的結(jié)果,分析事務(wù)間加鎖時(shí)序,例如可以通過tx_query字段得知被阻塞的事務(wù)SQL,trx_state得知事務(wù)狀態(tài)等,找到對(duì)應(yīng)代碼邏輯,進(jìn)行優(yōu)化修改。

(2)臨時(shí)修改方案

trx_mysql_thread_id是對(duì)應(yīng)的事務(wù)sessionId,可以通過以下命令殺死長(zhǎng)時(shí)間執(zhí)行的事務(wù),從而避免阻塞其他事務(wù)執(zhí)行。

kill 105853

3.3  連接數(shù)過多

3.3.1  問題出現(xiàn)

常出現(xiàn)too many connections異常,數(shù)據(jù)庫連接到達(dá)最大連接數(shù)。

3.3.2  解決方案

解決方案:

  • 通過set global max_connections=XXX增大最大連接數(shù)。


  • 先利用show processlist獲取連接信息,然后利用kill殺死過多的連。


常用腳本如下:

排序數(shù)據(jù)庫連接的數(shù)目 mysql -h127.0.0.0.1 -uabc_test -pXXXXX -P3306 -A -e 'show processlist'| awk '{print $4}'|sort|uniq -c|sort -rn|head -10

3.4  相關(guān)知識(shí)

3.4.1 索引 

3.4.1.1  MySql不同的存儲(chǔ)引擎

3.4.1.2  InnoDB B+Tree索引實(shí)現(xiàn)

主鍵索引(聚集索引):

  • 葉子節(jié)點(diǎn)data域保存了完整的數(shù)據(jù)的地址。


  • 主鍵與數(shù)據(jù)全部存儲(chǔ)在一顆樹上。


  • Root節(jié)點(diǎn)常駐內(nèi)存。


  • 每個(gè)非葉子節(jié)點(diǎn)一個(gè)innodb_page_size大小,加速磁盤IO。


  • 磁盤的I/O要比內(nèi)存慢幾百倍,而磁盤慢的原因在于機(jī)械設(shè)備尋找磁道慢,因此采用磁盤預(yù)讀,每次讀取一個(gè)磁盤頁(page:計(jì)算機(jī)管理存儲(chǔ)器的邏輯塊-通常為4k)的整倍數(shù)。


  • 如果沒有主鍵,MySQL默認(rèn)生成隱含字段作為主鍵,這個(gè)字段長(zhǎng)度為6個(gè)字節(jié),類型為長(zhǎng)整形。


  • 輔助索引結(jié)構(gòu)與主索引相同,但葉子節(jié)點(diǎn)data域保存的是主鍵指針。


  • InnoDB以表空間Tablespace(idb文件)結(jié)構(gòu)進(jìn)行組織,每個(gè)Tablespace 包含多個(gè)Segment段。


  • 每個(gè)段(分為2種段:葉子節(jié)點(diǎn)Segment&非葉子節(jié)點(diǎn)Segment),一個(gè)Segment段包含多個(gè)Extent。


  • 一個(gè)Extent占用1M空間包含64個(gè)Page(每個(gè)Page 16k),InnoDB B-Tree 一個(gè)邏輯節(jié)點(diǎn)就分配一個(gè)物理Page,一個(gè)節(jié)點(diǎn)一次IO操作。


  • 一個(gè)Page里包含很多有序數(shù)據(jù)Row行數(shù)據(jù),Row行數(shù)據(jù)中包含F(xiàn)iled屬性數(shù)據(jù)等信息。


InnoDB存儲(chǔ)引擎中頁的大小為16KB,一般表的主鍵類型為INT(占用4個(gè)字節(jié))或BIGINT(占用8個(gè)字節(jié)),指針類型也一般為4或8個(gè)字節(jié),也就是說一個(gè)頁(B+Tree中的一個(gè)節(jié)點(diǎn))中大概存儲(chǔ)16KB/(8B+8B)=1K個(gè)鍵值(因?yàn)槭枪乐担?/span>為方便計(jì)算,這里的K取值為[10]^3)。

也就是說一個(gè)深度為3的B+Tree索引可以維護(hù) 10^3 * 10^3 * 10^3 = 10億 條記錄。


每個(gè)索引的左指針都是比自己小的索引/節(jié)點(diǎn),右指針是大于等于自己的索引/節(jié)點(diǎn)。

3.4.2  B+ Tree索引檢索

3.4.2.1  主鍵索引檢索

select * from table where id = 1


3.4.2.2  輔助索引檢索

select * from table where name = 'a'


3.4.3  事物的隔離級(jí)別

3.4.3.1  如何查看數(shù)據(jù)庫的事務(wù)隔離級(jí)別

使用如下命令可以查看事務(wù)的隔離級(jí)別:

show variables like 'tx_isolation';

里云上的rds的隔離級(jí)別是read committed ,而不是原生mysql的“可重復(fù)讀(repeatable-read)。


  • Repeatable read不存在幻讀的問題,RR隔離級(jí)別保證對(duì)讀取到的記錄加鎖 (記錄鎖),同時(shí)保證對(duì)讀取的范圍加鎖,新的滿足查詢條件的記錄不能夠插入 (間隙鎖),不存在幻讀現(xiàn)象。


  • 在MYSQL的事務(wù)引擎中,INNODB是使用范圍最廣的。它默認(rèn)的事務(wù)隔離級(jí)別是REPEATABLE READ(可重復(fù)讀),在標(biāo)準(zhǔn)的事務(wù)隔離級(jí)別定義下,REPEATABLE READ是不能防止幻讀產(chǎn)生的。INNODB使用了next-key locks實(shí)現(xiàn)了防止幻讀的發(fā)生。


  • 在默認(rèn)情況下,mysql的事務(wù)隔離級(jí)別是可重復(fù)讀,并且innodb_locks_unsafe_for_binlog參數(shù)為OFF,這時(shí)默認(rèn)采用next-key locks。所謂Next-Key Locks,就是Record lock和gap lock的結(jié)合,即除了鎖住記錄本身,還要再鎖住索引之間的間隙??梢栽O(shè)置為ON,則RR隔離級(jí)別時(shí)會(huì)出現(xiàn)幻讀。


3.4.3.2  多版本并發(fā)控制MVCC

MySQL InnoDB存儲(chǔ)引擎,實(shí)現(xiàn)的是基于多版本的并發(fā)控制協(xié)議——MVCC (Multi-Version Concurrency Control) (注:與MVCC相對(duì)的,是基于鎖的并發(fā)控制,Lock-Based Concurrency Control)。

MVCC最大的好處,相信也是耳熟能詳:讀不加鎖,讀寫不沖突。在讀多寫少的OLTP應(yīng)用中,讀寫不沖突是非常重要的,極大的增加了系統(tǒng)的并發(fā)性能。

在MVCC并發(fā)控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當(dāng)前讀 (current read)。

快照讀:簡(jiǎn)單的select操作,屬于快照讀,不加鎖。(當(dāng)然,也有例外,下面會(huì)分析)。

 select * from table where ?;

當(dāng)前讀:特殊的讀操作,插入/更新/刪除操作,屬于當(dāng)前讀,需要加鎖。

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 ?;

3.4.4.3   場(chǎng)景模擬

修改事務(wù)隔離級(jí)別的語句:

SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;  -- READ UNCOMMITTED/READ COMMITTED/REPEATABLE READ/SERIALIZABLE

(1)臟讀場(chǎng)景模擬

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 BTREEENGINE=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');

臟讀場(chǎng)景模擬

(2)不可重復(fù)讀模擬

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');

不可重復(fù)讀的重點(diǎn)是修改: 同樣的條件, 你讀取過的數(shù)據(jù), 再次讀取出來發(fā)現(xiàn)值不一樣了。


(3)幻讀場(chǎng)景模擬

表結(jié)構(gòu)與數(shù)據(jù)如下:id不是主鍵,也不是唯一索引,只是一個(gè)普通索引,事務(wù)隔離級(jí)別設(shè)置的是RR,可以模擬到GAP鎖產(chǎn)生的場(chǎng)景。

DROP TABLE IF EXISTS `emp`;CREATE TABLE `emp` ( `id` int(11) NOT NULL, `salary` int(11) DEFAULT NULL, KEY `IDX_ID` (`id`) USING BTREEENGINE=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');

修改id=20的數(shù)據(jù)后,會(huì)在加多個(gè)鎖:20會(huì)被加X鎖,[10-20],[20-30]之間會(huì)被加GAP鎖。


幻讀的重點(diǎn)在于新增或者刪除 (數(shù)據(jù)條數(shù)變化)。同樣的條件, 第1次和第2次讀出來的記錄數(shù)不一樣。

在標(biāo)準(zhǔn)的事務(wù)隔離級(jí)別定義下,REPEATABLE READ是不能防止幻讀產(chǎn)生的。INNODB使用了2種技術(shù)手段(MVCC AND GAP LOCK)實(shí)現(xiàn)了防止幻讀的發(fā)生。

3.4.4  Innodb的多種鎖

3.4.4.1  鎖類型


  • 表鎖的優(yōu)勢(shì):開銷?。患渔i快;無死鎖。


  • 表鎖的劣勢(shì):鎖粒度大,發(fā)生鎖沖突的概率高,并發(fā)處理能力低。


  • 加鎖的方式:自動(dòng)加鎖。查詢操作(SELECT),會(huì)自動(dòng)給涉及的所有表加讀鎖,更新操作(UPDATE、DELETE、INSERT),會(huì)自動(dòng)給涉及的表加寫鎖。也可以顯示加鎖。


  • 共享讀鎖:lock table tableName read


  • 獨(dú)占寫鎖:lock table tableName write


  • 批量解鎖:unlock tables


3.4.4.2   行鎖


只在Repeatable read和Serializable兩種事務(wù)隔離級(jí)別下才會(huì)取得上面的鎖。

3.4.4.3  意向鎖

(1)場(chǎng)景

在mysql中有表鎖,LOCK TABLE my_tabl_name READ;  用讀鎖鎖表,會(huì)阻塞其他事務(wù)修改表數(shù)據(jù)。LOCK TABLE my_table_name WRITe; 用寫鎖鎖表,會(huì)阻塞其他事務(wù)讀和寫。

Innodb引擎又支持行鎖,行鎖分為共享鎖,一個(gè)事務(wù)對(duì)一行的共享只讀鎖。排它鎖,一個(gè)事務(wù)對(duì)一行的排他讀寫鎖。

這兩中類型的鎖共存的問題考慮這個(gè)例子:

事務(wù)A鎖住了表中的一行,讓這一行只能讀,不能寫。之后,事務(wù)B申請(qǐng)整個(gè)表的寫鎖。如果事務(wù)B申請(qǐng)成功,那么理論上它就能修改表中的任意一行,這與A持有的行鎖是沖突的。

數(shù)據(jù)庫需要避免這種沖突,就是說要讓B的申請(qǐng)被阻塞,直到A釋放了行鎖。

(2)問題

數(shù)據(jù)庫要怎么判斷這個(gè)沖突呢?

(3)答案

無意向鎖的情況下:

  • step1:判斷表是否已被其他事務(wù)用表鎖鎖表

  • step2:判斷表中的每一行是否已被行鎖鎖住。


有意向鎖的情況下:

  • step1:不變

  • step2:發(fā)現(xiàn)表上有意向共享鎖,說明表中有些行被共享行鎖鎖住了,因此,事務(wù)B申請(qǐng)表的寫鎖會(huì)被阻塞。


(4)總結(jié)

在無意向鎖的情況下,step2需要遍歷整個(gè)表,才能確認(rèn)是否能拿到表鎖。而在意向鎖存在的情況下,事務(wù)A必須先申請(qǐng)表的意向共享鎖,成功后再申請(qǐng)一行的行鎖,不需要再遍歷整個(gè)表,提升了效率。因此意向鎖主要是為了實(shí)現(xiàn)多粒度鎖機(jī)制(白話:為了表鎖和行鎖都能用)。

3.4.4.4   X/S鎖


3.4.4.5   一條SQL的加鎖分析

-- select操作均不加鎖,采用的是快照讀,因此在下面的討論中就忽略了SQL1:select * from t1 where id = 10;SQL2:delete from t1 where id = 10;

組合分為如下幾種場(chǎng)景:


(1)組合7的GAP鎖詳解讀

Insert操作,如insert [10,aa],首先會(huì)定位到[6,c]與[10,b]間,然后在插入前,會(huì)檢查這個(gè)GAP是否已經(jīng)被鎖上,如果被鎖上,則Insert不能插入記錄。因此,通過第一遍的當(dāng)前讀,不僅將滿足條件的記錄鎖上 (X鎖),與組合三類似。同時(shí)還是增加3把GAP鎖,將可能插入滿足條件記錄的3個(gè)GAP給鎖上,保證后續(xù)的Insert不能插入新的id=10的記錄,也就杜絕了同一事務(wù)的第二次當(dāng)前讀,出現(xiàn)幻象的情況。

既然防止幻讀,需要靠GAP鎖的保護(hù),為什么組合五、組合六,也是RR隔離級(jí)別,卻不需要加GAP鎖呢?

GAP鎖的目的,是為了防止同一事務(wù)的兩次當(dāng)前讀,出現(xiàn)幻讀的情況。而組合五,id是主鍵;組合六,id是unique鍵,都能夠保證唯一性。

一個(gè)等值查詢,最多只能返回一條記錄,而且新的相同取值的記錄,一定不會(huì)在新插入進(jìn)來,因此也就避免了GAP鎖的使用。

(2)結(jié)論

  • Repeatable Read隔離級(jí)別下,id列上有一個(gè)非唯一索引,對(duì)應(yīng)SQL:delete from t1 where id = 10; 首先,通過id索引定位到第一條滿足查詢條件的記錄,加記錄上的X鎖,加GAP上的GAP鎖,然后加主鍵聚簇索引上的記錄X鎖,然后返回;然后讀取下一條,重復(fù)進(jìn)行。直至進(jìn)行到第一條不滿足條件的記錄[11,f],此時(shí),不需要加記錄X鎖,但是仍舊需要加GAP鎖,最后返回結(jié)束。


  • 什么時(shí)候會(huì)取得gap lock或nextkey lock  這和隔離級(jí)別有關(guān),只在REPEATABLE READ或以上的隔離級(jí)別下的特定操作才會(huì)取得gap lock或nextkey lock。


3.4.5  線上問題處理

3.4.5.1  觀察問題的幾個(gè)常見庫表

首先可以通過下屬兩個(gè)命令來查看mysql的相應(yīng)的系統(tǒng)變量和狀態(tài)變量。

# status代表當(dāng)前系統(tǒng)的運(yùn)行狀態(tài),只能查看,不能修改show status like '%abc%';show variables like '%abc%';

MySQL 5.7.6開始后改成了從如下表獲取:

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

之前是從如下表獲?。?/span>

INFORMATION_SCHEMA.GLOBAL_VARIABLES INFORMATION_SCHEMA.SESSION_VARIABLES INFORMATION_SCHEMA.GLOBAL_STATUS INFORMATION_SCHEMA.SESSION_STATUS

比較常用的系統(tǒng)變量和狀態(tài)變量有:

# 查詢慢SQL查詢是否開啟show variables like 'slow_query_log';# 查詢慢SQL的時(shí)間show variables like 'long_query_time';# 查看慢SQL存放路徑,一般:/home/mysql/data3016/mysql/slow_query.logshow variables like 'slow_query_log_file';
# 查看數(shù)據(jù)庫的事務(wù)隔離級(jí)別,RDS:READ-COMMITTED Mysql:Repeatable readshow variables like 'tx_isolation'; # innodb數(shù)據(jù)頁大小 16384show variables like 'innodb_page_size'
show status  like 'innodb_row_%';
# 查看慢SQLSHOW SLOW limit 10;show full slow limit 10;
# 查看autocommit配置select @@autocommit; # 同上show variables like 'autocommit'; #設(shè)置SQL自動(dòng)提交模式 1:默認(rèn),自動(dòng)提交 0:需要手動(dòng)觸發(fā)commit,否則不會(huì)生效set autocommit=1;  # 查看默認(rèn)的搜索引擎show variables like '%storage_engine%'
# 設(shè)置事務(wù)隔離級(jí)別SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;

3.5  一些建議

3.5.1  小表驅(qū)動(dòng)大表

  • nb_soft_nature:小表

  • nb_soft:大表

  • package_name:都是索引


MySQL 表關(guān)聯(lián)的算法是Nest Loop Join(嵌套循環(huán)連接),是通過驅(qū)動(dòng)表的結(jié)果集作為循環(huán)基礎(chǔ)數(shù)據(jù),然后一條一條地通過該結(jié)果集中的數(shù)據(jù)作為過濾條件到下一個(gè)表中查詢數(shù)據(jù),然后合并結(jié)果。

(1)小表驅(qū)動(dòng)大表  


nb_soft_nature 中只有24條數(shù)據(jù),每條數(shù)據(jù)的package_name連接到nb_soft表中做查詢,由于package_name在nb_soft表中有索引,因此一共只需要24次掃描即可。

(2)大表驅(qū)動(dòng)小表  


同上,需要100多萬次掃描才能返回結(jié)果

3.5.2  使用自增長(zhǎng)主鍵

結(jié)合B+Tree的特點(diǎn),自增主鍵是連續(xù)的,在插入過程中盡量減少頁分裂,即使要進(jìn)行頁分裂,也只會(huì)分裂很少一部分。并且能減少數(shù)據(jù)的移動(dòng),每次插入都是插入到最后。總之就是減少分裂和移動(dòng)的頻率。

四  Redis 

4.1  問題處理思路


4.2  內(nèi)存告警

時(shí)常會(huì)出現(xiàn)下述異常提示信息:

OOM command not allowed when used memory

4.2.1  設(shè)置合理的內(nèi)存大小

設(shè)置maxmemory和相對(duì)應(yīng)的回收策略算法,設(shè)置最好為物理內(nèi)存的3/4,或者比例更小,因?yàn)閞edis復(fù)制數(shù)據(jù)等其他服務(wù)時(shí),也是需要緩存的。以防緩存數(shù)據(jù)過大致使redis崩潰,造成系統(tǒng)出錯(cuò)不可用。

(1)通過redis.conf 配置文件指定

maxmemory xxxxxx

(2)通過命令修改

config set maxmemory xxxxx

4.2.2  設(shè)置合理的內(nèi)存淘汰策略



(1)通過redis.conf 配置文件指定

maxmemory-policy allkeys-lru

4.2.3  查看大key

(1)有工具的情況下:

安裝工具dbatools redisTools,列出最大的前N個(gè)key

/data/program/dbatools-master/redisTools/redis-cli-new -h <ip> -p <port> --bigkeys --bigkey-numb 3

得到如下結(jié)果:

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 bytesBiggest string Key Top 2 found 'xx2' has 1191 bytesBiggest string Key Top 3 found 'xx3' has 234 bytesBiggest list Key Top 1 found 'x4' has 204480 itemsBiggest list Key Top 2 found 'x5' has 119999 itemsBiggest list Key Top 3 found 'x6' has 60000 itemsBiggest set Key Top 1 found 'x7' has 14205 membersBiggest set Key Top 2 found 'x8' has 292 membersBiggest set Key Top 3 found 'x,7' has 21 membersBiggest hash Key Top 1 found 'x' has 302939 fieldsBiggest hash Key Top 2 found 'xc' has 92029 fieldsBiggest 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文件中的全部key/某種類型的占用量:

rdb -c memory dump.rdb -t list -f dump-formal-list.csv

查看某個(gè)key的內(nèi)存占用量:

[root@iZbp16umm14vm5kssepfdpZ redisTools]# redis-memory-for-key -s <ip> -p <port> xKey xBytes 4274388.0Type hashEncoding hashtableNumber of Elements 39634Length of Largest Element 29

(2)無工具的情況下可利用以下指令評(píng)估key大?。?/span>

debug object key 

4.3  Redis的慢命令

4.3.1  設(shè)置Redis的慢命令的時(shí)間閾值(單位:微妙)

(1)通過redis.conf配置文件方式

# 執(zhí)行時(shí)間大于多少微秒(microsecond,1秒 = 1,000,000 微秒)的查詢進(jìn)行記錄。slowlog-log-lower-than 1000
# 最多能保存多少條日志slowlog-max-len 200

(2)通過命令方式

# 配置查詢時(shí)間超過1毫秒的, 第一個(gè)參數(shù)單位是微秒config set slowlog-log-lower-than 1000
# 保存200條慢查記錄config set slowlog-max-len 200

4.3.2  查看Redis的慢命令

slowlog get

4.4  連接過多

(1)通過redis.conf 配置文件指定最大連接數(shù)

maxclients 10000

(2)通過命令修改

config set maxclients xxx

4.5  線上Redis節(jié)點(diǎn)掛掉一個(gè)之后的處理流程

4.5.1  查看節(jié)點(diǎn)狀態(tài)

執(zhí)行 cluster nodes 后發(fā)現(xiàn)會(huì)有一個(gè)節(jié)點(diǎn)dead:

[rgp@iZ23rjcqbczZ ~]$ /data/program/redis-3.0.3/bin/redis-cli -c -h <ip> -p <port>ip:port> cluster nodes9f194f671cee4a76ce3b7ff14d3bda190e0695d5 m1 master - 0 1550322872543 65 connected 10923-16383a38c6f957f2706f269cf5d9b628586a9372265e9 s1 slave 9f194f671cee4a76ce3b7ff14d3bda190e0695d5 0 1550322872943 65 connected77ce43ec23f25f77ec68fe71ae3cb799e7300c6d s2 slave 03d72a3a5050c85e280e0bbeb687056b84f10077 0 1550322873543 63 connected03d72a3a5050c85e280e0bbeb687056b84f10077 m2 master - 0 1550322873343 63 connected 5461-109225799070c6a63314296f3661b315b95c6328779f7 :0 slave,fail,noaddr 6147bf416ef216b6a1ef2f100d15de4f439b7352 1550320811474 1550320808793 49 disconnected6147bf416ef216b6a1ef2f100d15de4f439b7352 m3 myself,master - 0 0 49 connected 0-5460

4.5.2  移除錯(cuò)誤節(jié)點(diǎn)

(1)一開始執(zhí)行如下的刪除操作失敗,需要針對(duì)于每一個(gè)節(jié)點(diǎn)都執(zhí)行 cluster forget:

ip:port> cluster forget 61c70a61ad91bbac231e33352f5bdb9eb0be6289CLUSTER FORGET <node_id> 從集群中移除 node_id 指定的節(jié)點(diǎn)

(2)刪除掛掉的節(jié)點(diǎn):

[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.

(3)清理掉節(jié)點(diǎn)配置目錄下的rdb aof nodes.conf 等文件,否則節(jié)點(diǎn)的啟動(dòng)會(huì)有如下異常:

[ERR] Node s3 is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0.

4.5.3  恢復(fù)節(jié)點(diǎn)

(1)后臺(tái)啟動(dòng)Redis某個(gè)節(jié)點(diǎn):

/data/program/redis-3.0.3/bin/redis-server /data/program/redis-3.0.3/etc/7001/redis.conf &

(2)將該節(jié)點(diǎn)添加進(jìn)集群:

[root@iZ23rjcqbczZ 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 9f194f671cee4a76ce3b7ff14d3bda190e0695d5S: 77ce43ec23f25f77ec68fe71ae3cb799e7300c6d s2 slots: (0 slots) slave replicates 03d72a3a5050c85e280e0bbeb687056b84f10077M: 03d72a3a5050c85e280e0bbeb687056b84f10077 m2 slots:5461-10922 (5462 slots) master 1 additional replica(s)[OK] All nodes agree about slots configuration.>>> Check for open slots...>>> Check slots coverage...[OK] 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.[OK] New node added correctly.

  • s3:本次待添加的從節(jié)點(diǎn)ip:port

  • m3:主節(jié)點(diǎn)的ip:port

  • 6147bf416ef216b6a1ef2f100d15de4f439b7352:主節(jié)點(diǎn)編號(hào)


五  網(wǎng)絡(luò)

5.1  排查流程

5.1.1  現(xiàn)象出現(xiàn)

在非壓測(cè)或者高峰期的情況下,突然出現(xiàn)大量的503等錯(cuò)誤碼,頁面無法打開。

5.1.2  查看是否遭受了DOS攻擊

當(dāng)Server上有大量半連接狀態(tài)且源IP地址是隨機(jī)的,則可以斷定遭到SYN攻擊了,使用如下命令可以讓之現(xiàn)行。

netstat -n|grep SYN_RECV

5.1.3  查看TCP連接狀態(tài)

首先利用以下查看tcp總連接數(shù),判斷連接數(shù)是否正常:

netstat -anoe|grep 8000|wc -l 查看8000

然后利用如下命令判斷各個(gè)狀態(tài)的連接數(shù)是否正常:

netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

根據(jù)上述信息,如果TIME_WAIT 狀態(tài)數(shù)量過多,可利用如下命令查看連接CLOSE_WAIT最多的IP地址,再結(jié)合業(yè)務(wù)分析問題:

netstat -n|grep TIME_WAIT|awk '{print $5}'|awk -F: '{print $1}'|sort|uniq -c|sort -nr|head -10

5.2  相關(guān)知識(shí)

5.2.1  TCP連接

TCP三次握手四次揮手


為什么在第3步中客戶端還要再進(jìn)行一次確認(rèn)呢?這主要是為了防止已經(jīng)失效的連接請(qǐng)求報(bào)文段突然又傳回到服務(wù)端而產(chǎn)生錯(cuò)誤的場(chǎng)景:

所謂'已失效的連接請(qǐng)求報(bào)文段'是這樣產(chǎn)生的。正常來說,客戶端發(fā)出連接請(qǐng)求,但因?yàn)檫B接請(qǐng)求報(bào)文丟失而未收到確認(rèn)。于是客戶端再次發(fā)出一次連接請(qǐng)求,后來收到了確認(rèn),建立了連接。數(shù)據(jù)傳輸完畢后,釋放了連接,客戶端一共發(fā)送了兩個(gè)連接請(qǐng)求報(bào)文段,其中第一個(gè)丟失,第二個(gè)到達(dá)了服務(wù)端,沒有'已失效的連接請(qǐng)求報(bào)文段'。


現(xiàn)在假定一種異常情況,即客戶端發(fā)出的第一個(gè)連接請(qǐng)求報(bào)文段并沒有丟失,只是在某些網(wǎng)絡(luò)節(jié)點(diǎn)長(zhǎng)時(shí)間滯留了,以至于延誤到連接釋放以后的某個(gè)時(shí)間點(diǎn)才到達(dá)服務(wù)端。本來這個(gè)連接請(qǐng)求已經(jīng)失效了,但是服務(wù)端收到此失效的連接請(qǐng)求報(bào)文段后,就誤認(rèn)為這是客戶端又發(fā)出了一次新的連接請(qǐng)求。于是服務(wù)端又向客戶端發(fā)出請(qǐng)求報(bào)文段,同意建立連接。假定不采用三次握手,那么只要服務(wù)端發(fā)出確認(rèn),連接就建立了。

由于現(xiàn)在客戶端并沒有發(fā)出連接建立的請(qǐng)求,因此不會(huì)理會(huì)服務(wù)端的確認(rèn),也不會(huì)向服務(wù)端發(fā)送數(shù)據(jù),但是服務(wù)端卻以為新的傳輸連接已經(jīng)建立了,并一直等待客戶端發(fā)來數(shù)據(jù),這樣服務(wù)端的許多資源就這樣白白浪費(fèi)了。

采用三次握手的辦法可以防止上述現(xiàn)象的發(fā)生。比如在上述的場(chǎng)景下,客戶端不向服務(wù)端的發(fā)出確認(rèn)請(qǐng)求,服務(wù)端由于收不到確認(rèn),就知道客戶端并沒有要求建立連接。

SYN攻擊時(shí)一種典型的DDOS攻擊,檢測(cè)SYN攻擊的方式非常簡(jiǎn)單,即當(dāng)Server上有大量半連接狀態(tài)且源IP地址是隨機(jī)的,則可以斷定遭到SYN攻擊了,使用如下命令可以讓之現(xiàn)行:

netstat -nap | grep SYN_RECV


5.2.2  一些常見問題

(1)為什么TCP連接的建立只需要三次握手而TCP連接的釋放需要四次握手呢?

因?yàn)榉?wù)端在LISTEN狀態(tài)下,收到建立請(qǐng)求的SYN報(bào)文后,把ACK和SYN放在一個(gè)報(bào)文里發(fā)送給客戶端。而連接關(guān)閉時(shí),當(dāng)收到對(duì)方的FIN報(bào)文時(shí),僅僅表示對(duì)方?jīng)]有需要發(fā)送的數(shù)據(jù)了,但是還能接收數(shù)據(jù),己方未必?cái)?shù)據(jù)已經(jīng)全部發(fā)送給對(duì)方了,所以己方可以立即關(guān)閉,也可以將應(yīng)該發(fā)送的數(shù)據(jù)全部發(fā)送完畢后再發(fā)送FIN報(bào)文給客戶端來表示同意現(xiàn)在關(guān)閉連接。

從這個(gè)角度而言,服務(wù)端的ACK和FIN一般都會(huì)分開發(fā)送。

(2)如果已經(jīng)建立了連接,但是客戶端突然出現(xiàn)故障了怎么辦?

TCP還設(shè)有一個(gè)保活計(jì)時(shí)器,顯然,客戶端如果出現(xiàn)故障,服務(wù)器不能一直等下去,白白浪費(fèi)資源。服務(wù)器每收到一次客戶端的請(qǐng)求后都會(huì)重新復(fù)位這個(gè)計(jì)時(shí)器,時(shí)間通常是設(shè)置為2小時(shí),若兩小時(shí)還沒有收到客戶端的任何數(shù)據(jù),服務(wù)器就會(huì)發(fā)送一個(gè)探測(cè)報(bào)文段,以后每隔75秒鐘發(fā)送一次。若一連發(fā)送10個(gè)探測(cè)報(bào)文仍然沒反應(yīng),服務(wù)器就認(rèn)為客戶端出了故障,接著就關(guān)閉連接。

(3)為什么TIME_WAIT狀態(tài)需要經(jīng)過2MSL(最大報(bào)文段生存時(shí)間)才能返回到CLOSE狀態(tài)?

雖然按道理,四個(gè)報(bào)文都發(fā)送完畢,我們可以直接進(jìn)入CLOSE狀態(tài)了,但是我們必須假象網(wǎng)絡(luò)是不可靠的,有可以最后一個(gè)ACK丟失。所以TIME_WAIT狀態(tài)就是用來重發(fā)可能丟失的ACK報(bào)文。

在Client發(fā)送出最后的ACK回復(fù),但該ACK可能丟失。Server如果沒有收到ACK,將不斷重復(fù)發(fā)送FIN片段。所以Client不能立即關(guān)閉,它必須確認(rèn)Server接收到了該ACK。Client會(huì)在發(fā)送出ACK之后進(jìn)入到TIME_WAIT狀態(tài)。Client會(huì)設(shè)置一個(gè)計(jì)時(shí)器,等待2MSL的時(shí)間。如果在該時(shí)間內(nèi)再次收到FIN,那么Client會(huì)重發(fā)ACK并再次等待2MSL。所謂的2MSL是兩倍的MSL(Maximum Segment Lifetime)。

MSL指一個(gè)片段在網(wǎng)絡(luò)中最大的存活時(shí)間,2MSL就是一個(gè)發(fā)送和一個(gè)回復(fù)所需的最大時(shí)間。如果直到2MSL,Client都沒有再次收到FIN,那么Client推斷ACK已經(jīng)被成功接收,則結(jié)束TCP連接。

六  業(yè)務(wù)異常日志

6.1  問題出現(xiàn)

主要是通過業(yè)務(wù)日志監(jiān)控主動(dòng)報(bào)警或者是查看錯(cuò)誤日志被動(dòng)發(fā)現(xiàn):


6.2  日志分析

6.2.1  確認(rèn)日志格式

日志格式如下:

<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'/>

<!--日志格式 時(shí)間|級(jí)別|鏈路id|應(yīng)用名|服務(wù)器ip|租戶id|用戶id|線程名稱|logger名稱|業(yè)務(wù)消息 --><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'/>

6.2.2  在日志文件中檢索異常

利用如下命令可獲得異常的詳細(xì)信息:

cat error.log|grep -n ' java.lang.reflect.InvocationTargetException'


根據(jù)日志格式和日志信息,可獲得traceId為489d71fe-67db-4f59-a916-33f25d35cab8,然后利用以下指令獲取整個(gè)流程的日志信息:

cat biz.log |grep -n '489d71fe-67db-4f59-a916-33f25d35cab8'


6.2.3  代碼分析

然后根據(jù)上述流程日志找到對(duì)應(yīng)的代碼實(shí)現(xiàn),然后進(jìn)行具體的業(yè)務(wù)分析。

招聘

歡迎各路技術(shù)同路人加入烏鶇科技,我們是阿里巴巴全資子公司,為政府、企業(yè)提供全方位數(shù)字化服務(wù)和解決方案,打通政府、企業(yè)與民眾的連接,助力政府的治理現(xiàn)代化,加速企業(yè)的數(shù)字化轉(zhuǎn)型,團(tuán)隊(duì)招聘高級(jí)研發(fā)工程師/技術(shù)專家(Java),base杭州,內(nèi)推直達(dá)郵箱 hxf240223@alibaba-inc.com、longhui.clh@alibaba-inc.com,快速響應(yīng)你的面試安排。

崗位要求:Java基礎(chǔ)扎實(shí),對(duì)JVM原理有一定的了解;對(duì)于用過的開源框架,了解到它的原理和機(jī)制;熟悉分布式系統(tǒng)的設(shè)計(jì)和應(yīng)用,有高并發(fā)應(yīng)用開發(fā)經(jīng)驗(yàn);較強(qiáng)的工作責(zé)任心和良好的溝通協(xié)調(diào)能力,能在壓力下獨(dú)立解決問題。




輕量應(yīng)用服務(wù)器
新用戶專享

阿里云開發(fā)者成長(zhǎng)計(jì)劃面向全年齡段開發(fā)者,依托免費(fèi)資源、免費(fèi)體驗(yàn)、免費(fèi)學(xué)習(xí)、免費(fèi)實(shí)踐 4 大場(chǎng)景,全面助力開發(fā)者輕松掌握云上技能。新用戶專享輕量應(yīng)用服務(wù)器,內(nèi)置WordPress等8種主流環(huán)境,5M峰值帶寬,40GBSSD云盤,1000G流量包,滿足學(xué)習(xí)、搭建應(yīng)用等場(chǎng)!

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
數(shù)據(jù)庫常見面試題(附答案)
MySQL連環(huán)炮,你扛得住嘛?
途虎 面經(jīng),其實(shí)挺簡(jiǎn)單的!
本科畢業(yè)3年的我,是如何薪資翻倍拿到38萬年薪Offer的?
最全技術(shù)面試180題:阿里11面試 網(wǎng)易 百度 美團(tuán)!含答案大贈(zèng)送!
盤點(diǎn)那些被問爛了的 Mysql 面試題 | Laravel China 社區(qū)
更多類似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服