答疑文章(一) 日誌與索引相關問題讀後總結

2021-09-26 07:37:29 字數 4133 閱讀 5139

日誌相關的問題:

mysql 利用 binlog與redo log做 崩潰恢復。mysql利用了二階段提交維護了主備資料一致性

(ps:對mysql的崩潰恢復,以及異常資料恢復不是一樣的情況需要注意)

兩階段提交:

取id=2這一行 =》判斷資料頁是否在記憶體中,不在就從磁碟中讀入記憶體中返回資料。=》將這一行的c值加1,寫入新行=》新行更新到記憶體=》寫入redo log處於prepare階段。=》寫入binlog=》提交事務redo log 處於commit狀態。

在兩階段提交的過程中,mysql異常重啟後產生的情況:

處於redo log prepare狀態,並在寫binlog之前。redo log 狀態沒有commit,以及bin log 沒有寫。在崩潰恢復的時候,事務會回滾。bin log 沒有寫,所以也不會傳到備庫上。

2.binlog寫完後,redo log狀態commit 之前。這裡提供一下崩潰恢復的判斷規則

redo log中的事務狀態已經是commit,則直接提交

redo log中的事務只有完整的prepare,則判斷對應的binlog事務是否完整

完整則提交事務

否則,回滾事務

mysq怎麼知道binlog是完整的?

乙個事務的binlog是有完整格式:

statement格式中,每乙個事務最後都會有乙個commit

row格式中,每個事務最後都會有乙個xid event

mysql5.6以後 用binlog-checksum引數檢查binlog是否完整。

redo log 與bin log是如何聯絡起來的?

redolog與binlog有乙個公共字段,xid。

恢復崩潰時,會順序掃瞄redolog。

1.遇到既有prepare與commit的redolog直接提交

2. 遇到只有prepare的事務,拿著該事務的xid去binlog中查對應的事務是否完整。

處於prepare的redo與完整的binlog,就可以重啟恢復,mysql為什麼要這麼設計?

這時候binlog已經寫入,所以就可能同步到從庫中,所以主庫恢復的時候需要將事務提交。這樣就保證了主從資料一致。

為什麼還需要兩階段提交,保證redolog與binlog資料完整,做崩潰異常

兩階段提交是所有分布式系統的經典資料一致性問題。

而mysql的redo log寫完之後就不能回滾了。所以如果不使用兩階段提交的話,redolog寫成功,但是binlog寫失敗了,由於redolog的事務無法回滾,導致主從資料不一致。

不引入兩個日誌,就可以不考慮兩階段提交的問題。只用binlog來支援崩潰恢復,又能支援歸檔,不就可以了?

首先innodb一開始是以外掛程式的身份接入mysql的,binlog沒有崩潰恢復的能力。

binlog無法現實資料頁的恢復。

那能不能反過來,只要redo log,不要binlog?

binlog是mysql高可用的基礎元件,binlog複製,以及歸檔等等作用是redo log無法實現的。

redo log 一般設定多大?

redo log 如果設定太小的話,會導致經常刷redo log,刷髒頁,影響磁碟效能,並且不能發揮wal的最大的作用。一般幾t硬碟直接設4個redo log,乙個檔案乙個g大小。

正常執行的例項,資料寫入後端最終落盤,是從redolog更新過來的還是從buffer pool更新過來的?

髒頁被刷到磁碟的過程與redolog沒有關係。redolog中沒有記錄有關資料頁的資料,根本沒有能力修改磁碟資料頁。

正常執行的例項,在之前提過的四種情況下,1.redolog滿了,2.記憶體不足,3.mysql認為系統空閒,4.mysql重啟時觸發刷髒頁。將記憶體頁資料刷入磁碟。redolog中記錄的更改記錄,並沒有源資料。

2.在崩潰恢復的場景中,innodb判定乙個資料頁在崩潰中可能丟失的更新,就會將它讀入記憶體,從redolog讀取更新操作,更新該資料頁使其成為髒頁。回到了第一種情況。redo log 與資料落盤沒有直接關係。

redo log buffer是什麼?是先修改記憶體,還是先寫redo log 檔案

redo log buffer是一塊記憶體,用來先存redo log的。乙個事務中,更新語句執行完,先更新記憶體,在將redo log 寫入 redo log buffer 中,到最後commit的再寫入redo log 檔案。

事務執行過程中一般不會中主動刷盤,以減少不必要的io消耗。但是也會有被動刷盤的情況發生比如記憶體不夠,有其他事務提交的情況。

業務設計問題

背景:使用者相互關注自動成為好友,有兩張表一張liker表記錄了誰關注誰,另一張表friend記錄哪些使用者成為好友。使用者關注流程,當使用者a關注b的時候,先檢視b是否關注了a,是則ab自動成為好友,向friend插入一條資料,在liker表中插入a關注b的記錄,否則只在liker表中插入a關注b的記錄。

問題在併發相互關注的時候,會引起雙方無法成為好友的情況。原因是在雙方查詢的時候對方關注的記錄還沒有與插入,導致形成了只向liker表中插入了ab相互關注了對方,但是friend表中並沒有記錄ab成為好友。

根本原因沒有記錄所以你想用鎖也無用武之地。向liker表中加乙個欄位relation ,1表示a關注b,2表示b關注a,3表示相互關注。

create tablelike(

idint(11) not null auto_increment,

user_idint(11) not null,

liker_idint(11) not null,

primary key (id),

unique keyuk_user_id_liker_id(user_id,liker_id)

) engine=innodb;

create tablefriend(

idint(11) not null auto_increment,friend_1_idint(11) not null,firned_2_idint(11) not null, unique keyuk_friend(friend_1_id,firned_2_id) primary key (id`)

) engine=innodb;

mysql> begin; /* 啟動事務 /

insert intolike(user_id, liker_id, relation_ship) values(a, b, 1) on duplicate key update relation_ship=relation_ship | 1;

select relation_ship fromlikewhere user_id=a and liker_id=b;

/ **中判斷返回的 relation_ship,

如果是 1,事務結束,執行 commit

如果是 3,則執行下面這兩個語句:

*/insert ignore into friend(friend_1_id, friend_2_id) values(a,b);

commit;

mysql> begin; /* 啟動事務 /

insert intolike(user_id, liker_id, relation_ship) values(b, a, 2) on duplicate key update relation_ship=relation_ship | 2;

select relation_ship fromlikewhere user_id=b and liker_id=a;

/ **中判斷返回的 relation_ship,

如果是 2,事務結束,執行 commit

如果是 3,則執行下面這兩個語句:

*/insert ignore into friend(friend_1_id, friend_2_id) values(b,a);

commit;

這個設計裡,liker表中資料保證user_id |與 insert ignore,是保證了重複呼叫時的冪等性。

專案一 日誌分析

import random import datetime import time import threading import re import sys from queue import queue from pathlib import path from user agents impo...

統一日誌處理

日誌是幹啥的.不多說.這裡只記錄怎麼配置日誌.logger 日誌記錄器.可以配置不同的日誌級別.不同的級別顯示的日誌資訊不同的.越往後的日誌級別會包含前面所有日誌級別顯示的資訊 off,fatal,error,warn,info,debug,all loggin.level.root warn這是 ...

統一日誌框架

常見的框架有log4j log4j2 logback 如果乙個專案中整合元件有單獨的框架那麼日誌配置就很混亂 log4j log4j2是沒有實現slf4j門面的 logback是實現的 就是我們獲取logger的包 是從slf4j獲取的 將我們自己的日誌框架通過slf4j實現 如果是log4j通過s...