日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

29 | 如何判断一个数据库是不是出问题了?

發(fā)布時間:2025/3/17 数据库 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 29 | 如何判断一个数据库是不是出问题了? 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

我在第25和27篇文章中,和你介紹了主備切換流程。通過這些內(nèi)容的講解,你應(yīng)該已經(jīng)很清楚了:在一主一備的雙M架構(gòu)里,主備切換只需要把客戶端流量切到備庫;而在一主多從架構(gòu)里,主備切換除了要把客戶端流量切到備庫外,還需要把從庫接到新主庫上。

主備切換有兩種場景,一種是主動切換,一種是被動切換。而其中被動切換,往往是因為主庫出問題了,由HA系統(tǒng)發(fā)起的。

這也就引出了我們今天要討論的問題:怎么判斷一個主庫出問題了?

你一定會說,這很簡單啊,連上MySQL,執(zhí)行個select 1就好了。但是select 1成功返回了,就表示主庫沒問題嗎?

select 1判斷

實際上,select 1成功返回,只能說明這個庫的進(jìn)程還在,并不能說明主庫沒問題。現(xiàn)在,我們來看一下這個場景。

set global innodb_thread_concurrency=3;CREATE TABLE `t` ( `id` int(11) NOT NULL, `c` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB;insert into t values(1,1)

圖1 查詢blocked

我們設(shè)置innodb_thread_concurrency參數(shù)的目的是,控制InnoDB的并發(fā)線程上限。也就是說,一旦并發(fā)線程數(shù)達(dá)到這個值,InnoDB在接收到新請求的時候,就會進(jìn)入等待狀態(tài),直到有線程退出。

這里,我把innodb_thread_concurrency設(shè)置成3,表示InnoDB只允許3個線程并行執(zhí)行。而在我們的例子中,前三個session 中的sleep(100),使得這三個語句都處于“執(zhí)行”狀態(tài),以此來模擬大查詢。

你看到了, session D里面,select 1是能執(zhí)行成功的,但是查詢表t的語句會被堵住。也就是說,如果這時候我們用select 1來檢測實例是否正常的話,是檢測不出問題的。

在InnoDB中,innodb_thread_concurrency這個參數(shù)的默認(rèn)值是0,表示不限制并發(fā)線程數(shù)量。但是,不限制并發(fā)線程數(shù)肯定是不行的。因為,一個機(jī)器的CPU核數(shù)有限,線程全沖進(jìn)來,上下文切換的成本就會太高。

所以,通常情況下,我們建議把innodb_thread_concurrency設(shè)置為64~128之間的值。這時,你一定會有疑問,并發(fā)線程上限數(shù)設(shè)置為128夠干啥,線上的并發(fā)連接數(shù)動不動就上千了。

產(chǎn)生這個疑問的原因,是搞混了并發(fā)連接和并發(fā)查詢。

并發(fā)連接和并發(fā)查詢,并不是同一個概念。你在show processlist的結(jié)果里,看到的幾千個連接,指的就是并發(fā)連接。而“當(dāng)前正在執(zhí)行”的語句,才是我們所說的并發(fā)查詢。

并發(fā)連接數(shù)達(dá)到幾千個影響并不大,就是多占一些內(nèi)存而已。我們應(yīng)該關(guān)注的是并發(fā)查詢,因為并發(fā)查詢太高才是CPU殺手。這也是為什么我們需要設(shè)置innodb_thread_concurrency參數(shù)的原因。

然后,你可能還會想起我們在第7篇文章中講到的熱點(diǎn)更新和死鎖檢測的時候,如果把innodb_thread_concurrency設(shè)置為128的話,那么出現(xiàn)同一行熱點(diǎn)更新的問題時,是不是很快就把128消耗完了,這樣整個系統(tǒng)是不是就掛了呢?

實際上,在線程進(jìn)入鎖等待以后,并發(fā)線程的計數(shù)會減一,也就是說等行鎖(也包括間隙鎖)的線程是不算在128里面的。

MySQL這樣設(shè)計是非常有意義的。因為,進(jìn)入鎖等待的線程已經(jīng)不吃CPU了;更重要的是,必須這么設(shè)計,才能避免整個系統(tǒng)鎖死。

為什么呢?假設(shè)處于鎖等待的線程也占并發(fā)線程的計數(shù),你可以設(shè)想一下這個場景:

  • 線程1執(zhí)行begin; update t set c=c+1 where id=1, 啟動了事務(wù)trx1, 然后保持這個狀態(tài)。這時候,線程處于空閑狀態(tài),不算在并發(fā)線程里面。

  • 線程2到線程129都執(zhí)行 update t set c=c+1 where id=1; 由于等行鎖,進(jìn)入等待狀態(tài)。這樣就有128個線程處于等待狀態(tài);

  • 如果處于鎖等待狀態(tài)的線程計數(shù)不減一,InnoDB就會認(rèn)為線程數(shù)用滿了,會阻止其他語句進(jìn)入引擎執(zhí)行,這樣線程1不能提交事務(wù)。而另外的128個線程又處于鎖等待狀態(tài),整個系統(tǒng)就堵住了。

  • 下圖2顯示的就是這個狀態(tài)。

    圖2 系統(tǒng)鎖死狀態(tài)(假設(shè)等行鎖的語句占用并發(fā)計數(shù))

    這時候InnoDB不能響應(yīng)任何請求,整個系統(tǒng)被鎖死。而且,由于所有線程都處于等待狀態(tài),此時占用的CPU卻是0,而這明顯不合理。所以,我們說InnoDB在設(shè)計時,遇到進(jìn)程進(jìn)入鎖等待的情況時,將并發(fā)線程的計數(shù)減1的設(shè)計,是合理而且是必要的。

    雖然說等鎖的線程不算在并發(fā)線程計數(shù)里,但如果它在真正地執(zhí)行查詢,就比如我們上面例子中前三個事務(wù)中的select sleep(100) from t,還是要算進(jìn)并發(fā)線程的計數(shù)的。

    在這個例子中,同時在執(zhí)行的語句超過了設(shè)置的innodb_thread_concurrency的值,這時候系統(tǒng)其實已經(jīng)不行了,但是通過select 1來檢測系統(tǒng),會認(rèn)為系統(tǒng)還是正常的。

    因此,我們使用select 1的判斷邏輯要修改一下。

    查表判斷

    為了能夠檢測InnoDB并發(fā)線程數(shù)過多導(dǎo)致的系統(tǒng)不可用情況,我們需要找一個訪問InnoDB的場景。一般的做法是,在系統(tǒng)庫(mysql庫)里創(chuàng)建一個表,比如命名為health_check,里面只放一行數(shù)據(jù),然后定期執(zhí)行:

    mysql> select * from mysql.health_check;

    使用這個方法,我們可以檢測出由于并發(fā)線程過多導(dǎo)致的數(shù)據(jù)庫不可用的情況。

    但是,我們馬上還會碰到下一個問題,即:空間滿了以后,這種方法又會變得不好使。

    我們知道,更新事務(wù)要寫binlog,而一旦binlog所在磁盤的空間占用率達(dá)到100%,那么所有的更新語句和事務(wù)提交的commit語句就都會被堵住。但是,系統(tǒng)這時候還是可以正常讀數(shù)據(jù)的。

    因此,我們還是把這條監(jiān)控語句再改進(jìn)一下。接下來,我們就看看把查詢語句改成更新語句后的效果。

    更新判斷

    既然要更新,就要放個有意義的字段,常見做法是放一個timestamp字段,用來表示最后一次執(zhí)行檢測的時間。這條更新語句類似于:

    mysql> update mysql.health_check set t_modified=now();

    節(jié)點(diǎn)可用性的檢測都應(yīng)該包含主庫和備庫。如果用更新來檢測主庫的話,那么備庫也要進(jìn)行更新檢測。

    但,備庫的檢測也是要寫binlog的。由于我們一般會把數(shù)據(jù)庫A和B的主備關(guān)系設(shè)計為雙M結(jié)構(gòu),所以在備庫B上執(zhí)行的檢測命令,也要發(fā)回給主庫A。

    但是,如果主庫A和備庫B都用相同的更新命令,就可能出現(xiàn)行沖突,也就是可能會導(dǎo)致主備同步停止。所以,現(xiàn)在看來mysql.health_check 這個表就不能只有一行數(shù)據(jù)了。

    為了讓主備之間的更新不產(chǎn)生沖突,我們可以在mysql.health_check表上存入多行數(shù)據(jù),并用A、B的server_id做主鍵。

    mysql> CREATE TABLE `health_check` ( `id` int(11) NOT NULL, `t_modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`) ) ENGINE=InnoDB;/* 檢測命令 */ insert into mysql.health_check(id, t_modified) values (@@server_id, now()) on duplicate key update t_modified=now();

    由于MySQL規(guī)定了主庫和備庫的server_id必須不同(否則創(chuàng)建主備關(guān)系的時候就會報錯),這樣就可以保證主、備庫各自的檢測命令不會發(fā)生沖突。

    更新判斷是一個相對比較常用的方案了,不過依然存在一些問題。其中,“判定慢”一直是讓DBA頭疼的問題。

    你一定會疑惑,更新語句,如果失敗或者超時,就可以發(fā)起主備切換了,為什么還會有判定慢的問題呢?

    其實,這里涉及到的是服務(wù)器IO資源分配的問題。

    首先,所有的檢測邏輯都需要一個超時時間N。執(zhí)行一條update語句,超過N秒后還不返回,就認(rèn)為系統(tǒng)不可用。

    你可以設(shè)想一個日志盤的IO利用率已經(jīng)是100%的場景。這時候,整個系統(tǒng)響應(yīng)非常慢,已經(jīng)需要做主備切換了。

    但是你要知道,IO利用率100%表示系統(tǒng)的IO是在工作的,每個請求都有機(jī)會獲得IO資源,執(zhí)行自己的任務(wù)。而我們的檢測使用的update命令,需要的資源很少,所以可能在拿到IO資源的時候就可以提交成功,并且在超時時間N秒未到達(dá)之前就返回給了檢測系統(tǒng)。

    檢測系統(tǒng)一看,update命令沒有超時,于是就得到了“系統(tǒng)正常”的結(jié)論。

    也就是說,這時候在業(yè)務(wù)系統(tǒng)上正常的SQL語句已經(jīng)執(zhí)行得很慢了,但是DBA上去一看,HA系統(tǒng)還在正常工作,并且認(rèn)為主庫現(xiàn)在處于可用狀態(tài)。

    之所以會出現(xiàn)這個現(xiàn)象,根本原因是我們上面說的所有方法,都是基于外部檢測的。外部檢測天然有一個問題,就是隨機(jī)性。

    因為,外部檢測都需要定時輪詢,所以系統(tǒng)可能已經(jīng)出問題了,但是卻需要等到下一個檢測發(fā)起執(zhí)行語句的時候,我們才有可能發(fā)現(xiàn)問題。而且,如果你的運(yùn)氣不夠好的話,可能第一次輪詢還不能發(fā)現(xiàn),這就會導(dǎo)致切換慢的問題。

    所以,接下來我要再和你介紹一種在MySQL內(nèi)部發(fā)現(xiàn)數(shù)據(jù)庫問題的方法。

    內(nèi)部統(tǒng)計

    針對磁盤利用率這個問題,如果MySQL可以告訴我們,內(nèi)部每一次IO請求的時間,那我們判斷數(shù)據(jù)庫是否出問題的方法就可靠得多了。

    其實,MySQL 5.6版本以后提供的performance_schema庫,就在file_summary_by_event_name表里統(tǒng)計了每次IO請求的時間。

    file_summary_by_event_name表里有很多行數(shù)據(jù),我們先來看看event_name='wait/io/file/innodb/innodb_log_file’這一行。

    圖3 performance_schema.file_summary_by_event_name的一行

    圖中這一行表示統(tǒng)計的是redo log的寫入時間,第一列EVENT_NAME 表示統(tǒng)計的類型。

    接下來的三組數(shù)據(jù),顯示的是redo log操作的時間統(tǒng)計。

    第一組五列,是所有IO類型的統(tǒng)計。其中,COUNT_STAR是所有IO的總次數(shù),接下來四列是具體的統(tǒng)計項, 單位是皮秒;前綴SUM、MIN、AVG、MAX,顧名思義指的就是總和、最小值、平均值和最大值。

    第二組六列,是讀操作的統(tǒng)計。最后一列SUM_NUMBER_OF_BYTES_READ統(tǒng)計的是,總共從redo log里讀了多少個字節(jié)。

    第三組六列,統(tǒng)計的是寫操作。

    最后的第四組數(shù)據(jù),是對其他類型數(shù)據(jù)的統(tǒng)計。在redo log里,你可以認(rèn)為它們就是對fsync的統(tǒng)計。

    在performance_schema庫的file_summary_by_event_name表里,binlog對應(yīng)的是event_name = "wait/io/file/sql/binlog"這一行。各個字段的統(tǒng)計邏輯,與redo log的各個字段完全相同。這里,我就不再贅述了。

    因為我們每一次操作數(shù)據(jù)庫,performance_schema都需要額外地統(tǒng)計這些信息,所以我們打開這個統(tǒng)計功能是有性能損耗的。

    我的測試結(jié)果是,如果打開所有的performance_schema項,性能大概會下降10%左右。所以,我建議你只打開自己需要的項進(jìn)行統(tǒng)計。你可以通過下面的方法打開或者關(guān)閉某個具體項的統(tǒng)計。

    如果要打開redo log的時間監(jiān)控,你可以執(zhí)行這個語句:

    mysql> update setup_instruments set ENABLED='YES', Timed='YES' where name like '%wait/io/file/innodb/innodb_log_file%';

    假設(shè),現(xiàn)在你已經(jīng)開啟了redo log和binlog這兩個統(tǒng)計信息,那要怎么把這個信息用在實例狀態(tài)診斷上呢?

    很簡單,你可以通過MAX_TIMER的值來判斷數(shù)據(jù)庫是否出問題了。比如,你可以設(shè)定閾值,單次IO請求時間超過200毫秒屬于異常,然后使用類似下面這條語句作為檢測邏輯。

    mysql> select event_name,MAX_TIMER_WAIT FROM performance_schema.file_summary_by_event_name where event_name in ('wait/io/file/innodb/innodb_log_file','wait/io/file/sql/binlog') and MAX_TIMER_WAIT>200*1000000000;

    發(fā)現(xiàn)異常后,取到你需要的信息,再通過下面這條語句:

    mysql> truncate table performance_schema.file_summary_by_event_name;

    把之前的統(tǒng)計信息清空。這樣如果后面的監(jiān)控中,再次出現(xiàn)這個異常,就可以加入監(jiān)控累積值了。

    小結(jié)

    今天,我和你介紹了檢測一個MySQL實例健康狀態(tài)的幾種方法,以及各種方法存在的問題和演進(jìn)的邏輯。

    你看完后可能會覺得,select 1這樣的方法是不是已經(jīng)被淘汰了呢,但實際上使用非常廣泛的MHA(Master High Availability),默認(rèn)使用的就是這個方法。

    MHA中的另一個可選方法是只做連接,就是 “如果連接成功就認(rèn)為主庫沒問題”。不過據(jù)我所知,選擇這個方法的很少。

    其實,每個改進(jìn)的方案,都會增加額外損耗,并不能用“對錯”做直接判斷,需要你根據(jù)業(yè)務(wù)實際情況去做權(quán)衡。

    我個人比較傾向的方案,是優(yōu)先考慮update系統(tǒng)表,然后再配合增加檢測performance_schema的信息。

    最后,又到了我們的思考題時間。

    今天,我想問你的是:業(yè)務(wù)系統(tǒng)一般也有高可用的需求,在你開發(fā)和維護(hù)過的服務(wù)中,你是怎么判斷服務(wù)有沒有出問題的呢?

    你可以把你用到的方法和分析寫在留言區(qū),我會在下一篇文章中選取有趣的方案一起來分享和分析。感謝你的收聽,也歡迎你把這篇文章分享給更多的朋友一起閱讀。

    上期問題時間

    上期的問題是,如果使用GTID等位點(diǎn)的方案做讀寫分離,在對大表做DDL的時候會怎么樣。

    假設(shè),這條語句在主庫上要執(zhí)行10分鐘,提交后傳到備庫就要10分鐘(典型的大事務(wù))。那么,在主庫DDL之后再提交的事務(wù)的GTID,去備庫查的時候,就會等10分鐘才出現(xiàn)。

    這樣,這個讀寫分離機(jī)制在這10分鐘之內(nèi)都會超時,然后走主庫。

    這種預(yù)期內(nèi)的操作,應(yīng)該在業(yè)務(wù)低峰期的時候,確保主庫能夠支持所有業(yè)務(wù)查詢,然后把讀請求都切到主庫,再在主庫上做DDL。等備庫延遲追上以后,再把讀請求切回備庫。

    通過這個思考題,我主要想讓關(guān)注的是,大事務(wù)對等位點(diǎn)方案的影響。

    當(dāng)然了,使用gh-ost方案來解決這個問題也是不錯的選擇。

    ?

    轉(zhuǎn)載于:https://www.cnblogs.com/a-phper/p/10313969.html

    總結(jié)

    以上是生活随笔為你收集整理的29 | 如何判断一个数据库是不是出问题了?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 中国黄色三级 | 日韩有码一区 | 欧美日韩在线观看一区二区 | 日韩黄色录像 | 免费无码一区二区三区 | 欧美黄色短片 | 中文日本在线 | 无码人妻aⅴ一区二区三区玉蒲团 | av中文字幕在线免费观看 | 色多多网站| 美国av导航 | 一级福利片 | 国产a网| 一区两区小视频 | 国产精品伦一区二区三区免费看 | 亚洲日本欧美在线 | 激情免费av | 中文字幕免 | 精品少妇人妻av一区二区 | 北条麻妃一区二区三区免费 | 婷婷的五月 | 手机在线观看免费av | 天堂网亚洲 | 露脸啪啪清纯大学生美女 | 成人福利网址 | 久久久剧场 | 亚洲无限av | 亚州国产精品视频 | 午夜狠狠干 | 玖玖爱免费视频 | 日本做爰高潮又黄又爽 | 久久色视频 | 男人天堂视频在线 | 成人免费毛片色戒 | 亚洲精品在线不卡 | jizz91| 狠狠操在线播放 | 日韩av在线播放一区 | 午夜一区二区三区 | 中文字幕一区不卡 | 国产精品麻豆入口 | 亚洲国产精品久久久久婷婷老年 | 香港一级纯黄大片 | 国产精品人人做人人爽人人添 | 午夜专区 | 免费在线观看一区 | 国产精品无码AV | 六月丁香啪啪 | 国产精品毛片久久久久久久 | 成人综合激情网 | 欧美黄色免费网站 | 无遮挡裸光屁屁打屁股男男 | av色噜噜| 亚洲激情一区二区三区 | 天天摸天天干 | 天天操网站 | 黄色在线网站 | 亚洲 小说区 图片区 | 五月天亚洲色图 | 国产精品久久久久久妇女 | 日日狠狠久久偷偷四色综合免费 | 亚洲最大av网 | 欧美成人一级视频 | 中国国语农村大片 | xxxxx黄色片| 天堂av中文字幕 | 国产精品1000| 国产精品麻豆一区二区三区 | 日本中文字幕在线观看视频 | 久久久精品久久 | 新红楼梦2005锦江版高清在线观看 | 东京av在线| 亚洲欧洲在线视频 | 亚洲最大福利 | 婷婷免费| 久久亚洲综合色图 | 亚洲精品久久久久久久久久久 | 日韩伦理一区 | 国内黄色片 | 国产豆花视频 | 亚洲激情在线 | 欧美人与动牲交xxxxbbbb | 一级片免费在线观看 | 99久久婷婷国产精品综合 | 少妇特黄a一区二区三区88av | 能直接看的av网站 | 亚洲国产精品无码久久久久高潮 | 亚洲性生活大片 | 成人1区2区| jizz黄色片 | 国产91丝袜在线播放 | 亚洲九九精品 | 亚洲精品少妇一区二区 | www亚洲成人 | 日韩欧美高清片 | 久久精品伦理 | av片一区二区三区 | 国产一二三在线观看 | 中文字幕伦理 |