高可用设计模式:冗余、故障转移与仲裁
é«å¯ç¨è®¾è®¡æ¨¡å¼ï¼åä½ãæ é转移ä¸ä»²è£
ltl 2026-08-10 10 é 读21åéåæåå¸äº quant67.comï¼è½¬è½½è¯·ä¿çåºå¤ã
ä¸ä¸ªæ¯ä»ç³»ç»çæ°æ®åºä¸»èç¹å¨åæ¨ 3:17 åçç£çæ éï¼å¤èç¹æ£æµå°å¿è·³è¶ æ¶å¹¶å¨ 8 ç§å 宿忢ï¼å¯¹å¤æå¡ä¸ææ¶é´æ§å¶å¨ 10 ç§ä»¥å ãå¦ä¸ä¸ªçµåå¹³å°çæ°æ®åºä¹åçäºç±»ä¼¼æ éï¼ä½å 为å¤èç¹å主èç¹åæ¶è®¤ä¸ºèªå·±æ¯ä¸»ââèè£ï¼Split-Brainï¼ââ两个èç¹åèªæ¥ååå ¥ï¼å¯¼è´è®¢åæ°æ®åºç°ä¸å¯è°åçå²çªï¼æ¢å¤ç¨äº 6 å°æ¶ã
两个系ç»é½å£°ç§°èªå·±æ¯"é«å¯ç¨æ¶æ"ãå·®å«å¨äºï¼åè çé«å¯ç¨è®¾è®¡ç»è¿äºæ 鿣æµãä»²è£æºå¶åæ°æ®ä¸è´æ§ä¸ä¸ªå±é¢ç宿´èéï¼åè åªåäºåä½é¨ç½²ï¼ç¼ºå°ä»²è£å Fencing æºå¶ã
é«å¯ç¨ï¼High Availabilityï¼HAï¼ä¸æ¯ä¸ä¸ªåè½ï¼èæ¯ä¸ç»è®¾è®¡æ¨¡å¼çç»åãå使ä¾äºæ éåçåçæ¢å¤è½åï¼ä½å使¬èº«ä¸çäºé«å¯ç¨ââå¦ä½æ£æµæ éãå¦ä½å³å®åæ¢ã忢è¿ç¨ä¸å¦ä½ä¿è¯æ°æ®ä¸è´ãå¦ä½é¿å èè£ï¼è¿äºé®é¢ççæ¡å³å®äºä¸ä¸ªç³»ç»å°åºè½åå°å 个 9ã
æ¬æä»åº¦éä½ç³»å¼å§ï¼éå±æè§£å使¨¡åãæ éæ£æµã忢æºå¶ãèè£é²æ¤ãç½ç»å±åæ¢ãæ°æ®ä¸è´æ§ï¼æåç»åºå·¥ç¨æ¡ä¾å模å¼éå对æ¯ã
ä¸ãåæºç代价ï¼ä¸ºä»ä¹éè¦é«å¯ç¨
åæºç代价å¯ä»¥ç¨ä¸ä¸ªç»´åº¦æ¥è¡¡éï¼ç´æ¥ç»æµæå¤±ãç¨æ·ä¿¡ä»»æå¤±ãåè§é£é©ã
ç´æ¥ç»æµæå¤±ã 2017 å¹´ Amazon ç S3 æ éæç»çº¦ 4 å°æ¶ï¼å½±åäºå¤§éä¾èµ S3 çäºèç½æå¡ï¼æ®ä¼°ç®é æè¶ è¿ 1.5 亿ç¾å çç´æ¥ç»æµæå¤±ã对äºå¨çº¿äº¤æç³»ç»ï¼æ¯åéåæºå¯è½æå³çæ°ä¸ç¬äº¤ææ æ³å®æãä¸ä¸ªæ¥å交æé¢ 1 亿å çæ¯ä»ç³»ç»ï¼å¦ææ¯åéå¤ç约 7 ä¸å 交æï¼åæº 30 åéçç´æ¥äº¤ææå¤±å°±è¶ è¿ 200 ä¸å ã
ç¨æ·ä¿¡ä»»æå¤±ã ç¨æ·å¯¹æå¡å¯ç¨æ§ç容å¿åº¦å¨è¿å»åå¹´éæç»éä½ãç§»å¨äºèç½æ¶ä»£ï¼ä¸ä¸ª App æä¸å¼ï¼ç¨æ· 3 ç§å å°±ä¼åæ¢å°ç«äºå¯¹æãä¿¡ä»»ä¸æ¦å¤±å»ï¼æ¢å¤çææ¬è¿é«äºææ¯ä¿®å¤æ¬èº«çææ¬ã
åè§é£é©ã éèãå»çãçµä¿¡è¡ä¸ææç¡®çå¯ç¨æ§è¦æ±ãä¸å½äººæ°é¶è¡å¯¹æ¯ä»æ¸ ç®ç³»ç»çå¯ç¨æ§è¦æ±æ¯ 99.99%ï¼æ¬§çç DORAï¼Digital Operational Resilience Actï¼å¯¹éèæºæç ICT ç³»ç»å¯ç¨æ§ææ³å¾å±é¢ç约æã
è¿äºä»£ä»·ä¸æ¯çº¿æ§çãä» 99.9% æåå° 99.99% çå·¥ç¨ææ¬å¯è½æ¯ 10 åï¼ä½ä» 99.9% æå° 99% çä¸å¡æå¤±å¯è½æ¯ 100 åãé«å¯ç¨è®¾è®¡çç®æ 䏿¯"æ°¸ä¸åæº"ââé£å¨ç©çä¸ä¸å¯è½ââèæ¯æåæºæ¶é´æ§å¶å¨ä¸å¡å¯ä»¥æ¿åçèå´å ã
äºãå¯ç¨æ§åº¦éï¼MTBFãMTTR ä¸"å 个 9"
åºæ¬æ¦å¿µ
é«å¯ç¨çå®éæè¿°ä¾èµä¸ä¸ªæ ¸å¿ææ ï¼
MTBFï¼Mean Time Between Failuresï¼å¹³åæ éé´éæ¶é´ï¼ï¼ ç³»ç»ä¸¤æ¬¡æ éä¹é´ç平忣叏è¿è¡æ¶é´ãMTBF è¶å¤§ï¼è¯´æç³»ç»è¶ç¨³å®ãæ éé¢çè¶ä½ã
MTTRï¼Mean Time To Repairï¼å¹³åä¿®å¤æ¶é´ï¼ï¼ 仿 éåç尿塿¢å¤ç平忶é´ãMTTR å 嫿 éæ£æµæ¶é´ãè¯ææ¶é´ãä¿®å¤æ¶é´åæ¢å¤éªè¯æ¶é´ã
MTTFï¼Mean Time To Failureï¼å¹³åæ æ éæ¶é´ï¼ï¼ 对äºä¸å¯ä¿®å¤çç»ä»¶ï¼å¦ç¡¬çï¼ï¼ä½¿ç¨ MTTF èé MTBFã对äºå¯ä¿®å¤çç³»ç»ï¼MTBF â MTTF + MTTRã
å¯ç¨æ§ï¼Availabilityï¼ç计ç®å ¬å¼ï¼
A = MTBF / (MTBF + MTTR)
è¿ä¸ªå ¬å¼æç¤ºäºä¸ä¸ªå ³é®æ´å¯ï¼æåå¯ç¨æ§æä¸¤æ¡è·¯å¾ââå¢å¤§ MTBFï¼åå°æ éåççé¢çï¼æè åå° MTTRï¼ç¼©çæ 鿢å¤çæ¶é´ï¼ãé«å¯ç¨è®¾è®¡å¨ä¸¤ä¸ªæ¹åä¸åæ¶ååï¼ä½å®è·µä¸ï¼ç¼©ç MTTR çæå ¥äº§åºæ¯å¾å¾æ´é«ã
åå å¾ç®åï¼MTBF çæååéäºç¡¬ä»¶å¯é æ§ã软件缺é·ççé¾ä»¥æ ¹æ¬æ¶é¤çå ç´ ï¼è MTTR å¯ä»¥éè¿èªå¨åæ 鿣æµãèªå¨å忢ãé¢é ç½®å¤èç¹çå·¥ç¨ææ®µå¤§å¹ éä½ã
"å 个 9"çå«ä¹
å·¥ä¸çç¨"å 个 9"æ¥æè¿°å¯ç¨æ§ç级ãä¸é¢çè¡¨æ ¼ååºäºä¸åç级çå«ä¹ï¼
| å¯ç¨æ§ç级 | ç¾åæ¯ | æ¯å¹´å è®¸åæºæ¶é´ | æ¯æå è®¸åæºæ¶é´ | æ¯å¨å è®¸åæºæ¶é´ | å ¸ååºæ¯ |
|---|---|---|---|---|---|
| 2 个 9 | 99% | 3.65 天 | 7.31 å°æ¶ | 1.68 å°æ¶ | å é¨ç®¡çç³»ç» |
| 3 个 9 | 99.9% | 8.77 å°æ¶ | 43.83 åé | 10.08 åé | ä¸è¬ä¸å¡ç³»ç» |
| 3.5 个 9 | 99.95% | 4.38 å°æ¶ | 21.92 åé | 5.04 åé | çµåå¹³å° |
| 4 个 9 | 99.99% | 52.60 åé | 4.38 åé | 1.01 åé | æ¯ä»ç³»ç»ãæ ¸å¿äº¤æ |
| 4.5 个 9 | 99.995% | 26.30 åé | 2.19 åé | 30.24 ç§ | çµä¿¡æ ¸å¿ç½ |
| 5 个 9 | 99.999% | 5.26 åé | 26.30 ç§ | 6.05 ç§ | èªç©ºç®¡å¶ãå»çè®¾å¤ |
ä»è¿å¼ 表å¯ä»¥çåºå ä¸ªå ³é®ä¿¡æ¯ï¼
第ä¸ï¼æ¯æåä¸ä¸ª 9ï¼å 许çåæºæ¶é´ç¼©ç约 10 åã ä» 3 个 9 å° 4 个 9ï¼å è®¸åæºæ¶é´ä»æ¯å¹´ 8.77 å°æ¶éå° 52.60 åéã
第äºï¼4 个 9 æå³çæ¯ä¸ªæçåæºçªå£åªæçº¦ 4 åéã è¿æå³çæ 鿣æµå åæ¢çæ»æ¶é´å¿ é¡»æ§å¶å¨åé级å«ä»¥å ââ人工ä»å ¥å ä¹ä¸å¯è½ï¼å¿ é¡»ä¾èµèªå¨åã
第ä¸ï¼5 个 9 æå³çæ¯å¹´åªå 许 5 åéåæºã è¿ä¸ªçº§å«çå¯ç¨æ§é常éè¦å ¨åä½ç¡¬ä»¶ãæ åç¹æ é设计ãèªå¨åæ 鿣æµå忢ã以åå®åçç¾å¤æ¹æ¡ã
å¯ç¨æ§ç计ç®é·é±
å¯ç¨æ§è®¡ç®æå 个常è§ç误åºï¼
串èç³»ç»çå¯ç¨æ§ã 妿ä¸ä¸ªè¯·æ±é¾è·¯ç»è¿ AãBãC ä¸ä¸ªæå¡ï¼æ¯ä¸ªæå¡çå¯ç¨æ§é½æ¯ 99.9%ï¼é£ä¹æ´æ¡é¾è·¯çå¯ç¨æ§æ¯ï¼
A_total = 0.999 Ã 0.999 Ã 0.999 = 0.997 â 99.7%
ä¸ä¸ª 3 个 9 çæå¡ä¸²èï¼æ´ä½åªæä¸å° 3 个 9ãè¿å°±æ¯ä¸ºä»ä¹å¾®æå¡æ¶æä¸ï¼å个æå¡çå¯ç¨æ§æ åå¾å¾éè¦é«äºç³»ç»æ´ä½çç®æ ã
å¹¶èç³»ç»çå¯ç¨æ§ã 妿åä¸ä¸ªæå¡é¨ç½²äºä¸¤ä¸ªç¸äºç¬ç«ç坿¬ï¼ä»»ä¸å¯æ¬å¯ç¨å³æå¡å¯ç¨ï¼é£ä¹ï¼
A_parallel = 1 - (1 - A)^2 = 1 - (0.001)^2 = 1 - 0.000001 = 99.9999%
两个 3 个 9 çèç¹å¹¶èï¼ç论å¯ç¨æ§è¾¾å° 6 个 9ãä½è¿æä¸ä¸ªåæââ两个èç¹çæ éå¿ é¡»æ¯ç¬ç«çãå¦æå ±ç¨åä¸ä¸ªçµæºãåä¸ä¸ªæºæ¶ãåä¸ä¸ªäº¤æ¢æºï¼é£ä¹ä¸ä¸ªç¡¬ä»¶æ éå¯è½åæ¶å»å两个èç¹ï¼ç¬ç«æ§åè®¾å°±ä¸æç«äºã
计åå åæºç®ä¸ç®ï¼ ä¸åç»ç»çå£å¾ä¸åãæäºç»ç»æè®¡åå ç»´æ¤çªå£æé¤å¨å¯ç¨æ§è®¡ç®ä¹å¤ï¼æäºåå ¨é¨è®¡å ¥ãSLAï¼Service Level Agreementï¼éå¿ é¡»æç¡®è¿ä¸ç¹ï¼å¦ååæ ·æ¯"4 个 9"ï¼å®é å«ä¹å¯è½å®å ¨ä¸åã
ä¸ãå使¨¡åï¼ä» Active-Passive å° N+M
åä½ï¼Redundancyï¼æ¯é«å¯ç¨çåºç¡ã没æåä½å°±æ²¡ææ¥ç®¡èµæºãå使¨¡å¼çéæ©ç´æ¥å½±åææ¬ãå¤æåº¦å忢é度ã
Active-Passiveï¼ä¸»å¤æ¨¡å¼ï¼
Active-Passive ä¹å«ä¸»å¤æ¨¡å¼ï¼Master-Slave æ Primary-Standbyï¼ãç³»ç»ä¸æä¸ä¸ªä¸»èç¹ï¼Activeï¼å¤çææè¯·æ±ï¼ä¸ä¸ªæå¤ä¸ªå¤èç¹ï¼Passiveï¼å¤äºçå¾ ç¶æï¼å½ä¸»èç¹æ éæ¶ï¼å¤èç¹æ¥ç®¡æå¡ã
graph TB
Client[客æ·ç«¯] --> VIP[VIP èæ IP]
VIP --> Active[主èç¹ Active]
Active -.->|æ°æ®åæ¥| Standby[å¤èç¹ Passive]
Active -.->|å¿è·³æ£æµ| Standby
subgraph æ£å¸¸ç¶æ
Active
Standby
end
style Active fill:#4CAF50,color:#fff
style Standby fill:#9E9E9E,color:#fff
style VIP fill:#2196F3,color:#fff
工使ºå¶ï¼
- 主èç¹æ¿æ ææè¯»å请æ±ã
- æ°æ®éè¿åæ¥æå¼æ¥å¤å¶ä¼ è¾å°å¤èç¹ã
- å¿è·³æºå¶æç»æ£æµä¸»èç¹ç¶æã
- 主èç¹æ éæ¶ï¼å¤èç¹æå为æ°ç主èç¹ï¼VIP æ¼ç§»å°æ°ä¸»èç¹ã
ä¼ç¹ï¼
- æ¶æç®åï¼ç¶æç®¡çæ¸ æ°ââå¨ä»»ä½æ¶å»ï¼åªæä¸ä¸ªèç¹æ¥ååå ¥ï¼ä¸åå¨åå²çªã
- 忢é»è¾ç¸å¯¹ç®åï¼åªéè¦å䏿¬¡è§è²è½¬æ¢ã
- 对åºç¨å±éæââåºç¨åªéè¦è¿æ¥ VIPï¼ä¸éè¦æç¥ä¸»å¤åæ¢ã
缺ç¹ï¼
- å¤èç¹èµæºå©ç¨çä½ââ卿£å¸¸æ åµä¸ï¼å¤èç¹å¤äºé²ç½®ç¶æï¼æåªæ¿æ å°éåªè¯»æ¥è¯¢ï¼ï¼ç¡¬ä»¶èµæºæµªè´¹ã
- 忢è¿ç¨æä¸æââ仿£æµå°æ éå°å®æåæ¢ï¼é常éè¦æ°ç§å°æ°åç§ï¼æé´æå¡ä¸å¯ç¨ã
- æ°æ®åæ¥å»¶è¿ââå¦æä½¿ç¨å¼æ¥å¤å¶ï¼åæ¢æ¶å¯è½ä¸¢å¤±æªåæ¥çæ°æ®ã
å ¸å使ç¨åºæ¯ï¼ ä¼ ç»æ°æ®åºä¸»å¤ï¼MySQL 主ä»ãPostgreSQL æµå¤å¶ï¼ãRedis Sentinel 模å¼ãåä½åºç¨ç HA é¨ç½²ã
Active-Activeï¼å活模å¼ï¼
Active-Active ä¹å«åæ´»æå¤æ´»ï¼Multi-Activeï¼ãææèç¹åæ¶å¤ç请æ±ï¼æ²¡æ"å¤"çæ¦å¿µã
工使ºå¶ï¼
- å¤ä¸ªèç¹åæ¶æ¥å读å请æ±ã
- 请æ±éè¿è´è½½åè¡¡å¨ååå°åèç¹ã
- èç¹é´éè¦å®æ¶æ°æ®åæ¥æºå¶æ¥ä¿è¯ä¸è´æ§ã
- ä»»ä¸èç¹æ éæ¶ï¼è´è½½åè¡¡å¨å°å ¶ä»æå¡æ± ä¸ç§»é¤ï¼æµéèªå¨ååå°å©ä½èç¹ã
ä¼ç¹ï¼
- èµæºå©ç¨çé«ââææèç¹é½å¨å·¥ä½ï¼æ²¡æé²ç½®èµæºã
- 忢é度快ââä¸éè¦è§è²è½¬æ¢ï¼åªéè¦ä»è´è½½åè¡¡æ± ä¸æé¤æ éèç¹ã
- å¤©ç¶æ¯ææ¨ªåæ©å±ââå¢å èç¹å³å¯æåå¤çè½åã
缺ç¹ï¼
- æ°æ®ä¸è´æ§ææå¤§ââå¤ä¸ªèç¹åæ¶åå ¥ï¼éè¦è§£å³åå²çªé®é¢ã
- æ¶æå¤æåº¦é«ââéè¦åå¸å¼ä¸è´æ§åè®®ï¼å¦ PaxosãRaftï¼æå²çªè§£å³çç¥ï¼å¦ CRDTãLast-Write-Winsï¼ã
- èè£é£é©ââç½ç»ååºæ¶ï¼ä¸åèç¹å¯è½æ¥åå²çªçåå ¥ã
å ¸å使ç¨åºæ¯ï¼ æ ç¶æåºç¨é群ãDNS 轮询ãåå¸å¼ç¼åé群ãè·¨æ°æ®ä¸å¿é¨ç½²ã
å ³äº"çåæ´»"ç说æï¼ ä¸¥æ ¼æä¹ä¸çæ°æ®åºåæ´»ï¼ä¸¤ä¸ªèç¹åæ¶åå ¥åä¸ä»½æ°æ®ä¸ä¿è¯å¼ºä¸è´æ§ï¼å¨å·¥ç¨ä¸æå ¶å¤æãå¾å¤å£°ç§°"åæ´»"çæ¹æ¡ï¼å®é 䏿¯"è¯»åæ´»ãååæ´»"ï¼æè "æåçåæ´»"ââä¸åçæ°æ®åçæåèªç主èç¹ï¼åå¸å¨ä¸åæ°æ®ä¸å¿ï¼æ´ä½çèµ·æ¥æ¯åæ´»ï¼ä½å¯¹æ¯ä¸ä¸ªåçæ¥è¯´ä»ç¶æ¯ Active-Passiveã
N+1 åä½
N+1 åä½çå«ä¹æ¯ï¼N 个工ä½èç¹å 1 个å¤ç¨èç¹ãæ£å¸¸æ åµä¸ N 个èç¹å¤ç请æ±ï¼å¤ç¨èç¹å¾ å½ãä»»ä¸å·¥ä½èç¹æ éæ¶ï¼å¤ç¨èç¹æ¥ç®¡ã
å Active-Passive çåºå«ï¼ Active-Passive éå¸¸æ¯ 1+1ï¼ä¸ä¸»ä¸å¤ï¼ï¼N+1 æ¯å¤ä¸»ä¸å¤ãN+1 çå¤ç¨èç¹æ¯"å ±äº«"çââå®ä¸æ¯æä¸ªç¹å®å·¥ä½èç¹çå¤ä»½ï¼èæ¯æ´ä¸ªé群çå¤ä»½ãè¿æå³çå¤ç¨èµæºçæ¯ä¾æ´ä½ï¼ææ¬æçæ´é«ã
示ä¾ï¼ ä¸ä¸ªæå¡éè¦ 5 个èç¹æè½æ¿è½½å³°å¼æµéã1+1 æ¹æ¡éè¦é¨ç½² 10 个èç¹ï¼5 个主ï¼5 个å¤ï¼ï¼èµæºå©ç¨ç 50%ãN+1 æ¹æ¡åªéè¦ 6 个èç¹ï¼5 个工ä½èç¹ï¼1 个å¤ç¨ï¼ï¼èµæºå©ç¨ç 83%ã
éå¶ï¼ N+1 å设å䏿¶é´æå¤åªæä¸ä¸ªèç¹æ éãå¦æä¸¤ä¸ªå·¥ä½èç¹åæ¶æ éï¼å¤ç¨èç¹åªè½æ¥ç®¡å ¶ä¸ä¸ä¸ªãå¯¹äºæ 鿦çè¾é«æå¯¹å¯ç¨æ§è¦æ±æé«çåºæ¯ï¼éè¦ N+2 ææ´é«çåä½åº¦ã
N+M åä½
N+M å使¯ N+1 çæ³åï¼N 个工ä½èç¹å M 个å¤ç¨èç¹ãM çéæ©åå³äºå¯¹åæ¶æ éæ°éç容å¿åº¦ã
M å¼çç¡®å®æ¹æ³ï¼
- åºäºå岿 éæ°æ®ï¼ç»è®¡è¿å»ä¸å¹´éåæ¶åççæå¤§æ éèç¹æ°ï¼åè¯¥å¼æç¥é«äºè¯¥å¼ä½ä¸º Mã
- åºäºå¯ç¨æ§ç®æ ï¼å¦æè¦æ±å¨ä»»æ K 个èç¹åæ¶æ éæ¶ä»è½ç»´ææå¡ï¼é£ä¹ M ⥠Kã
- åºäºææ¬çº¦æï¼M è¶å¤§ï¼å使æ¬è¶é«ãé常å¨å¯ç¨æ§ç®æ åææ¬ä¹é´åæè¡¡ã
å ¸å使ç¨åºæ¯ï¼ å¤§è§æ¨¡é群é¨ç½²ï¼å¦ Kubernetes ä¸ç ReplicaSetï¼è®¾ç½®å¯æ¬æ° = éè¦æ° + å使°ï¼ãæ°æ®ä¸å¿çº§å«çæå¡å¨åä½ãç½ç»è®¾å¤åä½ã
å使¨¡å对æ¯
| 维度 | Active-Passive | Active-Active | N+1 | N+M |
|---|---|---|---|---|
| èµæºå©ç¨ç | 50%ï¼1+1 åºæ¯ï¼ | æ¥è¿ 100% | N/(N+1) | N/(N+M) |
| 忢é度 | ç§çº§å°åç§çº§ | 毫ç§å°ç§çº§ | ç§çº§å°åç§çº§ | ç§çº§å°åç§çº§ |
| æ°æ®ä¸è´æ§ | è¾å¥½ï¼ååå ¥ç¹ï¼ | 夿ï¼å¤åå ¥ç¹ï¼ | è¾å¥½ | è¾å¥½ |
| æ¶æå¤æåº¦ | ä½ | é« | ä¸ | ä¸ |
| 容å¿åæ¶æ éæ° | 1 | åå³äºå©ä½å®¹é | 1 | M |
| å ¸åææ¬æ¯ | 2x | 1.2x-1.5x | 1.2x | 1+(M/N)x |
åãæ éæ£æµä¸åæ¢æºå¶
åä½åªæ¯é«å¯ç¨çåæãæäºå¤ç¨èç¹ï¼è¿éè¦åçï¼ä¸»èç¹æ¯å¦æ éäºï¼ç¡®è®¤æ éåè°æ¥æ¥ç®¡ï¼æ¥ç®¡è¿ç¨æä¹æ§è¡ï¼
å¿è·³æ£æµï¼Heartbeat Detectionï¼
å¿è·³æ£æµæ¯æåºç¡çæ éæ£æµæ¹å¼ãå¤èç¹ï¼æçæ§èç¹ï¼å®æå主èç¹å鿢æµå ï¼å¦æè¿ç» N æ¬¡æªæ¶å°ååºï¼åå¤å®ä¸»èç¹æ éã
å¿è·³æ£æµçé ç½®é常æ¶åä¸ä¸ªåæ°ï¼
- å¿è·³é´éï¼Heartbeat Intervalï¼ï¼ 两次å¿è·³ä¹é´çæ¶é´é´éãé常设置为 1-5 ç§ã
- è¶ æ¶éå¼ï¼Timeoutï¼ï¼ æªæ¶å°å¿è·³ååºçæå¤§çå¾ æ¶é´ãé常设置为å¿è·³é´éç 2-3 åã
- éè¯æ¬¡æ°ï¼Retry Countï¼ï¼ è¿ç»å¤å°æ¬¡å¿è·³å¤±è´¥åå¤å®æ éãé常设置为 3-5 次ã
以 Keepalived 为ä¾ï¼å¿è·³æ£æµçé ç½®å¦ä¸ï¼
vrrp_instance VI_1 {
state MASTER
interface eth0
virtual_router_id 51
priority 100
advert_int 1 # å¿è·³é´éï¼1 ç§
authentication {
auth_type PASS
auth_pass mypassword
}
virtual_ipaddress {
192.168.1.100/24 # VIP å°å
}
track_script {
chk_service # å
³èæå¡æ£æ¥èæ¬
}
}
vrrp_script chk_service {
script "/etc/keepalived/check_service.sh"
interval 2 # æ¯ 2 ç§æ§è¡ä¸æ¬¡æ£æ¥
weight -20 # æ£æ¥å¤±è´¥æ¶éä½ä¼å
级 20
fall 3 # è¿ç» 3 次失败å¤å®ä¸ºæ
é
rise 2 # è¿ç» 2 次æåå¤å®ä¸ºæ¢å¤
}
对åºçæå¡æ£æ¥èæ¬ï¼
#!/bin/bash
# /etc/keepalived/check_service.sh
# æ£æ¥ MySQL æ¯å¦å¯ç¨
MYSQL_HOST="127.0.0.1"
MYSQL_PORT=3306
MYSQL_USER="monitor"
MYSQL_PASS="monitor_pass"
# å°è¯æ§è¡ç®åæ¥è¯¢
mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" \
-e "SELECT 1" > /dev/null 2>&1
if [ $? -ne 0 ]; then
# MySQL ä¸å¯ç¨ï¼è¿åéé¶éåºç
exit 1
fi
# æ£æ¥å¤å¶å»¶è¿ï¼å¯éï¼
SLAVE_LAG=$(mysql -h "$MYSQL_HOST" -P "$MYSQL_PORT" -u "$MYSQL_USER" -p"$MYSQL_PASS" \
-e "SHOW SLAVE STATUS\G" 2>/dev/null | grep "Seconds_Behind_Master" | awk '{print $2}')
if [ -n "$SLAVE_LAG" ] && [ "$SLAVE_LAG" -gt 30 ]; then
# å¤å¶å»¶è¿è¶
è¿ 30 ç§ï¼å¤å®ä¸ºä¸å¥åº·
exit 1
fi
exit 0
å¿è·³æ£æµçå±éæ§ï¼ å¿è·³æ£æµåªè½æ£æµ"èç¹æ¯å¦å¯è¾¾"ï¼ä¸è½æ£æµ"æå¡æ¯å¦æ£å¸¸"ãä¸ä¸ªèç¹å¯è½ç½ç»å¯è¾¾ä½æ°æ®åºè¿ç¨å·²æï¼ä¹å¯è½æ°æ®åºè¿ç¨å¨è¿è¡ä½ä¸è½æ£å¸¸ååºæ¥è¯¢ãå æ¤ç产ç¯å¢ä½¿ç¨åºç¨çº§å«çå¥åº·æ£æ¥ââå¦ä¸é¢çèæ¬å®é æ§è¡ SQL æ¥è¯¢æ¥éªè¯ã
ä»²è£æç¥¨ï¼Quorum Votingï¼
å¿è·³æ£æµæä¸ä¸ªæ ¹æ¬é®é¢ï¼å¦æä¸»èç¹åå¤èç¹ä¹é´çç½ç»ä¸æäºï¼ä½ä¸»èç¹æ¬èº«æ¯æ£å¸¸çæä¹åï¼å¤èç¹ä¼è®¤ä¸ºä¸»èç¹æ éå¹¶å°è¯æ¥ç®¡ï¼ç»æä¸¤ä¸ªèç¹åæ¶æä¾æå¡ââèè£ã
ä»²è£æç¥¨ï¼Quorumï¼æºå¶çæ ¸å¿ææ³æ¯ï¼ä¸ä¾èµåä¸èç¹ç夿ï¼èæ¯è®©å¤ä¸ªèç¹å ±åæç¥¨å³å®æ éãåªæè·å¾å¤æ°ç¥¨ï¼Quorumï¼çèç¹ç»æè½ç»§ç»æä¾æå¡ã
Quorum ç计ç®ï¼ 对äºä¸ä¸ªç± N 个èç¹ç»æçé群ï¼Quorum = floor(N/2) + 1ãä¾å¦ï¼3 èç¹é群ç Quorum æ¯ 2ï¼5 èç¹é群ç Quorum æ¯ 3ã
工使ºå¶ï¼
- æ¯ä¸ªèç¹æç»ä¸å ¶ä»ææèç¹ä¿æå¿è·³ã
- å½æä¸ªèç¹æ£æµå°å ¶ä»èç¹ä¸å¯è¾¾æ¶ï¼å®ä¼ç»è®¡èªå·±è½èç³»å°çèç¹æ°ã
- 妿è½èç³»å°çèç¹æ°ï¼å«èªå·±ï¼â¥ Quorumï¼å认为èªå·±å¨"夿°æ´¾"ä¸ä¾§ï¼ç»§ç»æä¾æå¡ã
- 妿è½èç³»å°çèç¹æ° < Quorumï¼å认为èªå·±å¨"å°æ°æ´¾"ä¸ä¾§ï¼ä¸»å¨åæ¢æå¡ã
class QuorumChecker:
"""ä»²è£æ£æ¥å¨ï¼å¤æå½åèç¹æ¯å¦å¨å¤æ°æ´¾ä¸ä¾§"""
def __init__(self, cluster_nodes: list[str], self_node: str):
self.cluster_nodes = cluster_nodes
self.self_node = self_node
self.quorum_size = len(cluster_nodes) // 2 + 1
def check_quorum(self, reachable_nodes: set[str]) -> bool:
"""æ£æ¥å½åå¯è¾¾èç¹æ°æ¯å¦æ»¡è¶³ Quorum è¦æ±"""
# å ä¸èªå·±
reachable_count = len(reachable_nodes) + 1
has_quorum = reachable_count >= self.quorum_size
if not has_quorum:
self._step_down()
return has_quorum
def _step_down(self):
"""䏿»¡è¶³ Quorumï¼ä¸»å¨é级"""
print(f"èç¹ {self.self_node} ä¸å¨å¤æ°æ´¾ä¸ä¾§ï¼"
f"å¯è¾¾èç¹æ°ä¸è¶³ {self.quorum_size}ï¼ä¸»å¨åæ¢æå¡")
# 忢æ¥åå请æ±
# éæ¾ VIP
# è®°å½æ¥å¿
# 示ä¾ï¼3 èç¹é群
checker = QuorumChecker(
cluster_nodes=["node-1", "node-2", "node-3"],
self_node="node-1"
)
# åºæ¯ 1ï¼node-1 è½èç³»å° node-2ï¼ä¸è½èç³»å° node-3
# å¯è¾¾èç¹æ° = 2ï¼node-1 + node-2ï¼ï¼Quorum = 2ï¼æ»¡è¶³
result = checker.check_quorum(reachable_nodes={"node-2"})
print(f"Quorum æ£æ¥ç»æ: {result}") # True
# åºæ¯ 2ï¼node-1 ä¸è½èç³»å° node-2 å node-3
# å¯è¾¾èç¹æ° = 1ï¼ä»
node-1ï¼ï¼Quorum = 2ï¼ä¸æ»¡è¶³
result = checker.check_quorum(reachable_nodes=set())
print(f"Quorum æ£æ¥ç»æ: {result}") # False
Quorum ä¸èç¹æ°çå ³ç³»ï¼ 3 èç¹å®¹å¿ 1 个æ éï¼Quorum=2ï¼ï¼5 èç¹å®¹å¿ 2 个æ éï¼Quorum=3ï¼ï¼7 èç¹å®¹å¿ 3 个æ éï¼Quorum=4ï¼ãå¶æ°èç¹æ²¡æé¢å¤ä¼å¿ââ4 èç¹ç Quorum æ¯ 3ï¼åªå®¹å¿ 1 个æ éï¼å 3 èç¹ç¸åãå æ¤ Quorum é群é常使ç¨å¥æ°ä¸ªèç¹ã
Witness èç¹ï¼è§è¯èç¹ï¼
å½éç¾¤åªæ 2 个èç¹æ¶ï¼æå¸¸è§ç Active-Passive é¨ç½²ï¼ï¼æ æ³ä½¿ç¨ Quorum æç¥¨ââ两个èç¹åæä¸ç¥¨ï¼ç½ç»ååºæ¶æ æ³ååºå¤æ°æ´¾ãè§£å³æ¹æ¡æ¯å¼å ¥ç¬¬ä¸æ¹ Witnessï¼è§è¯ï¼èç¹ã
Witness èç¹ä¸æ¿è½½ä¸å¡æ°æ®ï¼åªåä¸æç¥¨ãå®çä½ç¨æ¯å¨ä¸¤ä¸ªä¸å¡èç¹æ æ³äºç¸éä¿¡æ¶ï¼å å½ä»²è£è ï¼åªä¸ªä¸å¡èç¹è½èç³»å° Witnessï¼åªä¸ªå°±è·å¾ç»§ç»æå¡çæå©ã
# Corosync é群é
置示ä¾ï¼å« Witness èç¹ï¼
totem {
version: 2
secauth: on
cluster_name: payment-db-cluster
transport: udpu
}
nodelist {
node {
ring0_addr: 10.0.1.10 # 主èç¹
name: db-primary
nodeid: 1
}
node {
ring0_addr: 10.0.1.11 # å¤èç¹
name: db-standby
nodeid: 2
}
node {
ring0_addr: 10.0.2.10 # Witness èç¹ï¼ä¸ååç½ï¼
name: witness
nodeid: 3
}
}
quorum {
provider: corosync_votequorum
expected_votes: 3
two_node: 0 # ä¸ä½¿ç¨ two_node 模å¼
}
Witness èç¹çé¨ç½²ååï¼
- Witness å¿ é¡»é¨ç½²å¨ä¸ä¸¤ä¸ªä¸å¡èç¹ä¸åçæ éåã妿䏻å¤èç¹å¨åä¸ä¸ªæºæ¿ï¼Witness åºè¯¥å¨å¦ä¸ä¸ªæºæ¿æäºå¯ç¨åºã
- Witness çç½ç»è¿æ¥åºè¯¥ç¬ç«äºä¸»å¤èç¹ä¹é´çç½ç»ãå¦å䏿¬¡ç½ç»æ éå¯è½åæ¶åæä¸»å¤éä¿¡å Witness éä¿¡ã
- Witness æ¬èº«çå¯ç¨æ§è¦æ±ä¸ä½äºä¸å¡èç¹ââ妿 Witness æ éäºï¼é群éå为 2 èç¹é群ï¼ååå°äºæ æ³ä»²è£çç¶æã
æ 鿣æµå»¶è¿åæ
仿 éåçå°å®æåæ¢çæ»æ¶é´ï¼å³å®äºç³»ç»çå®é MTTRãè¿ä¸ªè¿ç¨å¯ä»¥å解为åä¸ªé¶æ®µï¼
| é¶æ®µ | å ¸åèæ¶ | å½±åå ç´ |
|---|---|---|
| æ éåçå°å¿è·³è¶ æ¶ | 3-15 ç§ | å¿è·³é´é à éè¯æ¬¡æ° |
| ä»²è£æç¥¨å®æ | 1-5 ç§ | éç¾¤è§æ¨¡ãç½ç»å»¶è¿ |
| è§è²åæ¢ï¼VIP æ¼ç§»ãæå¡å¯å¨ï¼ | 1-10 ç§ | æå¡å¯å¨æ¶é´ãARP 广æ |
| 客æ·ç«¯è¿æ¥æ¢å¤ | 1-30 ç§ | è¿æ¥æ± è¶ æ¶ãéè¯çç¥ |
| æ»è®¡ | 6-60 ç§ |
以ä¸ä¸ªå ¸åç Keepalived + MySQL 䏻夿¶æä¸ºä¾ï¼
- å¿è·³é´é 1 ç§ï¼3 æ¬¡è¶ æ¶å¤å®æ éï¼æé¿ 3 ç§ã
- VIP æ¼ç§»ï¼å è´¹ ARP 广æï¼ï¼é常 1 ç§ä»¥å ã
- MySQL å¤èç¹æå为主ï¼å¦æä½¿ç¨å忥å¤å¶ï¼ï¼1-2 ç§ã
- åºç¨è¿æ¥æ± æ£æµå°è¿æ¥æå¼å¹¶é建ï¼åå³äºè¿æ¥æ± é ç½®ï¼é常 5-30 ç§ã
æ»åæ¢æ¶é´ï¼çº¦ 10-36 ç§ãè¿ä¸ªæ¶é´å¯¹äº 4 个 9 çå¯ç¨æ§æ¥è¯´è¶³å¤äºï¼æ¯æå 许 4.38 åéåæºï¼ï¼ä½å¯¹äºéè¦ç§çº§åæ¢çåºæ¯ï¼éè¦æ´ç§¯æçé ç½®ã
äºãèè£é®é¢ä¸ Fencing
ä»ä¹æ¯èè£
èè£ï¼Split-Brainï¼æ¯åå¸å¼ç³»ç»ä¸æå±é©çæ éä¹ä¸ãå®åçå¨ä»¥ä¸åºæ¯ï¼
é群ä¸çèç¹ä¹é´çéä¿¡ä¸æï¼ç½ç»ååºï¼ï¼ä½åèç¹æ¬èº«è¿è¡æ£å¸¸ãæ¯ä¸ä¾§çèç¹é½è®¤ä¸ºå¯¹æ¹å·²ç»æ éï¼äºæ¯åèªæå为主èç¹ï¼ç¬ç«æ¥åå请æ±ãå½ç½ç»æ¢å¤åï¼ä¸¤ä¾§çæ°æ®å·²ç»ååï¼æ æ³èªå¨åå¹¶ã
sequenceDiagram
participant C1 as 客æ·ç«¯ A
participant N1 as èç¹ 1ï¼å主ï¼
participant N2 as èç¹ 2ï¼å¤ï¼
participant C2 as 客æ·ç«¯ B
Note over N1,N2: æ£å¸¸ç¶æï¼èç¹ 1 为主ï¼èç¹ 2 为å¤
C1->>N1: åå
¥è®¢å #1001
N1->>N2: åæ¥æ°æ®
Note over N1,N2: ç½ç»ååºåç
N1--xN2: å¿è·³è¶
æ¶
N2--xN1: å¿è·³è¶
æ¶
Note over N2: èç¹ 2 å¤å®èç¹ 1 æ
éï¼èªææå为主
Note over N1: èç¹ 1 ä»å¨æ£å¸¸è¿è¡
C1->>N1: åå
¥è®¢å #1002ï¼éé¢ 100ï¼
C2->>N2: åå
¥è®¢å #1002ï¼éé¢ 200ï¼
Note over N1,N2: ç½ç»æ¢å¤
Note over N1,N2: 订å #1002 åºç°å²çªï¼<br/>èç¹ 1 è®°å½éé¢ 100<br/>èç¹ 2 è®°å½éé¢ 200
èè£çå±å®³ï¼
- æ°æ®ä¸ä¸è´ï¼ 两个主èç¹åèªæ¥ååå ¥ï¼äº§çå²çªæ°æ®ãå¯¹äºæ¯ä»ç³»ç»ï¼è¿å¯è½æå³çåä¸ç¬äº¤æè¢«å¤ç两次ã
- æ°æ®æåï¼ æäºåå¨å¼æå¨åæ¶è¢«ä¸¤ä¸ªå®ä¾åå ¥æ¶å¯è½å¯¼è´æä»¶æåï¼ä¾å¦å ±äº«åå¨åºæ¯ï¼ã
- æ¢å¤å°é¾ï¼ èè£åçæ°æ®å并没æéç¨æ¹æ¡ã人工ä»å ¥ææ¥åä¿®å¤å¯è½éè¦æ°å°æ¶çè³æ°å¤©ã
èè£çæ ¹å
èè£çæ ¹å å¯ä»¥å½ç»ä¸ºä¸å¥è¯ï¼æ æ³åºå"èç¹æ é"å"ç½ç»ååº"ã
ä»è§å¯è çè§è§çï¼"å¯¹æ¹æ²¡æååºå¿è·³"æä¸¤ç§å¯è½çè§£éï¼
- 对æ¹ç¡®å®æäºï¼èç¹æ éï¼ï¼åºè¯¥åæ¢ã
- å¯¹æ¹æ²¡æï¼åªæ¯ç½ç»æäºï¼ç½ç»ååºï¼ï¼ä¸åºè¯¥åæ¢ã
妿ä¸è½åºåè¿ä¸¤ç§æ åµå°±è´¸ç¶åæ¢ï¼å°±å¯è½äº§çèè£ã
STONITHï¼ç¡®ä¿æ éèç¹ä¸åè¿è¡
STONITHï¼Shoot The Other Node In The Headï¼ççç¥å¾ç´æ¥ï¼å¨åæ¢ä¹åï¼å ç¡®ä¿åæ¥ç主èç¹å·²ç»è¢«å½»åºå ³éãå³ä½¿ä¸ç¡®å®å®æ¯ççæ éäºè¿æ¯åªæ¯ç½ç»ä¸éï¼ç´æ¥æå®å ³æºï¼æè éå¯ï¼ï¼ç¶ååæ§è¡åæ¢ã
STONITH çå®ç°æ¹å¼ï¼
| æ¹å¼ | æºå¶ | éç¨ç¯å¢ |
|---|---|---|
| IPMI/BMC | éè¿å¸¦å¤ç®¡çæ¥å£åéå ³æºæä»¤ | ç©çæå¡å¨ |
| PDUï¼çµæºåé åå ï¼ | è¿ç¨åæç®æ æå¡å¨ççµæº | æ°æ®ä¸å¿ |
| èæå API | è°ç¨ vSphere/KVM API å ³éèææº | èæåç¯å¢ |
| äº API | è°ç¨ AWS/Azure/GCP API 忢å®ä¾ | äºç¯å¢ |
| SBDï¼Storage-Based Deathï¼ | éè¿å ±äº«åå¨ä¸ç"æ¯è¯ä¸¸"æºå¶è§¦åèªæ | å ±äº«åå¨é群 |
以 Pacemaker é群ç STONITH é 置为ä¾ï¼
# é
ç½® IPMI STONITH 设å¤
pcs stonith create ipmi-fencing fence_ipmilan \
ipaddr="10.0.1.200" \
login="admin" \
passwd="admin_pass" \
pcmk_host_list="db-primary" \
pcmk_host_check="static-list" \
power_wait="5"
# é
ç½® STONITH çç¥
pcs property set stonith-enabled=true
pcs property set stonith-action=reboot
pcs property set stonith-timeout=60s
# éªè¯ STONITH é
ç½®
pcs stonith show
pcs stonith fence db-primary --off
å¨äºç¯å¢ä¸ï¼STONITH éè¿äº API å®ç°ââè°ç¨ ec2.stop_instances(Force=True) æçä»·ç API 强å¶åæ¢ç®æ å®ä¾ï¼ç¶åéè¿ describe_instances éªè¯å®ä¾ç¡®å®å·²åæ¢ã
STONITH çäºè®®ï¼
STONITH æ¯ä¸ä¸ª"å®å¯è¯¯æï¼ä¸å¯æ¾è¿"ççç¥ãå®ç好夿¯å½»åºæ¶é¤èè£é£é©ââå主èç¹è¢«ç©çå ³æºäºï¼ä¸å¯è½åæ¥ååå ¥ãä½å®ç代价ä¹å¾ææ¾ï¼
- 妿å主èç¹å ¶å®æ¯å¥åº·çï¼åªæ¯ç½ç»æå¨å¯¼è´å¿è·³è¶ æ¶ï¼ï¼STONITH 伿ä¸ä¸ªå¥åº·çèç¹å¼ºå¶å ³æºï¼ç¶ååå忢ãè¿æå³çæ´ä¸ªéç¾¤ä» 2 个èç¹åæ 1 个èç¹ï¼ç´å°è¢«å ³æºçèç¹éæ°å¯å¨å¹¶å å ¥é群ã
- STONITH ä¾èµå¸¦å¤ç®¡çééï¼IPMIãäº APIï¼çå¯ç¨æ§ãå¦æè¯¥ééä¸å¯ç¨ï¼STONITH æ æ³æ§è¡ï¼é群ä¼é·å ¥åµå±ã
Quorum-Based æ¹æ¡
Quorum æ¹æ¡å¨åä¸èå·²ç»è®¨è®ºè¿ãå®çæ ¸å¿æ¯"å°æ°æ´¾èªæ"ï¼ç½ç»ååºåçåï¼ä¸å¨å¤æ°æ´¾ä¸ä¾§çèç¹ä¸»å¨åæ¢æå¡ãè¿æ ·å¯ä»¥ä¿è¯å¨ä»»ä½æ¶å»ï¼æå¤åªæä¸ç»èç¹å¨æä¾æå¡ã
Quorum æ¹æ¡å STONITH å¹¶ä¸äºæ¥ãç产ç¯å¢éå¸¸åæ¶ä½¿ç¨ï¼Quorum è´è´£"è°æææä¸ºä¸»"çå³çï¼STONITH è´è´£"ç¡®ä¿æ§ä¸»å·²ç»åæ¢"çæ§è¡ã
# Pacemaker éç¾¤åæ¶å¯ç¨ Quorum å STONITH
pcs property set no-quorum-policy=stop # å¤±å» Quorum æ¶åæ¢ææèµæº
pcs property set stonith-enabled=true # å¯ç¨ STONITH
# é
ç½® Quorum çç¥
# last_man_standing: éç¾¤ç¼©å°æ¶èªå¨è°æ´ expected_votes
# wait_for_all: å¯å¨æ¶çå¾
ææèç¹å å
¥
cat > /etc/corosync/corosync.conf.d/quorum.conf << 'EOF'
quorum {
provider: corosync_votequorum
expected_votes: 3
wait_for_all: 1
last_man_standing: 1
last_man_standing_window: 10000
}
EOF
Fencing çç¥çéæ©
| æ¹æ¡ | é²èè£ææ | 宿½å¤æåº¦ | éç¨åºæ¯ |
|---|---|---|---|
| STONITHï¼IPMIï¼ | 强 | ä¸ | ç©çæå¡å¨ãæ°æ®ä¸å¿ |
| STONITHï¼äº APIï¼ | 强 | ä½ | äºç¯å¢ |
| SBDï¼å卿¯è¯ä¸¸ï¼ | 强 | é« | å ±äº«åå¨é群 |
| Quorum + å°æ°æ´¾èªæ | ä¸å¼º | ä¸ | 3 èç¹å以ä¸é群 |
| Witness èç¹ | ä¸ | ä½ | 2 èç¹é群 |
| ä¸å Fencing | æ | æ | 䏿¨èç¨äºç产ç¯å¢ |
å ãVIP æ¼ç§» vs DNS 忢
æ 鿣æµå®æãä»²è£æç¥¨éè¿ä¹åï¼æå䏿¥æ¯è®©å®¢æ·ç«¯æµé忢尿°ç主èç¹ã两ç§ä¸»æµæ¹å¼æ¯ VIP æ¼ç§»å DNS 忢ã
VIP æ¼ç§»ï¼VRRP/Keepalivedï¼
VIPï¼Virtual IPï¼èæ IPï¼æ¼ç§»çåçæ¯ï¼ä¸ä¸ªèæ IP å°åä¸ç»å®å°ä»»ä½ç©çç½å¡ï¼èæ¯ç±é群管çè½¯ä»¶å¨æç»å®å°å½åç主èç¹ãå½ä¸»èç¹æ éæ¶ï¼VIP 被è¿ç§»å°æ°ç主èç¹ï¼å®¢æ·ç«¯ç»§ç»ä½¿ç¨åä¸ä¸ª IP å°åè®¿é®æå¡ã
VRRPï¼Virtual Router Redundancy Protocolï¼èæè·¯ç±åä½åè®®ï¼æ¯ VIP æ¼ç§»çæ ååè®®ãKeepalived æ¯ VRRP ç主æµå¼æºå®ç°ã
VIP æ¼ç§»çè¿ç¨ï¼
- 主èç¹ææ VIPï¼å¹¶éè¿ VRRP åè®®å®æåå¤èç¹åééåã
- å¤èç¹çå¬ VRRP éåãå¦æè¶ è¿è®¾å®æ¶é´æªæ¶å°éåï¼å¤èç¹å¤å®ä¸»èç¹æ éã
- å¤èç¹æ¥ç®¡ VIPï¼å° VIP ç»å®å°èªå·±çç½å¡ä¸ã
- å¤èç¹åéå è´¹ ARPï¼Gratuitous ARPï¼å¹¿æï¼éç¥å±åç½å ææè®¾å¤æ´æ° ARP ç¼åââ"è¿ä¸ª IP å°åç°å¨å¯¹åºç MAC å°åæ¯æç"ã
- åç»åå¾ VIP çæ°æ®å 被路ç±å°æ°ç主èç¹ã
Keepalived 宿´é 置示ä¾ï¼
# /etc/keepalived/keepalived.confï¼ä¸»èç¹ï¼
global_defs {
router_id db_primary
vrrp_skip_check_adv_addr
vrrp_garp_interval 0
vrrp_gna_interval 0
}
vrrp_script chk_mysql {
script "/etc/keepalived/check_mysql.sh"
interval 2
weight -30
fall 3
rise 2
}
vrrp_instance VI_DB {
state MASTER
interface eth0
virtual_router_id 100
priority 100
advert_int 1
nopreempt # 䏿¢å ï¼æ
鿢å¤åä¸èªå¨åå
unicast_src_ip 10.0.1.10 # 使ç¨åææ¿ä»£ç»æ
unicast_peer {
10.0.1.11
}
authentication {
auth_type PASS
auth_pass ha_secret_2024
}
virtual_ipaddress {
10.0.1.100/24 dev eth0 # VIP å°å
}
track_script {
chk_mysql
}
notify_master "/etc/keepalived/notify.sh master"
notify_backup "/etc/keepalived/notify.sh backup"
notify_fault "/etc/keepalived/notify.sh fault"
}
å¤èç¹çé
ç½®ä¸ä¸»èç¹åºæ¬ç¸åï¼å
³é®å·®å¼æ¯ state BACKUP å priority 90ï¼ä½äºä¸»èç¹ç 100ï¼ãå½ä¸»èç¹å¿è·³è¶
æ¶ï¼å¤èç¹èªå¨æ¥ç®¡ VIPãnopreempt åæ°ç¡®ä¿å主èç¹æ¢å¤åä¸ä¼èªå¨æ¢å VIPï¼é¿å
ä¸å¿
è¦çäºæ¬¡åæ¢ã
VIP æ¼ç§»çä¼ç¼ºç¹ï¼
| ä¼ç¹ | ç¼ºç¹ |
|---|---|
| 忢é度快ï¼é常 1-3 ç§ï¼ | ä» éåä¸äºå±ç½ç»ï¼åä¸åç½ï¼ |
| 对客æ·ç«¯å®å ¨éæ | è·¨æ°æ®ä¸å¿ä¸å¯ç¨ |
| ä¸ä¾èµ DNS ç¼å | äºç¯å¢æ¯ææéï¼éè¦ Elastic IPï¼ |
| å®ç°æçï¼ç»è¿å¤§éç产éªè¯ | å è´¹ ARP å¯è½è¢«ç½ç»è®¾å¤éé |
DNS 忢
DNS 忢çåçæ¯ï¼å®¢æ·ç«¯éè¿ååè®¿é®æå¡ï¼ååè§£æå°ä¸»èç¹ç IP å°åãå½ä¸»èç¹æ éæ¶ï¼ä¿®æ¹ DNS è®°å½ï¼å°ååæåæ°ä¸»èç¹ç IPã
DNS 忢çè¿ç¨ï¼
- æ£å¸¸ç¶æä¸ï¼DNS A è®°å½æå主èç¹ IPã
- æ 鿣æµç³»ç»åç°ä¸»èç¹ä¸å¯ç¨ã
- éè¿ DNS API ä¿®æ¹ A è®°å½ï¼æåå¤èç¹ IPã
- çå¾ DNS ç¼åè¿æï¼TTLï¼ï¼å®¢æ·ç«¯éæ¥åæ¢å°æ°èç¹ã
import boto3
def dns_failover(
hosted_zone_id: str,
record_name: str,
new_ip: str,
ttl: int = 30
):
"""éè¿ Route53 API æ§è¡ DNS 忢"""
client = boto3.client("route53")
response = client.change_resource_record_sets(
HostedZoneId=hosted_zone_id,
ChangeBatch={
"Comment": f"Failover to {new_ip}",
"Changes": [
{
"Action": "UPSERT",
"ResourceRecordSet": {
"Name": record_name,
"Type": "A",
"TTL": ttl,
"ResourceRecords": [
{"Value": new_ip}
]
}
}
]
}
)
return response["ChangeInfo"]["Status"]
äºååï¼å¦ AWS Route53ãé¿éäº DNSï¼è¿æ¯æåºäºå¥åº·æ£æ¥çèªå¨ DNS æ é转移ï¼é ç½®ä¸¤æ¡ Failover ç±»åçè®°å½ï¼PRIMARY å SECONDARYï¼ï¼å½ PRIMARY å¥åº·æ£æ¥å¤±è´¥æ¶ï¼DNS èªå¨è¿å SECONDARY ç IPã
TTL ä¸åæ¢å»¶è¿ï¼
DNS 忢çæå¤§é®é¢æ¯ TTLï¼Time To Liveï¼ãDNS è®°å½ç TTL å³å®äºå®¢æ·ç«¯åä¸é´ DNS æå¡å¨ç¼å该记å½çæ¶é´ãå³ä½¿ä½ å¨ 1 ç§å ä¿®æ¹äº DNS è®°å½ï¼å®¢æ·ç«¯å¯è½å¨ TTL è¿æä¹åä»ç¶ä½¿ç¨æ§ç IP å°åã
| TTL 设置 | åæ¢å»¶è¿ | DNS æ¥è¯¢è´è½½ | éç¨åºæ¯ |
|---|---|---|---|
| 300 ç§ï¼5 åéï¼ | æé¿ 5 åé | ä½ | 坹忢æ¶é´ä¸ææçåºæ¯ |
| 60 ç§ | æé¿ 1 åé | ä¸ | ä¸è¬ä¸å¡ç³»ç» |
| 30 ç§ | æé¿ 30 ç§ | ä¸é« | éè¦è¾å¿«åæ¢çåºæ¯ |
| 10 ç§ | æé¿ 10 ç§ | é« | 坹忢æ¶é´ææçåºæ¯ |
注æï¼TTL åªæ¯å»ºè®®å¼ï¼æäºå®¢æ·ç«¯åä¸é´ DNS æå¡å¨å¯è½ä¸éµå® TTLï¼ç¼åæ¶é´æ´é¿ãJava çé»è®¤ DNS ç¼åå¨æäº JVM ç
Aitishiku.com