Azure VM 教程
在本指南中,我们将创建一个主节点和辅助 Postgres 节点并设置 最多pg_auto_failover在它们之间复制数据。我们将模拟失败 主节点,并查看系统如何顺利切换(故障转移) 到次要。
为了进行说明,我们将在 Azure 中的虚拟机上运行数据库 平台,但这里的技术与任何云提供商或 本地网络。我们将使用四个虚拟机:一个主数据库,一个 辅助数据库、监视器和“应用程序”。监视器监视 其他节点的运行状况,管理全局状态,并为节点分配其角色。
创建虚拟网络
我们的数据库机器需要相互通信并与监视节点通信,因此 让我们创建一个虚拟网络。
az group create \
--name ha-demo \
--location eastus
az network vnet create \
--resource-group ha-demo \
--name ha-demo-net \
--address-prefix 10.0.0.0/16
我们需要在机器之间打开端口 5432(Postgres)和 22 (SSH),并且 也让我们自己从我们的远程 IP 访问。我们将通过网络来做到这一点 安全组和子网。
az network nsg create \
--resource-group ha-demo \
--name ha-demo-nsg
az network nsg rule create \
--resource-group ha-demo \
--nsg-name ha-demo-nsg \
--name ha-demo-ssh-and-pg \
--access allow \
--protocol Tcp \
--direction Inbound \
--priority 100 \
--source-address-prefixes `curl ifconfig.me` 10.0.1.0/24 \
--source-port-range "*" \
--destination-address-prefix "*" \
--destination-port-ranges 22 5432
az network vnet subnet create \
--resource-group ha-demo \
--vnet-name ha-demo-net \
--name ha-demo-subnet \
--address-prefixes 10.0.1.0/24 \
--network-security-group ha-demo-nsg
最后添加四个虚拟机(ha-demo-a、ha-demo-b、ha-demo-monitor 和 哈演示应用程序)。为了提高速度,我们将进程后台并运行 它们并行:az vm create
# create VMs in parallel
for node in monitor a b app
do
az vm create \
--resource-group ha-demo \
--name ha-demo-${node} \
--vnet-name ha-demo-net \
--subnet ha-demo-subnet \
--nsg ha-demo-nsg \
--public-ip-address ha-demo-${node}-ip \
--image debian \
--admin-username ha-admin \
--generate-ssh-keys &
done
wait
为了在以后的步骤中更轻松地通过 SSH 连接到这些 VM,让我们创建一个 shell 检索其 IP 地址的功能:
# run this in your local shell as well
vm_ip () {
az vm list-ip-addresses -g ha-demo -n ha-demo-$1 -o tsv \
--query '[] [] .virtualMachine.network.publicIpAddresses[0].ipAddress'
}
# for convenience with ssh
for node in monitor a b app
do
ssh-keyscan -H `vm_ip $node` >> ~/.ssh/known_hosts
done
让我们回顾一下到目前为止我们创建的内容。
az resource list --output table --query \
"[?resourceGroup=='ha-demo'].{ name: name, flavor: kind, resourceType: type, region: location }"
这将显示以下资源:
Name ResourceType Region
------------------------------- ----------------------------------------------------- --------
ha-demo-a Microsoft.Compute/virtualMachines eastus
ha-demo-app Microsoft.Compute/virtualMachines eastus
ha-demo-b Microsoft.Compute/virtualMachines eastus
ha-demo-monitor Microsoft.Compute/virtualMachines eastus
ha-demo-appVMNic Microsoft.Network/networkInterfaces eastus
ha-demo-aVMNic Microsoft.Network/networkInterfaces eastus
ha-demo-bVMNic Microsoft.Network/networkInterfaces eastus
ha-demo-monitorVMNic Microsoft.Network/networkInterfaces eastus
ha-demo-nsg Microsoft.Network/networkSecurityGroups eastus
ha-demo-a-ip Microsoft.Network/publicIPAddresses eastus
ha-demo-app-ip Microsoft.Network/publicIPAddresses eastus
ha-demo-b-ip Microsoft.Network/publicIPAddresses eastus
ha-demo-monitor-ip Microsoft.Network/publicIPAddresses eastus
ha-demo-net Microsoft.Network/virtualNetworks eastus
安装“pg_autoctl”可执行文件
本指南使用 Debian Linux,但类似的步骤也适用于其他 分布。所有不同的是包和路径。请参阅安装pg_auto_failover。
pg_auto_failover系统作为单个二进制文件分发 使用子命令来初始化和管理复制的 PostgreSQL 服务。 我们将在所有 节点。它将帮助我们运行和观察PostgreSQL。pg_autoctl
for node in monitor a b app
do
az vm run-command invoke \
--resource-group ha-demo \
--name ha-demo-${node} \
--command-id RunShellScript \
--scripts \
"sudo touch /home/ha-admin/.hushlogin" \
"curl https://install.citusdata.com/community/deb.sh | sudo bash" \
"sudo DEBIAN_FRONTEND=noninteractive apt-get install -q -y postgresql-common" \
"echo 'create_main_cluster = false' | sudo tee -a /etc/postgresql-common/createcluster.conf" \
"sudo DEBIAN_FRONTEND=noninteractive apt-get install -q -y postgresql-11-auto-failover-1.4" \
"sudo usermod -a -G postgres ha-admin" &
done
wait
运行监视器
pg_auto_failover监视器是要运行的第一个组件。它定期 尝试联系其他节点并观察其运行状况。它还 维护全局状态,每个节点上的“守护者”都会咨询以确定其 在系统中自己的角色。
# on the monitor virtual machine
ssh -l ha-admin `vm_ip monitor` -- \
pg_autoctl create monitor \
--auth trust \
--ssl-self-signed \
--pgdata monitor \
--pgctl /usr/lib/postgresql/11/bin/pg_ctl
此命令在指向的位置初始化 PostgreSQL 集群 通过选项。省略时,尝试使用环境变量。如果一个PostgreSQL 实例已存在于目标目录中,此命令 会将其配置为充当监视器。--pgdata``--pgdata``pg_autoctl``PGDATA
pg_auto_failover`,安装 Postgres 扩展,以及 向新用户授予访问权限。`pgautofailover``autoctl_node
在快速入门中,我们使用 避免复杂的安全设置。 Postgres信任身份验证方法不被认为是合理的 生产环境的选择。请考虑使用该选项,或者自己设置密码。--auth trust``--skip-pg-hba``--auth scram-sha-256
此时,将创建监视器。现在我们将它作为服务安装 systemd,以便在虚拟机重新启动时恢复。
ssh -T -l ha-admin `vm_ip monitor` << CMD
pg_autoctl -q show systemd --pgdata ~ha-admin/monitor > pgautofailover.service
sudo mv pgautofailover.service /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable pgautofailover
sudo systemctl start pgautofailover
CMD
Bring up the nodes
We’ll create the primary database using the subcommand.pg_autoctl create
ssh -l ha-admin `vm_ip a` -- \
pg_autoctl create postgres \
--pgdata ha \
--auth trust \
--ssl-self-signed \
--username ha-admin \
--dbname appdb \
--hostname ha-demo-a.internal.cloudapp.net \
--pgctl /usr/lib/postgresql/11/bin/pg_ctl \
--monitor 'postgres://autoctl_node@ha-demo-monitor.internal.cloudapp.net/pg_auto_failover?sslmode=require'
Notice the user and database name in the monitor connection string – these are what monitor init created. We also give it the path to pg_ctl so that the keeper will use the correct version of pg_ctl in future even if other versions of postgres are installed on the system.
In the example above, the keeper creates a primary database. It chooses to set up node A as primary because the monitor reports there are no other nodes in the system yet. This is one example of how the keeper is state-based: it makes observations and then adjusts its state, in this case from “init” to “single.”
Also add a setting to trust connections from our “application” VM:
ssh -T -l ha-admin `vm_ip a` << CMD
echo 'hostssl "appdb" "ha-admin" ha-demo-app.internal.cloudapp.net trust' \
>> ~ha-admin/ha/pg_hba.conf
CMD
此时,监视器和主节点已创建并运行。接下来我们 需要运行守门员。这是一个独立的过程,因此它可以继续 即使 PostgreSQL 进程在节点上终止,也会运行。我们会 使用 systemd 将其作为服务安装,以便在 VM 重新启动时恢复。
ssh -T -l ha-admin `vm_ip a` << CMD
pg_autoctl -q show systemd --pgdata ~ha-admin/ha > pgautofailover.service
sudo mv pgautofailover.service /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable pgautofailover
sudo systemctl start pgautofailover
CMD
接下来连接到节点 B 并执行相同的过程。我们将同时执行这两个步骤:
ssh -l ha-admin `vm_ip b` -- \
pg_autoctl create postgres \
--pgdata ha \
--auth trust \
--ssl-self-signed \
--username ha-admin \
--dbname appdb \
--hostname ha-demo-b.internal.cloudapp.net \
--pgctl /usr/lib/postgresql/11/bin/pg_ctl \
--monitor 'postgres://autoctl_node@ha-demo-monitor.internal.cloudapp.net/pg_auto_failover?sslmode=require'
ssh -T -l ha-admin `vm_ip b` << CMD
pg_autoctl -q show systemd --pgdata ~ha-admin/ha > pgautofailover.service
sudo mv pgautofailover.service /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable pgautofailover
sudo systemctl start pgautofailover
CMD
它从监视器中发现主数据库存在,然后切换自己的主数据库 状态为热备用并开始从主数据库流式传输 WAL 内容。
节点通信
为方便起见,pg_autoctl修改每个节点的文件以允许 要相互连接的节点。例如,pg_autoctl添加了 节点 A 的以下行:pg_hba.conf
# automatically added to node A
hostssl "appdb" "ha-admin" ha-demo-a.internal.cloudapp.net trust
hostssl replication "pgautofailover_replicator" ha-demo-b.internal.cloudapp.net trust
hostssl "appdb" "pgautofailover_replicator" ha-demo-b.internal.cloudapp.net trust
在监控节点上pg_autoctl检查本地网络 并对要允许的子网进行最佳猜测。在我们的例子中,它猜到了 正确:pg_hba.conf
# automatically added to the monitor
hostssl "pg_auto_failover" "autoctl_node" 10.0.1.0/24 trust
如果工作线程节点具有更多临时地址并且不在同一子网中,则 最好在创建过程中使用命令行选项禁用pg_autoctl对pg_hba的自动修改。然后,您将需要 手动编辑 HBA 文件。手动编辑的另一个原因是使用 特殊的身份验证方法。--skip-pg-hba
观看复制
首先,让我们验证监视器是否知道我们的节点,看看是什么 声明它已分配它们:
ssh -l ha-admin `vm_ip monitor` pg_autoctl show state --pgdata monitor
Name | Node | Host:Port | LSN | Reachable | Current State | Assigned State
-------+-------+--------------------------------------+-----------+-----------+---------------------+--------------------
node_1 | 1 | ha-demo-a.internal.cloudapp.net:5432 | 0/3000060 | yes | primary | primary
node_2 | 2 | ha-demo-b.internal.cloudapp.net:5432 | 0/3000060 | yes | secondary | secondary
这看起来不错。我们可以将数据添加到主数据库,稍后会看到它出现在 二 次。我们将从“应用程序”虚拟机内部连接到数据库, 使用从监视器获取的连接字符串。
ssh -l ha-admin `vm_ip monitor` pg_autoctl show uri --pgdata monitor
Type | Name | Connection String
-----------+---------+-------------------------------
monitor | monitor | postgres://autoctl_node@ha-demo-monitor.internal.cloudapp.net:5432/pg_auto_failover?sslmode=require
formation | default | postgres://ha-demo-b.internal.cloudapp.net:5432,ha-demo-a.internal.cloudapp.net:5432/appdb?target_session_attrs=read-write&sslmode=require
现在,我们将获取连接字符串并将其存储在本地环境中 变量:
APP_DB_URI=$( \
ssh -l ha-admin `vm_ip monitor` \
pg_autoctl show uri --formation default --pgdata monitor \
)
连接字符串包含我们的两个节点,逗号分隔,并包括 URL 参数告诉 psql 我们 想要连接到这些服务器中的任何一个支持读取和写入。 这将是主服务器。?target_session_attrs=read-write
# connect to database via psql on the app vm and
# create a table with a million rows
ssh -l ha-admin -t `vm_ip app` -- \
psql "'$APP_DB_URI'" \
-c "'CREATE TABLE foo AS SELECT generate_series(1,1000000) bar;'"
导致故障转移
现在我们已经将数据添加到节点 A,让我们切换哪个被认为是 主要和次要。切换后,我们将再次连接 并查询数据,这次是从节点 B 查询。
# initiate failover to node B
ssh -l ha-admin -t `vm_ip monitor` \
pg_autoctl perform switchover --pgdata monitor
一旦节点B被标记为“主”(或“wait_primary”),我们就可以连接并验证 数据仍然存在:
# connect to database via psql on the app vm
ssh -l ha-admin -t `vm_ip app` -- \
psql "'$APP_DB_URI'" \
-c "'SELECT count(*) FROM foo;'"
它显示
count
---------
1000000
导致节点故障
这个剧情太无聊了,是时候介绍个问题了。我们将关闭 VM 的 节点 B(当前是我们上次故障转移后的主节点)和监视节点 A 升职。
在一个终端中,让我们密切关注事件:
ssh -t -l ha-admin `vm_ip monitor` -- \
watch -n 1 -d pg_autoctl show state --pgdata monitor
在另一个终端中,我们将关闭虚拟服务器。
az vm stop \
--resource-group ha-demo \
--name ha-demo-b
在多次尝试与节点 B 通信失败后,监视器确定 节点运行状况不佳,并将其置于“降级”状态。监视器 将节点 A 提升为新的主节点。
Name | Node | Host:Port | LSN | Reachable | Current State | Assigned State
-------+-------+--------------------------------------+-----------+-----------+---------------------+--------------------
node_1 | 1 | ha-demo-a.internal.cloudapp.net:5432 | 0/6D4E068 | yes | wait_primary | wait_primary
node_2 | 2 | ha-demo-b.internal.cloudapp.net:5432 | 0/6D4E000 | yes | demoted | catchingup
节点 A 不能被视为处于完全“主”状态,因为没有辅助节点 存在,但它仍然可以满足客户端请求。它被标记为“wait_primary” 直到出现辅助数据库,以指示它在没有备份的情况下运行。
让我们在 B 离线时添加一些数据。
# notice how $APP_DB_URI continues to work no matter which node
# is serving as primary
ssh -l ha-admin -t `vm_ip app` -- \
psql "'$APP_DB_URI'" \
-c "'INSERT INTO foo SELECT generate_series(1000001, 2000000);'"
复活节点 B
运行以下命令以使节点 B 重新联机:
az vm start \
--resource-group ha-demo \
--name ha-demo-b
现在,守护者下次重试其运行状况检查时,它会恢复节点。 节点 B 在更新其数据以匹配时经历状态“追赶” 一个。一旦完成,B 将成为辅助,A 现在再次成为完整的主数据库。
Name | Node | Host:Port | LSN | Reachable | Current State | Assigned State
-------+-------+--------------------------------------+------------+-----------+---------------------+--------------------
node_1 | 1 | ha-demo-a.internal.cloudapp.net:5432 | 0/12000738 | yes | primary | primary
node_2 | 2 | ha-demo-b.internal.cloudapp.net:5432 | 0/12000738 | yes | secondary | secondary
更重要的是,如果我们再次直接连接到数据库,则所有 200 万行 仍然存在。
ssh -l ha-admin -t `vm_ip app` -- \
psql "'$APP_DB_URI'" \
-c "'SELECT count(*) FROM foo;'"
它显示
count
---------
2000000




