成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

基于PostgreSQL流復制的容災庫架構(gòu)設(shè)想及實現(xiàn)

開發(fā) 架構(gòu) PostgreSQL
我們知道在PostgreSQL中,其mvcc機制并不像Oracle或者MySQL一樣,將舊版本數(shù)據(jù)存放在另外的空間中,而是通過對事務號(xid)的控制對舊版本數(shù)據(jù)不可見的方式進行實現(xiàn)。所以PostgreSQL中無法實現(xiàn)類似于Oracle的閃回機制。

 [[409992]]

本文轉(zhuǎn)載自微信公眾號「數(shù)據(jù)和云」,作者王鑫。轉(zhuǎn)載本文請聯(lián)系數(shù)據(jù)和云公眾號。

一、前言

這幾天在對PostgreSQL流復制的架構(gòu)進行深入研究,其中一個關(guān)鍵的參數(shù):recovery_min_apply_delay引起了我的注意,設(shè)置該參數(shù)的大概意思是:在進行流復制的時候,備庫會延遲主庫recovery_min_apply_delay的時間進行應用。比如說,我們在主庫上insert10條數(shù)據(jù),不會立即在備庫上生效,而是在recovery_min_apply_delay的時間后,備庫才能完成應用。

另外,我們知道在PostgreSQL中,其mvcc機制并不像Oracle或者MySQL一樣,將舊版本數(shù)據(jù)存放在另外的空間中,而是通過對事務號(xid)的控制對舊版本數(shù)據(jù)不可見的方式進行實現(xiàn)。所以PostgreSQL中無法實現(xiàn)類似于Oracle的閃回機制。

在日常操作過程中,對表進行delete、truncate、drop等誤操作都不能通過閃回來快速恢復。不怕一萬,就怕萬一,在做數(shù)據(jù)庫維護的6年多里,遇到過的誤操作還是很多。那么在PostgreSQL這種無法實現(xiàn)閃回的數(shù)據(jù)庫中,如果出現(xiàn)誤操作如何快速恢復呢?

二、架構(gòu)簡介

對于PostgreSQL數(shù)據(jù)庫這種無法進行閃回的數(shù)據(jù)庫來講,最常用的辦法就是通過備份+歸檔的方式進行數(shù)據(jù)恢復。但是這種恢復方式也有弊端,當數(shù)據(jù)庫非常大時,恢復全量備份也會非常的慢,而且如果全量備份是一周前或者更久前的,那么恢復歸檔也會需要比較長的時間。這段時間內(nèi),可能業(yè)務就會長時間停擺,造成一定的損失。

如果通過流復制延遲特性作為生產(chǎn)數(shù)據(jù)庫的容災庫,則可以從一定程度上解決該問題,其簡單架構(gòu)如下:

三、恢復步驟

PostgreSQL流復制容災庫架構(gòu)的誤操作恢復步驟如下:

1.主庫出現(xiàn)誤操作,查看流復制的replay狀態(tài);

2.在recovery_min_apply_delay時間內(nèi),暫停備庫的replay;

3.判斷主庫出現(xiàn)的誤操作類型(delete/truncate/drop);

4.根據(jù)主庫誤操作類型,對備庫進行相應的操作;

5.通過pg_dump將誤操作表導出;

6.在主庫對pg_dump出的表進行恢復。

假設(shè)當前備庫與主庫相差10min,則誤操作可以分為以下兩個場景:

1)delete操作:

首先我們需要知道的是,針對delete操作,PostgreSQL會給相關(guān)表加一個ROW EXCLUSIVE鎖,而該鎖不會對select等dql操作進行阻塞。

所以當我們在主庫進行delete誤操作后,備庫則會晚10min中進行replay。且此時可以對該表進行查詢和pg_dump的導出。針對于主庫delete誤操作,恢復步驟如下:

第一步,查看流復制replay的狀態(tài),重點關(guān)注replay_lsn字段:

  1. select * from pg_stat_replication; 
  2. postgres=# select * from pg_stat_replication; 
  3. -[ RECORD 1 ]----+------------------------------ 
  4. pid              | 55694 
  5. usesysid         | 24746 
  6. usename          | repl 
  7. application_name | walreceiver 
  8. client_addr      | 192.168.18.82 
  9. client_hostname  |  
  10. client_port      | 31550 
  11. backend_start    | 2021-01-20 09:54:57.039779+08 
  12. backend_xmin     |  
  13. state            | streaming 
  14. sent_lsn         | 6/D2A17120 
  15. write_lsn        | 6/D2A17120 
  16. flush_lsn        | 6/D2A17120 
  17. replay_lsn       | 6/D2A170B8 
  18. write_lag        | 00:00:00.000119 
  19. flush_lag        | 00:00:00.000239 
  20. replay_lag       | 00:00:50.653858 
  21. sync_priority    | 0 
  22. sync_state       | async 
  23. reply_time       | 2021-01-20 14:11:31.704194+08 

此時可以發(fā)現(xiàn)數(shù)據(jù)庫中的replay_lsn字段的lsn值要比sent_lsn/write_lsn/flush_lsn都要小;

第二步,為了防止處理或者導出時間過慢而導致的數(shù)據(jù)同步,立即暫停備庫的replay:

  1. select * from pg_wal_replay_pause(); 

查看同步狀態(tài):

  1. postgres=# select * from pg_is_wal_replay_paused();   
  2.  
  3.  pg_is_wal_replay_paused  
  4. ------------------------- 
  5.  t 
  6. (1 row) 

第三步,在備庫查看數(shù)據(jù)是否存在:

  1. select * from wangxin1; 

第四步,通過pg_dump,將表內(nèi)容導出:

  1. pg_dump -h 192.168.18.182 -p 18802 -d postgres -U postgres -t wangxin1 --data-only --inserts -f wangxin1_data_only.sql 

第五步,在主庫執(zhí)行sql文件,將數(shù)據(jù)重新插入:

  1. psql -p 18801 
  2. \i wangxin1_data_only.sql 

恢復即完成。

2)truncate和drop:

這里首先需要知道的是,truncate和drop操作會給表加上一個access exclusive鎖,該類型鎖是PostgreSQL數(shù)據(jù)庫中最嚴重的鎖。如果表上有該鎖,則會阻止所有對該此表的訪問操作,其中也包括select和pg_dump操作。

所以說,在我們對主庫中的某張表進行truncate或者drop后,同樣,備庫會由于recovery_min_apply_delay參數(shù)比主庫晚完成truncate或drop動作10min(從參數(shù)理論上是這樣理解的,但實際并不是)。

那么針對truncate和drop的恢復過程我們也參考delete的方式來進行:

  1. -[ RECORD 2 ]----+------------------------------ 
  2. pid              | 67008 
  3. usesysid         | 24746 
  4. usename          | repl 
  5. application_name | walreceiver 
  6. client_addr      | 192.168.18.82 
  7. client_hostname  |  
  8. client_port      | 32122 
  9. backend_start    | 2021-01-20 23:33:05.538858+08 
  10. backend_xmin     |  
  11. state            | streaming 
  12. sent_lsn         | 7/3F0593E0 
  13. write_lsn        | 7/3F0593E0 
  14. flush_lsn        | 7/3F0593E0 
  15. replay_lsn       | 7/3F059330 
  16. write_lag        | 00:00:00.000141 
  17. flush_lag        | 00:00:00.000324 
  18. replay_lag       | 00:00:11.471699 
  19. sync_priority    | 0 
  20. sync_state       | async 
  21. reply_time       | 2021-01-20 23:33:58.303686+08 

接下來,為防止處理或?qū)С鰰r間過慢而導致的數(shù)據(jù)同步,應立即暫停備庫的replay:

  1. select * from pg_wal_replay_pause(); 

查看同步狀態(tài):

  1. postgres=# select * from pg_is_wal_replay_paused();   
  2.  
  3.  pg_is_wal_replay_paused  
  4. ------------------------- 
  5.  t 
  6. (1 row) 

接著,在備庫查看數(shù)據(jù)是否存在:

  1. select * from wangxin1; 

但是,此時就會發(fā)現(xiàn)問題:數(shù)據(jù)無法select出來,整個select進程會卡住(pg_dump也一樣):

  1. ^CCancel request sent 
  2. ERROR:  canceling statement due to user request 

此時,可以對備庫上的鎖信息進行查詢:

  1. select s.pid, 
  2. s.datname, 
  3. s.usename, 
  4. l.relation::regclass, 
  5. s.client_addr, 
  6. now()-s.query_start, 
  7. s.wait_event, 
  8. s.wait_event_type, 
  9. l.granted, 
  10. l.mode, 
  11. s.query 
  12. from pg_stat_activity s ,pg_locks l 
  13. where s.pid<>pg_backend_pid() 
  14. and s.pid=l.pid; 
  15.  
  16.   pid  | datname | usename | relation | client_addr | ?column? |     wait_event     | wait_event_type | granted |        mode         | query  
  17. -------+---------+---------+----------+-------------+----------+--------------------+-----------------+---------+---------------------+------- 
  18.  55689 |         |         |          |             |          | RecoveryApplyDelay | Timeout         | t       | ExclusiveLock       |  
  19.  55689 |         |         | wangxin1 |             |          | RecoveryApplyDelay | Timeout         | t       | AccessExclusiveLock |  
  20. (2 rows

發(fā)現(xiàn)此時truncate的表被鎖住了,而pid進程則是備庫的recover進程,所以此時我們根本無法訪問該表,也就無法做pg_dump操作了。

因此,想要恢復則必須想辦法將數(shù)據(jù)庫還原到鎖表之前的操作。于是對PostgreSQL的wal日志進行分析查看:

  1. pg_waldump -p /pgdata/pg_wal -s 7/3F000000 
  2.  
  3. rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 7/3F050D70, prev 7/3F050D40, desc: RUNNING_XACTS nextXid 13643577 latestCompletedXid 13643576 oldestRunningXid 13643577 
  4. rmgr: Heap2       len (rec/tot):     60/    60, tx:   13643577, lsn: 7/3F050DA8, prev 7/3F050D70, desc: NEW_CID rel 1663/13593/2619; tid 20/27; cmin: 4294967295, cmax: 0, combo: 4294967295 
  5. rmgr: Heap2       len (rec/tot):     60/    60, tx:   13643577, lsn: 7/3F050DE8, prev 7/3F050DA8, desc: NEW_CID rel 1663/13593/2619; tid 20/23; cmin: 0, cmax: 4294967295, combo: 4294967295 
  6. rmgr: Heap        len (rec/tot):     65/  6889, tx:   13643577, lsn: 7/3F050E28, prev 7/3F050DE8, desc: HOT_UPDATE off 27 xmax 13643577 flags 0x00 ; new off 23 xmax 0, blkref #0: rel 1663/13593/2619 blk 20 FPW 
  7. rmgr: Heap2       len (rec/tot):     60/    60, tx:   13643577, lsn: 7/3F052930, prev 7/3F050E28, desc: NEW_CID rel 1663/13593/2619; tid 20/28; cmin: 4294967295, cmax: 0, combo: 4294967295 
  8. rmgr: Heap2       len (rec/tot):     60/    60, tx:   13643577, lsn: 7/3F052970, prev 7/3F052930, desc: NEW_CID rel 1663/13593/2619; tid 20/24; cmin: 0, cmax: 4294967295, combo: 4294967295 
  9. rmgr: Heap        len (rec/tot):     76/    76, tx:   13643577, lsn: 7/3F0529B0, prev 7/3F052970, desc: HOT_UPDATE off 28 xmax 13643577 flags 0x20 ; new off 24 xmax 0, blkref #0: rel 1663/13593/2619 blk 20 
  10. rmgr: Heap        len (rec/tot):     53/  7349, tx:   13643577, lsn: 7/3F052A00, prev 7/3F0529B0, desc: INPLACE off 13, blkref #0: rel 1663/13593/1259 blk 1 FPW 
  11. rmgr: Transaction len (rec/tot):    130/   130, tx:   13643577, lsn: 7/3F0546D0, prev 7/3F052A00, descCOMMIT 2021-01-20 23:31:23.009466 CST; inval msgs: catcache 58 catcache 58 catcache 50 catcache 49 relcache 24780 
  12. rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 7/3F054758, prev 7/3F0546D0, desc: RUNNING_XACTS nextXid 13643578 latestCompletedXid 13643577 oldestRunningXid 13643578 
  13. rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 7/3F054790, prev 7/3F054758, desc: RUNNING_XACTS nextXid 13643578 latestCompletedXid 13643577 oldestRunningXid 13643578 
  14. rmgr: XLOG        len (rec/tot):    114/   114, tx:          0, lsn: 7/3F0547C8, prev 7/3F054790, desc: CHECKPOINT_ONLINE redo 7/3F054790; tli 1; prev tli 1; fpw true; xid 0:13643578; oid 33072; multi 1; offset 0; oldest xid 479 in DB 1; oldest multi 1 in DB 1; oldest/newest commit timestamp xid: 0/0; oldest running xid 13643578; online 
  15. rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 7/3F054840, prev 7/3F0547C8, desc: RUNNING_XACTS nextXid 13643578 latestCompletedXid 13643577 oldestRunningXid 13643578 
  16. rmgr: Standby     len (rec/tot):     42/    42, tx:   13643578, lsn: 7/3F054878, prev 7/3F054840, desc: LOCK xid 13643578 db 13593 rel 24780  
  17. rmgr: Storage     len (rec/tot):     42/    42, tx:   13643578, lsn: 7/3F0548A8, prev 7/3F054878, descCREATE base/13593/24885 
  18. rmgr: Heap2       len (rec/tot):     60/    60, tx:   13643578, lsn: 7/3F0548D8, prev 7/3F0548A8, desc: NEW_CID rel 1663/13593/1259; tid 1/13; cmin: 4294967295, cmax: 0, combo: 4294967295 
  19. rmgr: Heap2       len (rec/tot):     60/    60, tx:   13643578, lsn: 7/3F054918, prev 7/3F0548D8, desc: NEW_CID rel 1663/13593/1259; tid 1/14; cmin: 0, cmax: 4294967295, combo: 4294967295 
  20. rmgr: Heap        len (rec/tot):     65/  7537, tx:   13643578, lsn: 7/3F054958, prev 7/3F054918, descUPDATE off 13 xmax 13643578 flags 0x00 ; new off 14 xmax 0, blkref #0: rel 1663/13593/1259 blk 1 FPW 
  21. rmgr: Heap2       len (rec/tot):     76/    76, tx:   13643578, lsn: 7/3F0566E8, prev 7/3F054958, desc: CLEAN remxid 13642576, blkref #0: rel 1663/13593/1259 blk 1 
  22. rmgr: Btree       len (rec/tot):     53/  3573, tx:   13643578, lsn: 7/3F056738, prev 7/3F0566E8, desc: INSERT_LEAF off 141, blkref #0: rel 1663/13593/2662 blk 2 FPW 
  23. rmgr: Btree       len (rec/tot):     53/  5349, tx:   13643578, lsn: 7/3F057530, prev 7/3F056738, desc: INSERT_LEAF off 117, blkref #0: rel 1663/13593/2663 blk 2 FPW 
  24. rmgr: Btree       len (rec/tot):     53/  2253, tx:   13643578, lsn: 7/3F058A30, prev 7/3F057530, desc: INSERT_LEAF off 108, blkref #0: rel 1663/13593/3455 blk 4 FPW 
  25. rmgr: Heap        len (rec/tot):     42/    42, tx:   13643578, lsn: 7/3F059300, prev 7/3F058A30, descTRUNCATE nrelids 1 relids 24780 
  26. rmgr: Transaction len (rec/tot):    114/   114, tx:   13643578, lsn: 7/3F059330, prev 7/3F059300, descCOMMIT 2021-01-20 23:33:46.831804 CST; rels: base/13593/24884; inval msgs: catcache 50 catcache 49 relcache 24780 
  27. rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 7/3F0593A8, prev 7/3F059330, desc: RUNNING_XACTS nextXid 13643579 latestCompletedXid 13643578 oldestRunningXid 13643579 
  28. rmgr: Standby     len (rec/tot):     50/    50, tx:          0, lsn: 7/3F0593E0, prev 7/3F0593A8, desc: RUNNING_XACTS nextXid 13643579 latestCompletedXid 13643578 oldestRunningXid 13643579 
  29. rmgr: XLOG        len (rec/tot):    114/   114, tx:          0, lsn: 

從wal日志的分析中,可以非常明顯的看到,在最后一次checkpoint點后(恢復的起始點),正常來說,數(shù)據(jù)庫會繼續(xù)執(zhí)行l(wèi)sn為7/3F054840的步驟開啟事務,并在下一步lsn為7/3F054878的步驟直接對oid為24780(通過oid2name可以知道,這張表就是我們誤操作表)的表進行l(wèi)ock操作,做一系列相關(guān)的操作后,進行了truncate,最后進行commit操作。

而這一系列操作,我們則可以認為是truncate一張表的正常操作。

由于我們知道checkpoint點是數(shù)據(jù)庫的恢復起始點,那么我們是否可以將數(shù)據(jù)庫恢復到這一點的lsn呢?此時的lsn肯定不會對表進行l(wèi)ock操作,那么我們就可以對該表進行pg_dump操作了。

想法是好的,但是實際操作則沒那么順利。我們可以通過對備庫PostgreSQL的配置文件進行修改,加入?yún)?shù):

  • recovery_target_lsn= ‘7/3F0547C8’
  • recovery_target_action= ‘pause’

重啟數(shù)據(jù)庫。

此時卻發(fā)現(xiàn)數(shù)據(jù)庫無法啟動,通過對日志查看,發(fā)現(xiàn)原因竟然是:

這個恢復點,是一致性恢復點之前的點,所以無法正常恢復。

此時就出現(xiàn)了令我們奇怪的點,我們知道checkpoint的兩個主要作用是:將臟數(shù)據(jù)進行刷盤;將wal日志的checkpoint進行記錄。此時,肯定是數(shù)據(jù)庫一致的點,但是為什么會報不一致呢?

經(jīng)過一點一點的嘗試,發(fā)現(xiàn)能夠恢復的lsn點,只有truncate或者drop的commit操作的前面。那么這樣我們還是無法對誤操作表進行解鎖。

最后,只能通過一種方式,即pg_resetwal的方式,強制指定備庫恢復到我們想要的lsn點:

pg_resetwal -D data1 -x 559 Write-ahead log reset

再進行pg_dump即可。

但是,此時PostgreSQL的主備流復制關(guān)系已經(jīng)被破壞,只能重新搭建或者以其他方式進行恢復(比如pg_rewind)。

四、問題分析

再次返回到進行truncate或drop的恢復步驟中,我們可以發(fā)現(xiàn)一個問題,為什么在checkpoint點后、truncate點前,無法將數(shù)據(jù)庫恢復到一致點呢?為什么會報錯呢?

按照常理來講,checkpoint點就是恢復數(shù)據(jù)庫的起始點,也是一致點,但是卻無法恢復了。

繼續(xù)進行詳細的探究后發(fā)現(xiàn)一個現(xiàn)象:

延遲流復制過程中,我們配置了recovery_min_apply_delay參數(shù),對源端數(shù)據(jù)庫做truncate后,備庫replay的lsn,停留在truncate表后的commit操作。而從主庫的pg_stat_replication的replay_lsn值來看,此時備庫的recover進程,應該就是在執(zhí)行最后的commit的lsn;

更形象的來說,此時備庫類似于我執(zhí)行以下命令:

  1. begin
  2.  
  3. truncate table

也就是說,此時我并沒有提交,而備庫也正在等待我進行提交,所以此時誤操作表會被鎖定。

但實際上,truncate table這個動作,已經(jīng)在我的備庫上進行了replay,只是最后的commit動作沒有進行replay。因此,對于truncate動作之前所有l(wèi)sn的操作已經(jīng)是我當前數(shù)據(jù)庫狀態(tài)的一個過去式,無法恢復了,故會報錯。

為了驗證想法,在大佬的幫助下,又對PostgreSQL的源碼進行查看,發(fā)現(xiàn)猜想原因確實沒錯:

在/src/backend/access/transam/xlog.c中,對于recovery_min_apply_delay參數(shù)有以下的一段描述:

  1. /* 
  2. Is it a COMMIT record? 
  3. * We deliberately choose not to delay aborts since they have no effect on 
  4. * MVCC. We already allow replay of records that don't have a timestamp
  5. * so there is already opportunity for issues caused by early conflicts on 
  6. * standbys. 
  7. */ 

大概意思是,當record中沒有時間戳(timestamp)的時候,數(shù)據(jù)庫就已經(jīng)進行了replay。replay只會等待有時間戳的record,而所有的record中,只有commit操作有時間戳,故replay會等待一個commit操作。

不過在實際的生產(chǎn)環(huán)境中,我們通常會把recovery_min_apply_delay參數(shù)設(shè)置的較大,而在這之間,一般都會有一些其他的事務進行操作,當主庫出現(xiàn)誤操作(哪怕說truncate/drop),只要及時發(fā)現(xiàn),我們可以暫停replay的步驟,停在正常的事務操作下,此時誤操作的表的事務還沒有執(zhí)行,那么這個容災庫還是比較有作用的。

 

責任編輯:武曉燕 來源: 數(shù)據(jù)和云
相關(guān)推薦

2022-09-12 07:59:13

操作系統(tǒng)LVM模式

2022-01-10 07:59:14

PostgreSQl 主從流復制歸檔配置

2023-01-10 10:06:18

數(shù)據(jù)備份

2017-06-26 08:28:41

PostgreSQL數(shù)據(jù)庫單機

2017-09-22 10:05:48

Redis備份容災

2020-03-16 12:39:47

容災備份規(guī)劃

2013-12-30 16:00:37

華為OceanStor虛擬化容災

2009-01-13 17:38:10

2021-07-14 23:38:02

PostgreSQLOracle模式

2016-05-24 17:48:04

可用區(qū) Sixsho

2010-04-22 17:17:44

Oracle遠程復制

2017-01-12 17:22:34

2023-03-01 07:42:12

HBase編排部署數(shù)據(jù)

2020-02-07 15:12:13

容災技術(shù)構(gòu)建平臺

2023-03-19 11:53:27

2019-09-06 08:53:32

數(shù)據(jù)庫高可用容災

2013-11-13 13:53:51

華為云容災集約化容災

2009-01-06 13:40:26

服務器存儲備份

2017-10-26 09:22:26

2018-09-26 10:20:31

高可用容災指標
點贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 综合色站导航 | 在线亚洲一区二区 | 亚洲国产福利视频 | 欧美亚洲另类在线 | 国产精品久久久久久久模特 | 欧美 日韩 国产 一区 | 99精品国自产在线 | 91av视频在线观看 | 一级欧美| 性一交一乱一透一a级 | 国产精品1区 | 久久精品亚洲精品国产欧美 | 粉嫩一区二区三区性色av | 看羞羞视频免费 | 午夜男人免费视频 | 国产精品成人一区二区三区 | 久久久久久久久久久一区二区 | 国产日韩在线观看一区 | 91亚洲国产成人久久精品网站 | 毛片久久久 | 91色视频在线观看 | 99亚洲| 在线观看www高清视频 | www亚洲精品| 久久国产精品免费一区二区三区 | 久久精品国产一区老色匹 | 亚洲一在线 | 久久99精品国产麻豆婷婷 | av在线免费观看网址 | av日日操 | 中文字幕在线第二页 | 亚洲一区二区三区四区五区午夜 | 一区二区三区国产 | 国产精品一区二区三 | 老司机67194精品线观看 | 91免费福利在线 | 日日干天天操 | 视频在线一区二区 | 亚洲国产精品第一区二区 | 在线观看中文字幕dvd播放 | 欧美黑人一区 |