Chuyển đến nội dung chính

レッスン 10: レプリケーション管理

同期/非同期レプリカ、synchronous_mode、synchronous_node_count を構成し、クラスター内のレプリケーション ラグを監視します。

🔒 DevSecOps — レッスン 10 レッスン 10: レプリケーション管理__HTMLTAG_53___

Patroni と PostgreSQL の高可用性etcd

パート 3: クラスター管理

xdev.asia_

目標_

このレッスンの後、次のことを学びます:

  • Patroni クラスターのブートストラップ プロセスを理解する_
  • 3 ノードで初めて Patroni を起動_
  • クラスターのステータスを確認するpatronictl
  • レプリケーションがアクティブであることを確認__HTMLTAG_77___
  • 一般的な問題のトラブルシューティング__HTMLTAG_79___
  • 基本的なフェールオーバーをテスト

1。ブートストラップ前チェックリスト

1.1。前提条件の確認

Patroni を開始する前に、すべてのコンポーネントの準備ができていることを確認してください:

# ✅ etcd cluster healthy
etcdctl endpoint health --cluster

All endpoints should be healthy

✅ PostgreSQL installed nhưng NOT running

systemctl status postgresql

Should be: inactive (dead)

✅ Patroni installed

patroni --version

Should show: patroni 3.2.0+

✅ Config file exists và valid

sudo -u postgres cat /etc/patroni/patroni.yml python3 -c "import yaml; yaml.safe_load(open('/etc/patroni/patroni.yml'))"

✅ Data directory exists với permissions đúng

ls -ld /var/lib/postgresql/18/data

Owner: postgres:postgres, Permissions: drwx------

✅ Firewall rules

sudo ufw status | grep -E "(5432|8008)"

Ports 5432, 8008 should be allowed

1.2。ネットワーク接続テスト

ノード間の接続を確認します:

# Test PostgreSQL port
nc -zv 10.0.1.11 5432
nc -zv 10.0.1.12 5432
nc -zv 10.0.1.13 5432

Test Patroni REST API port

nc -zv 10.0.1.11 8008 nc -zv 10.0.1.12 8008 nc -zv 10.0.1.13 8008

Test etcd port

nc -zv 10.0.1.11 2379 nc -zv 10.0.1.12 2379 nc -zv 10.0.1.13 2379

1.3。データ ディレクトリをクリーンアップ

データ ディレクトリが空でない場合は、削除して最初からやり直します:

# CẢNH BÁO: Chỉ làm khi bootstrap lần đầu
sudo systemctl stop patroni
sudo rm -rf /var/lib/postgresql/18/data/*
sudo chown postgres:postgres /var/lib/postgresql/18/data

2。ブートストラップ プロセスを理解する_

2.1。ブートストラップ フロー

Step 1: Start Patroni trên Node 1
↓
Node 1 checks DCS: No cluster exists
↓
Node 1 acquires initialize key
↓
Node 1 runs pg_initdb
↓
Node 1 starts PostgreSQL as PRIMARY
↓
Node 1 creates replication user
↓
Node 1 stores cluster config in DCS
↓
Node 1 acquires leader lock

Step 2: Start Patroni trên Node 2 ↓ Node 2 checks DCS: Cluster exists ↓ Node 2 sees Node 1 is leader ↓ Node 2 runs pg_basebackup from Node 1 ↓ Node 2 starts PostgreSQL as REPLICA ↓ Node 2 connects to Node 1 for replication

Step 3: Start Patroni trên Node 3 ↓ Node 3 checks DCS: Cluster exists ↓ Node 3 sees Node 1 is leader ↓ Node 3 runs pg_basebackup from Node 1 ↓ Node 3 starts PostgreSQL as REPLICA ↓ Node 3 connects to Node 1 for replication

Final State: ┌─────────┐ ┌─────────┐ ┌─────────┐ │ Node 1 │────────→│ Node 2 │ │ Node 3 │ │ PRIMARY │ │ REPLICA │←────────│ REPLICA │ └─────────┘ └─────────┘ └─────────┘ Leader Streaming Streaming

2.2。競合状態の防止

Patroni は DCS を使用して、複数のノードがクラスターを初期化するのを防ぎます:

# In etcd
/service/postgres/initialize: "node1"  # First node acquires this
/service/postgres/leader: {...}        # Leader lock

2 つのノードが同時に開始する場合:

  • 高速ノード/initialize key
  • を取得します。他のノードはキーがすでに存在することを確認します。→待機して、リーダー

3からクローンを作成します。ブートストラップ クラスター - ステップバイステップ

3.1。ノード 1 で Patroni を開始

ノード 1 のターミナル:

# Start Patroni service
sudo systemctl start patroni

Watch logs

sudo journalctl -u patroni -f

予想通りログ:

INFO: No initialize key found in DCS
INFO: Trying to bootstrap a new cluster
INFO: Acquiring initialize key
INFO: Initializing a new cluster
INFO: Running initdb: /usr/lib/postgresql/18/bin/initdb ...
INFO: postmaster pid: 12345
INFO: PostgreSQL started
INFO: Running post_bootstrap script
INFO: Creating replication user
INFO: Lock owner: node1; I am node1
INFO: Leader election acquired
INFO: I am the leader with the lock

ノード 1 を確認:HTMLTAG_132__CODEBLOCK_7

3.2。 etcd_

# Check leader key
etcdctl get /service/postgres/leader --print-value-only | jq

Output:

{

"role": "master",

"state": "running",

"conn_url": "postgres://10.0.1.11:5432/postgres",

"api_url": "http://10.0.1.11:8008/patroni",

"xlog_location": 50331648,

"timeline": 1

}

Check members

etcdctl get /service/postgres/members/ --prefix

Should show node1

3.3 で確認します。ノード 2 で Patroni を開始

ノード 2 でターミナル:

# Start Patroni
sudo systemctl start patroni

Watch logs

sudo journalctl -u patroni -f

予想通りログ:

INFO: Cluster already initialized
INFO: Found leader: node1
INFO: Trying to clone from leader
INFO: Running: pg_basebackup -D /var/lib/postgresql/18/data ...
INFO: Basebackup completed
INFO: Starting PostgreSQL
INFO: postmaster pid: 12346
INFO: Configuring standby mode
INFO: Following new leader: node1
INFO: Replication established

ノード 2 を確認:

# Check if it's REPLICA
sudo -u postgres psql -c "SELECT pg_is_in_recovery();"

pg_is_in_recovery

------------------

t ← true = REPLICA

Check replication status

sudo -u postgres psql -c "SELECT * FROM pg_stat_wal_receiver;" -x

3.4。ノード 3 で Patroni を開始

ノード 3 のターミナル:

# Start Patroni
sudo systemctl start patroni

Watch logs

sudo journalctl -u patroni -f

予想されるログ: ノードに類似2._

ノード 3:

# Check replica status
sudo -u postgres psql -c "SELECT pg_is_in_recovery();"

Should return: t (true)

4 を確認します。クラスターのステータス

4.1 を確認します。 patronictl の使用_

# List cluster members
patronictl -c /etc/patroni/patroni.yml list

Output:

+ Cluster: postgres (7001234567890123456) ----+----+-----------+

| Member | Host | Role | State | TL | Lag in MB |

+--------+---------------+---------+---------+----+-----------+

| node1 | 10.0.1.11:5432| Leader | running | 1 | |

| node2 | 10.0.1.12:5432| Replica | running | 1 | 0 |

| node3 | 10.0.1.13:5432| Replica | running | 1 | 0 |

+--------+---------------+---------+---------+----+-----------+

列の意味:

  • メンバー: ノード名前_
  • ホスト: 接続アドレス
  • 役割: リーダー (プライマリ) またはレプリカ_
  • 状態: 実行中、ストリーミング、アーカイブ回復中
  • TL: タイムライン (すべて同じである必要があります)
  • MB のラグ: レプリケーションラグ_

4.2。トポロジを確認

patronictl -c /etc/patroni/patroni.yml topology postgres

Output shows replication tree

4.3。 REST API

# Check node1 (primary)
curl -s http://10.0.1.11:8008/ | jq

Output:

{

"state": "running",

"postmaster_start_time": "2024-11-24 10:30:15.123+00",

"role": "master",

"server_version": 180000,

"cluster_unlocked": false,

"xlog": {

"location": 50331648

},

"timeline": 1,

"database_system_identifier": "7001234567890123456"

}

Check node2 (replica)

curl -s http://10.0.1.12:8008/ | jq

Check node3 (replica)

curl -s http://10.0.1.13:8008/ | jq

4.4 の使用。 PostgreSQL からのレプリケーションを確認_

プライマリ (ノード 1) 上:

sudo -u postgres psql -c "SELECT * FROM pg_stat_replication;" -x

出力:

-[ RECORD 1 ]----+------------------------------
pid              | 12350
usesysid         | 16384
usename          | replicator
application_name | node2
client_addr      | 10.0.1.12
client_hostname  |
client_port      | 45678
backend_start    | 2024-11-24 10:31:00.123+00
backend_xmin     |
state            | streaming
sent_lsn         | 0/3000000
write_lsn        | 0/3000000
flush_lsn        | 0/3000000
replay_lsn       | 0/3000000
write_lag        |
flush_lag        |
replay_lag       |
sync_state       | async
sync_priority    | 0
reply_time       | 2024-11-24 10:35:00.456+00

-[ RECORD 2 ]----+------------------------------ pid | 12351 usesysid | 16384 usename | replicator application_name | node3 ...

レプリカ上 (ノード 2、ノード3):

sudo -u postgres psql -c "SELECT status, received_lsn, latest_end_lsn FROM pg_stat_wal_receiver;" -x

4.5。レプリケーション ラグ

# On primary
sudo -u postgres psql -c "
SELECT
application_name,
client_addr,
state,
pg_wal_lsn_diff(pg_current_wal_lsn(), replay_lsn) AS lag_bytes,
replay_lag
FROM pg_stat_replication;
"

Output:

application_name | client_addr | state | lag_bytes | replay_lag

-----------------+-------------+-----------+-----------+------------

node2 | 10.0.1.12 | streaming | 0 |

node3 | 10.0.1.13 | streaming | 0 |

5 を確認します。基本操作

5.1 をテストします。テスト データベースとテーブルを作成します

プライマリで (任意のノードに接続すると、patronictl はプライマリにルーティングします):

# Create database
sudo -u postgres psql -h 10.0.1.11 -c "CREATE DATABASE testdb;"

Create table with data

sudo -u postgres psql -h 10.0.1.11 -d testdb << EOF CREATE TABLE test_table ( id SERIAL PRIMARY KEY, data TEXT, created_at TIMESTAMP DEFAULT NOW() );

INSERT INTO test_table (data) SELECT 'Test data ' || i FROM generate_series(1, 1000) AS i; EOF

5.2。レプリケーションを確認します

レプリケーション時 (ノード 2 またはノード 3):

# Check data replicated
sudo -u postgres psql -h 10.0.1.12 -d testdb -c "SELECT COUNT(*) FROM test_table;"

Should return: 1000

Try to write (should fail on replica)

sudo -u postgres psql -h 10.0.1.12 -d testdb -c "INSERT INTO test_table (data) VALUES ('test');"

ERROR: cannot execute INSERT in a read-only transaction

5.3。継続的レプリケーションのテスト

ターミナル 1 (プライマリ - ノード 1):

# Insert data continuously
while true; do
sudo -u postgres psql -h 10.0.1.11 -d testdb -c 
"INSERT INTO test_table (data) VALUES ('Data at ' || NOW());" sleep 1 done

ターミナル 2 (レプリカ -ノード 2):

# Watch count increase
watch -n 1 "sudo -u postgres psql -h 10.0.1.12 -d testdb -t -c 'SELECT COUNT(*) FROM test_table;'"

データは毎秒増加するはずです → レプリケーションは動作しています!

6。ブートストラップの一般的な問題_

6.1。問題: Patroni が起動しない

症状:

sudo systemctl status patroni

Failed to start

確認してくださいログ_:

sudo journalctl -u patroni -n 50 --no-pager

一般的な原因と問題ソリューション:

A。構成ファイルの構文エラー

ERROR: Error parsing config file

解決策:

# Validate YAML
python3 -c "import yaml; yaml.safe_load(open('/etc/patroni/patroni.yml'))"

Common issues:

- Mixed tabs and spaces (use spaces only)

- Incorrect indentation

- Missing quotes around special characters

B。 etcd

ERROR: Failed to connect to etcd

Solution:

# Check etcd is running
etcdctl endpoint health

Check etcd endpoints in patroni.yml

grep "hosts:" /etc/patroni/patroni.yml

Test connectivity

curl http://10.0.1.11:2379/version

C に接続できません。データ ディレクトリ_

ERROR: data directory has wrong ownership

Solution:

sudo chown -R postgres:postgres /var/lib/postgresql/18/data
sudo chmod 700 /var/lib/postgresql/18/data

D。ポートはすでに使用されています

ERROR: could not bind IPv4 address "0.0.0.0": Address already in use

解決策:_

# Check what's using port 5432
sudo lsof -i :5432

Stop PostgreSQL if running

sudo systemctl stop postgresql

Kill process if needed

sudo pkill -9 postgres

6.2。問題: クラスターが初期化されません

症状: Patroni は起動しますが、クラスターが初期化されません。

Checkログ:

sudo journalctl -u patroni -f

一般的な原因:

A。データ ディレクトリが空ではありません_

INFO: Data directory is not empty

解決策:_

# Backup old data if needed
sudo mv /var/lib/postgresql/18/data /var/lib/postgresql/18/data.bak

Create fresh directory

sudo mkdir -p /var/lib/postgresql/18/data sudo chown postgres:postgres /var/lib/postgresql/18/data sudo chmod 700 /var/lib/postgresql/18/data

Restart Patroni

sudo systemctl restart patroni

B。 etcd

INFO: Another node is initializing

Solutio でスタックしたキーを初期化しますn:

# Check initialize key
etcdctl get /service/postgres/initialize

If stuck, delete it

etcdctl del /service/postgres/initialize

Restart Patroni

sudo systemctl restart patroni

6.3。問題: レプリカがプライマリからクローンを作成できない

症状: ノード 2 または 3 がベースバックアップを作成できません。

Checkログ:

sudo journalctl -u patroni -n 100 | grep -i basebackup

一般的な原因:

A。ネットワーク接続_

ERROR: could not connect to server

ソリューション:_

# Test connectivity
telnet 10.0.1.11 5432

Check firewall

sudo ufw status sudo ufw allow from 10.0.1.0/24 to any port 5432

B。認証に失敗しました

ERROR: FATAL: password authentication failed for user "replicator"

解決策:_

# Verify replication user exists on primary
sudo -u postgres psql -h 10.0.1.11 -c "\du replicator"

Check pg_hba.conf allows replication

sudo -u postgres psql -h 10.0.1.11 -c "SHOW hba_file;"

Then check the file

Verify password matches in patroni.yml

grep -A2 "replication:" /etc/patroni/patroni.yml

C。スペースが不十分です_

ERROR: No space left on device

解決策:_

# Check disk space
df -h /var/lib/postgresql

Clean up if needed

sudo du -sh /var/lib/postgresql/* | sort -h

6.4。問題: ノードのタイムラインが異なります

症状:

CODEBLOCK_4 7

解決策:

# Reinitialize diverged node
patronictl reinit postgres node2

Or manually

sudo systemctl stop patroni sudo rm -rf /var/lib/postgresql/18/data/* sudo systemctl start patroni

7。ブート

# Enable Patroni service
sudo systemctl enable patroni

Verify

systemctl is-enabled patroni

Output: enabled

Test reboot (optional)

sudo reboot

After reboot, check cluster

patronictl list

8 時の自動起動を有効にします。基本的なクラスター管理_

8.1。ノード

# Graceful restart
patronictl restart postgres node2

Force restart

patronictl restart postgres node2 --force

8.2を再起動します。構成_

# Reload Patroni config (non-PostgreSQL settings)
sudo systemctl reload patroni

Reload PostgreSQL config

patronictl reload postgres node1

8.3をリロードします。自動フェイルオーバーの一時停止/再開_

# Pause (disable auto-failover)
patronictl pause postgres

Resume (enable auto-failover)

patronictl resume postgres

8.4。構成_

# Show current DCS configuration
patronictl show-config postgres

9を表示します。自動フェイルオーバーのテスト (オプション)

警告: 非運用環境でのみテストしてください!

9.1。一次障害_

# On node1 (current primary)
sudo systemctl stop patroni

Or kill PostgreSQL

sudo pkill -9 postgres

9.2 をシミュレートします。クラスターのフェイルオーバー

# On node2 hoặc node3
watch -n 1 "patronictl list"

Timeline:

T+0s: node1 is Leader

T+10s: node1 not responding

T+30s: Leader lock expires

T+35s: node2 or node3 becomes Leader

T+40s: Cluster operational with new Leader

9.3 を監視します。新しいプライマリ

patronictl list

New output:

+ Cluster: postgres ----+----+-----------+

| Member | Host | Role | State | TL | Lag in MB |

+--------+---------+---------+---------+----+-----------+

| node1 | 10.0.1.11| Replica | stopped | 1 | |

| node2 | 10.0.1.12| Leader | running | 2 | | ← New primary

| node3 | 10.0.1.13| Replica | running | 2 | 0 |

+--------+---------+---------+---------+----+-----------+

注: タイムラインが 1 → 2 に増加しました (フェールオーバーが発生したことを示します)。

9.4。古いプライマリ

# Start node1 again
sudo systemctl start patroni

Patroni auto-rewinds và rejoins as replica

patronictl list

Output:

| node1 | 10.0.1.11| Replica | running | 2 | 0 | ← Rejoined

| node2 | 10.0.1.12| Leader | running | 2 | |

| node3 | 10.0.1.13| Replica | running | 2 | 0 |

10に再参加します。ラボ演習_

ラボ 1: ブートストラップと検証

タスク: 1. ✅ 3 つのノードで Patroni を順番に起動します。 2. ✅patronictl でクラスタを検証します。リスト_ 3. ✅ レプリケーション ステータスを確認する 4. ✅ テスト データベースを作成し、データのレプリカを確認する_

ラボ 2: レプリケーション ラグをテスト

タスク: 1. プライマリに 10,000 行を挿入します。 2. レプリカのレプリケーション ラグを測定します。 3. 監視します。 pg_stat_replication_

ラボ 3: ノード障害のシミュレーション

タスク_: 1. プライマリ ノードを停止する 2. 自動フェイルオーバーを監視する 3. 新しいプライマリが適応していることを確認する 4. 古いプライマリに再参加する 5. すべてのノードを確認する健康_

11.概要

重要なポイント

✅ ブートストラップ: 最初のノードの初期化、その他クローン

✅ リーダー選出: 自動、DCS ベース

✅ レプリケーション: pg_basebackup による自動セットアップ__HTMLTAG_416___

✅ patronictl: プライマリ管理ツール

✅ モニタリング: patronictl、REST API、pg_stat_replication 経由でチェック

✅ フェイルオーバー: 自動プライマリが失敗した場合

後でチェックリストを作成ブートストラップ

  •  patronictl リストHTMLTAG_434__
  •  1 リーダー、2 に表示される 3 つのノードすべてレプリカ
  •  すべてのノードが同じタイムライン
  •  レプリケーションラグ = 0 MB_
  •  テストデータがすべてのノードに複製
  •  REST API が応答中すべてのノード_
  •  Patroni の自動起動が有効
  •  etcd クラスターが正常

現在のアーキテクチャ_

✅ 3 VMs prepared (Bài 4)
✅ PostgreSQL 18 installed (Bài 5)
✅ etcd cluster running (Bài 6)
✅ Patroni installed (Bài 7)
✅ Patroni configured (Bài 8)
✅ Cluster bootstrapped (Bài 9)

Next: Advanced replication management

レッスンの準備10_

レッスン 10 では、レプリケーション管理について詳しく説明します:

  • 同期レプリケーションと非同期レプリケーション
  • 同期モードの構成
  • レプリケーションの監視ラグ_
  • _レプリケーションの問題の処理