前言
我們都知道mysql用server-id來唯一的標識某個資料庫例項,並在鏈式或雙主複製結構中用它來避免sql語句的無限迴圈。這篇文章分享下我對server-id的理解,然後比較和權衡生成唯一server-id的幾種方式。
server_id的用途
簡單說來,server_id有兩個用途:
1. 用來標記binlog event的源產地,就是sql語句最開始源自於**。
2. 用於io_thread對主庫binlog的過濾。如果沒有設定replicate-same-server-id=1,那麼當從庫的io_thread發現event的源與自己的server-id相同時,就會跳過該event,不把該event寫入到relay log中。從庫的sql_thread自然就不會執行該event。這在鏈式或雙主結構中可以避免sql語句的無限迴圈。
注意:相同server-id的event在io_thread這一層就過濾了;而對於replicate-(do|ignore)-等規則,則是在sql_thread這一層過濾的。io_thread和sql_thread都有過濾的功能。
server_id為何不能重複
在同乙個集群中,server-id一旦重複,可能引發一些詭異問題。
看看下面兩種情況:
圖1:主庫與從庫的server-id不同,但是兩個或多個從庫的server-id相同
這種情況下複製會左右搖擺。當兩個從庫的server-id相同時,如果從庫1已經連線上主庫,此時從庫2也需要連線到主庫,發現之前有server-id相同的連線,就會先登出該連線,然後重新註冊。
參考下面的**片段:
int register_sl**e(thd* thd, uchar* packet, uint packet_length)
兩台從庫不停的註冊,不停的登出,會產生很多relay log檔案,檢視從庫狀態會看到relay log檔名不停改變,從庫的複製狀態一會是yes一會是正在連線中。
圖2:鏈式或雙主結構中,主庫與從庫的server-id相同
從庫1同時又是relay資料庫,它能正確同步,然後把relay-log內容重寫到自己的binlog中。當server-id為100的從庫2 io執行緒獲取binlog時,發現所有內容都是源自於自己,就會丟棄這些event。因此從庫2無法正確同步主庫的資料。只有直接寫relay server的event能正確同步到從庫2。
上面兩種情況可以看到,在同乙個replication set中,保持server-id的唯一性非常重要。
server_id的動態修改
無意中發現server-id竟然是可以動態修改的,可別高興的太早。好處是,上面圖1的情況下,直接修改其中乙個從庫的server-id就可以解決server-id衝突的問題。壞處很隱蔽,如下圖的結構:
現在假設active-master因為某種原因與passive-master的同步斷開後,passive-master上進行了一些ddl變更。然後某dba突發奇想把passive-master的server-id修改為400。當雙master的複製啟動後,那些之前在passive-master上執行的server-id為200的ddl變更,會從此陷入死迴圈。如果是alter table t engine=innodb,它會一直不停,可能你會發現。但是像update a=a+1;這樣的sql,你很難發現。當然這種場景只是我的杜撰,這兒有個更真實的例子主備備的兩個備機轉為雙master時出現的詭異sl**e lag問題:主備備的兩個備機轉為雙master時出現的詭異sl**e-lag問題/。
舉這兩個例子只是想說明修改server-id有點危險,最好不要去修改,那麼能一步到位生成它嗎?
生成唯一的server_id
常用的方法有如下幾種:
1. 採用隨機數
mysql的server-id是4位元組整數,範圍從0-4294967295,因此採用該範圍內的隨機數來作為server-id產生衝突的可能性是非常小的。
2. 採用時間戳
直接用date +%s來生成server-id。一天86400秒來計算,往後計算50年,最大的server-id也才使用到86400*365*50,完全在server-id範圍內。
3. 採用ip位址+埠
這是我們經常採用的方法。例如ip為192.168.122.23,埠為3309,那麼server-id可以寫為122233309。產生衝突的可能性比較小:遇到*.*.122.23 或者*.*.12.223,而且搭建了同乙個replication set的3309才會出現。
4. 採用集中的發號器
在管理伺服器上採用自增的id來統一分配server-id。這可以保證不衝突,但是需要維護中心節點。
5. 分開管理每個replication set
在每個replication set中為mysql庫增加乙個管理表,保證每個從庫的serv程式設計客棧er-id不衝突。
上面的幾種方法都不賴,但是:
建議的方法
其實很簡單。ipv4是4位元組的整數,與server-id的範圍完全一樣。我們認為只有ip位址+埠才能唯一的確定乙個mysql例項,所以總是希望把ip資訊和埠資訊都整合到server-id中。但是別忘了,乙個ip上不能同時啟動兩個一樣的埠。所以,server-id只需採用ip位址的整數形式:select inet_aton('192.168.12.45'),3232238637!所有新上線的例項,mysql啟動指令碼強制對server-id進行檢查,發現server-id不對就進行糾正,然後啟動。這種方法有個前提條件:同一機器上的多個instance不要有主從關係,否則server-id一樣就會導致問題。這種情況一般只會在測試環境出現,**上基本是沒有的。滿足了這個前提,所有問題迎刃而解。
總結本文標題: mysql如何生成唯一的server-id
本文位址: /shujuku/mysql/272826.html
MySql唯一ID生成
前陣子,一直在折騰阿里雲。寫的一些文章也放到自己的wordpress部落格上了。但自己前陣子在做系統更換操作的時候未備份磁碟,大部分心血付諸東流。真是乙個悲傷的故事。現在決定用.net搞搞自己的部落格。正好把wordpress給拋棄掉。言歸正傳,這個唯一號類似自增id,自增id雖然好用,但進行資料庫...
如何生成隨機的唯一編碼
通常來講,oracle中生成隨機唯一編碼的方法就是呼叫sys guid 函式產生16進製制的16個字元的字串,如果用varchar2來儲存guid格式的字串,那就需要32個位元組,如果我們的編碼表的資料量很大,比如 的會員資訊表,其它的業務流水表會非常多地引用會員資訊表的主鍵,這個對儲存成本要求是非...
php生成遊客id PHP如何生成唯一的數字ID
樓主,你這個問題大了。twitter,weibo等都是專門做了乙個發號器來解決這個問題的。twitter那一套東西,叫做snowflake,樓上已經有人指出過了。這玩意一共64bit,前41bit是以微妙的時間戳,10bit是機器護著說伺服器id,最後12bit是seq序列累加計數器。weibo的方...