이 빌드가 만드는 것
2테라바이트의 파일과 라이브 Postgres 데이터베이스가 한 사이트에서 다른 사이트로 이동하는 동안, 애플리케이션은 계속해서 요청에 응답합니다. 그 방법은 소스가 계속 서비스를 제공하는 동안 대량 사전 복사를 수행하고, 동기화 상태를 유지하는 스트리밍 복제본을 만든 다음, DNS가 따라잡을 때까지 이전 호스트가 새 호스트에 프록시 역할을 하여 수 초 내에 전환하는 것입니다.
흥미로운 부분은 거리입니다. AMS-01과 FRA-01 사이의 왕복 시간은 7밀리초이고, 단일 스트림으로 포트를 가득 채울 수 있습니다. 동일한 복사를 GRU-01까지 수행하면 왕복 시간이 200밀리초에 가까워지는데, 조정되지 않은 전송은 두 시스템이 거의 유휴 상태인 동안에도 지불한 성능의 극히 일부밖에 내지 못합니다. 그 차이는 전적으로 하나의 연결이 얼마나 많은 데이터를 전송 중에 가질 수 있는지에 달려 있습니다.
시작하기 전에
- 소스 및 대상 인스턴스, 두 인스턴스 사이의 터널, 그리고 두 인스턴스 모두에 대한 루트 권한.
- DNS 레코드의 TTL을 적어도 하루 전에 60초로 낮춘, 제어 가능한 DNS. 이 단계를 건너뛰는 사람들이 많고, 그 결과 여섯 시간을 기다리게 됩니다.
- 대상 디스크에 전체 데이터 세트와 복제본을 저장할 충분한 공간.
1. 링크가 할 수 있는 것 파악하기
대역폭-지연 곱이 모든 것을 결정합니다. 원하는 전송률에 왕복 시간을 곱하면 어떤 순간에도 확인되지 않은 상태로 전송 중이어야 하는 데이터 양이 나옵니다:
ping -c20 target.example.com | tail -1| 경로 | RTT | 1 Gbit/s에 필요한 전송 중 데이터 | 기본 커널 윈도우 |
|---|---|---|---|
| AMS-01에서 FRA-01 | 7 ms | 0.9 MB | 충분함 |
| AMS-01에서 NYC-01 | 76 ms | 9.5 MB | 부족함 |
| AMS-01에서 SIN-01 | 168 ms | 21 MB | 턱없이 부족함 |
| AMS-01에서 GRU-01 | 196 ms | 24.5 MB | 턱없이 부족함 |
두 시스템 모두에서:
cat > /etc/sysctl.d/75-transfer.conf <<EOF
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 262144 134217728
net.ipv4.tcp_wmem = 4096 262144 134217728
net.ipv4.tcp_congestion_control = bbr
net.core.default_qdisc = fq
net.ipv4.tcp_mtu_probing = 1
EOF
sysctl --system손실이 조금이라도 있는 긴 경로에서는 기본 혼잡 제어보다 BBR이 중요합니다. 손실 기반 알고리즘은 패킷 하나가 유실되면 혼잡으로 해석하고 윈도우를 절반으로 줄이기 때문입니다. 200밀리초가 넘는 시간 동안, 그 회복에는 몇 초가 걸리며, 이는 반복적으로 발생합니다.
2테라바이트를 가정에 맡기기 전에 측정하세요:
# target
apt install -y iperf3 && iperf3 -s
# source
iperf3 -c target.example.com -P 8 -t 308개의 병렬 스트림은 포트 속도에 근접해야 합니다. 스트림 하나가 100메가비트를 처리하고 8개가 800메가비트를 처리한다면 윈도우 설정이 적용되지 않은 것입니다. 설정이 적용되면 단일 스트림으로도 대부분의 속도를 낼 수 있어야 합니다.
2. 대량 사전 복사
라이브 소스에 대해 이 작업을 실행합니다. 몇 시간이 걸리지만, 그 동안 아무것도 중단되지 않습니다:
apt install -y rsync
rsync -aHAX --numeric-ids --partial --inplace --info=progress2 \
-e "ssh -c [email protected] -o Compression=no" \
/srv/data/ [email protected]:/srv/data/암호화 알고리즘 선택은 미신이 아닙니다. 이 프로세서들에서는 하드웨어 가속 GCM 모드가 코어당 초당 수 기가바이트를 처리하는 반면, 일부 클라이언트 버전에서 기본 협상 암호는 현저히 느려서 전송을 단일 코어 벤치마크로 바꿔 버립니다. 압축은 데이터가 이미 압축되어 있기 때문에 꺼져 있으며, 그렇지 않으면 CPU가 바이트를 이동하는 대신 압축에 시간을 쓰게 됩니다.
수백만 개의 작은 파일의 경우, 단일 스트림은 잘못된 형태입니다. 최상위 디렉토리별로 분할하고 여러 개를 실행하세요:
ls /srv/data | xargs -P 8 -I{} rsync -aHAX --numeric-ids \
-e "ssh -c [email protected] -o Compression=no" \
/srv/data/{}/ [email protected]:/srv/data/{}/여기서는 8개의 전용 코어에서 8개의 병렬 복사가 적절한 수입니다. 16개는 두 배 빠르지 않으며 소스 시스템이 계속 서비스 중인 작업에 문제를 일으킬 수 있습니다.
3. 복사가 아닌 복제되는 데이터베이스
200기가바이트 Postgres를 덤프하고 복원하는 것은 쓰기 손실이 발생하는 긴 시간을 의미합니다. 대신 스트리밍하세요. 소스에서:
sudo -u postgres psql -c "CREATE USER repl WITH REPLICATION PASSWORD '<a long password>';"
sudo -u postgres psql -c "SELECT pg_create_physical_replication_slot('target_site');"
echo "host replication repl 10.9.0.2/32 scram-sha-256" >> /etc/postgresql/17/main/pg_hba.conf
systemctl reload postgresql대상에서:
systemctl stop postgresql
rm -rf /var/lib/postgresql/17/main/*
sudo -u postgres pg_basebackup -h 10.9.0.1 -U repl -D /var/lib/postgresql/17/main \
-S target_site -X stream -R -P -c fast
systemctl start postgresql-R 플래그는 연결 설정과 대기 신호 파일을 작성하여 대상이 복제본으로 시작하고 따라오게 합니다. 이 시점부터 소스와의 차이는 1~2초 이내로 유지되며, 이는 전환 시 더 이상 데이터베이스를 이동할 필요가 없음을 의미합니다.
4. 전환
제3의 시스템에서 프로브를 시작하고 계속 실행하세요. 이는 검증 도구이자 전환 비용에 대한 기록입니다:
while true; do curl -s -o /dev/null -w "%{http_code} %{time_total}\n" https://app.example.com/health; sleep 1; done | tee cutover.log그런 다음, 일시 중지 없이 다음 순서로 진행합니다:
# 1. final delta, source still live
rsync -aHAX --numeric-ids --delete -e "ssh -c [email protected]" /srv/data/ [email protected]:/srv/data/
# 2. stop writes on the source
systemctl stop app
# 3. one more delta, now tiny
rsync -aHAX --numeric-ids --delete -e "ssh -c [email protected]" /srv/data/ [email protected]:/srv/data/
# 4. promote the replica
ssh [email protected] "sudo -u postgres pg_ctl promote -D /var/lib/postgresql/17/main"
# 5. start the application on the target
ssh [email protected] "systemctl start app"2~5단계는 몇 초밖에 걸리지 않습니다. 이제 DNS가 전파되는 동안 이전 호스트가 오래된 콘텐츠를 제공하지 않도록 새 호스트에 대한 프록시로 전환하세요:
server {
listen 443 ssl;
server_name app.example.com;
ssl_certificate /etc/letsencrypt/live/app.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;
location / {
proxy_pass https://10.9.0.2;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
}이 부분이 전체 작업을 중단 없이 만드는 핵심입니다. 이전 주소를 계속 확인하는 사용자는 터널을 통해 오류를 받는 대신, 아니면 더 나쁘게 전환 시점에 업데이트가 중단된 데이터 사본을 받는 대신 올바른 응답을 받게 됩니다. 이제 DNS 레코드를 변경하세요.
검증
수집한 프로브 로그부터 시작하세요:
sort cutover.log | uniq -c | sort -rn | head모든 줄은 200를 읽어야 합니다. 전환 중 느린 응답이 몇 개 있는 것은 예상되지만, 비-200 응답은 2단계 후 5단계 시작 간격이 너무 길다는 것을 의미하며, 이전 섹션의 프록시가 그 간격을 없애는 역할을 합니다.
그런 다음 데이터가 단순히 존재하는 것이 아니라 동일하다는 것을 증명하세요:
rsync -aHAXn --delete --itemize-changes /srv/data/ [email protected]:/srv/data/ | head
du -s --bytes /srv/data
ssh [email protected] "du -s --bytes /srv/data"항목을 나열하지 않는 드라이 런은 두 트리가 내용, 권한, 소유권 및 확장 속성에서 일치함을 의미합니다. 바이트 합계는 정확히 일치해야 합니다.
다음은 데이터베이스입니다:
ssh [email protected] "sudo -u postgres psql -c 'SELECT pg_is_in_recovery();'"
ssh [email protected] "sudo -u postgres psql app -c 'SELECT count(*) FROM orders;'"
sudo -u postgres psql app -c "SELECT count(*) FROM orders;"대상에서 복구가 이제 false여야 하며, 행 수가 일치해야 합니다. 마지막으로 트래픽이 실제로 이동했는지, 조용히 영원히 프록시되지 않는지 확인하세요:
dig +short app.example.com
tail -f /var/log/nginx/access.log | wc -l # on the old host, an hour later이전 호스트가 전체 TTL과 여유 기간 동안 유휴 상태가 되면 프록시를 내리고 인스턴스를 제거하세요. 같은 날 제거하지 마세요. 이 전체 절차에서 가장 저렴한 보험은 소스 시스템을 일주일 동안 그대로 두고 전원을 끄는 것입니다.
이후
잘 조정된 장거리 경로에서 2테라바이트는 10기가비트에서 약 1시간이 걸리며, 소스가 동시에 서비스를 제공하므로 실제로는 더 오래 걸립니다. 인접한 유럽 사이트 사이에서는 오후를 계획하고, 대륙 간에는 저녁에 시작하여 다음 날 전환을 수행하세요. 위치 페이지에 측정된 왕복 시간이 나와 있으며, 그것들이 1단계 표에 넣을 숫자입니다.