1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

HadoopクラスタにHiveクラスタを導入してみた。(pgpool版)

1
Last updated at Posted at 2026-01-11

はじめに

Hiveについて、独立したホストでクラスタ化(pgpool利用)してみました。

前提として、以下手順に従いHadoopクラスタを構築してること。

動作確認用にzeppelinも構築していること。

構成概要

Hadoop クラスタ

master1 : ZooKeeper / JournalNode / NameNode(nn1) / ZKFC
JobHistoryServer / ATSv2 / Hive / PostgreSQL
master2 : ZooKeeper / JournalNode / NameNode(nn2) / ZKFC
ResourceManager(rm1)
master3 : ZooKeeper / JournalNode
ResourceManager(rm2)
worker1 : DataNode / NodeManager
worker2 : DataNode / NodeManager
zeppelin1 : zeppelin

上記ZookeeeperをHiveServer2クラスタで利用。
master1のHive&PostgreSQLは下記ホスト、Hive稼働できたらサービス停止してよい。

追加ホスト

hive1 : HiveServer2 + Hive Metastore
hive2 : HiveServer2 + Hive Metastore
pg1 : PostgreSQL Primary + pgpool
pg2 : PostgreSQL Standby + pgpool
pg3 : PostgreSQL Standby + pgpool
pg-vip : PostgreSQL 仮想IP(pgpool制御)

pg1/pg2/pg3について、AlmaLinux9を使用する。
それ以外は、Ubuntu24.04を使用する。

HA 方針

コンポーネント HA方式
HiveServer2 ZooKeeper Service Discovery
Hive Metastore Active-Active
PostgreSQL Streaming Replication
Primary 切替 pgpool
postgresql接続先 VIP (pgpool)
ZooKeeper Hadoop 既存を流用

前提 IP(例)

192.168.11.54 hive1
192.168.11.55 hive2
192.168.11.37 pg1
192.168.11.38 pg2
192.168.11.39 pg3
192.168.11.40 pg-vip

※適宜読み替えてください

1. 全ノード共通設定(新規ホスト)

全ホストの名前解決を行えるようにする。

以下のコマンドでBigTop APT リポジトリ追加すること。
こちらについてはpg1/pg2/pg3では実施しなくてよい。

sudo tee /etc/apt/sources.list.d/bigtop.list << 'EOF'
deb [trusted=yes] http://repos.bigtop.apache.org/releases/3.3.0/ubuntu/22.04/amd64 bigtop contrib
EOF

sudo apt update

2. PostgreSQL HA 構築

2.1. 全台共通(pg1 / pg2 / pg3)

2.1.1. 基本設定

sudo dnf -y update
sudo dnf -y install chrony vim wget
sudo systemctl enable --now chronyd

2.1.2. PostgreSQL PGDG リポジトリ

sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --set-enabled crb
sudo dnf -qy module disable postgresql
sudo dnf -y install \
  https://download.postgresql.org/pub/repos/yum/reporpms/EL-9-x86_64/pgdg-redhat-repo-latest.noarch.rpm

2.1.3. PostgreSQL + Pgpool インストール(全台)

sudo dnf -y install pgpool-II pgpool-II-pcp
sudo dnf -y install postgresql16-server

2.2 PostgreSQL:Streaming Replication 構築

2.2.1. 3台共通:初期化・起動

sudo /usr/pgsql-16/bin/postgresql-16-setup initdb
sudo systemctl enable --now postgresql-16

2.2.2. pg1: postgresql.conf

sudo -u postgres sed -i \
  -e "s/^#listen_addresses.*/listen_addresses = '*'/" \
  /var/lib/pgsql/16/data/postgresql.conf
sudo -u postgres tee -a /var/lib/pgsql/16/data/postgresql.conf >/dev/null <<'EOF'
wal_level = replica
max_wal_senders = 10
max_replication_slots = 10
hot_standby = on
wal_log_hints = on
EOF

2.2.2. pg1: DBユーザー作成(pgpool / repl)

sudo -u postgres psql <<'SQL'
SET password_encryption = 'scram-sha-256';

DO $$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='pgpool') THEN
    CREATE ROLE pgpool LOGIN;
  END IF;
  IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname='repl') THEN
    CREATE ROLE repl REPLICATION LOGIN;
  END IF;
END $$;

GRANT pg_monitor TO pgpool;
SQL
sudo -u postgres psql -c "\password pgpool"

sudo -u postgres psql -c "\password repl"

sudo -u postgres psql -c "\password postgres"

→それぞれのDBパスワードを定め、パスワードを控える

2.2.3. pg1: pg_hba.conf

sudo -u postgres tee -a /var/lib/pgsql/16/data/pg_hba.conf >/dev/null <<'EOF'
host    all             all             192.168.11.0/24         scram-sha-256
host    replication     all             192.168.11.0/24         scram-sha-256
EOF
sudo systemctl restart postgresql-16

2.3. pg2/pg3 を Standby にする(basebackup)

2.3.1. pg2 / pg3: データ作り直し

sudo systemctl stop postgresql-16
sudo mv /var/lib/pgsql/16/data /var/lib/pgsql/16/data.old.$(date +%F-%H%M%S)
sudo install -d -o postgres -g postgres -m 700 /var/lib/pgsql/16/data
sudo restorecon -RFv /var/lib/pgsql/16/data || true

2.3.2. pg2/pg3: pg_basebackup(pg1から)

sudo -u postgres /usr/pgsql-16/bin/pg_basebackup \
  -h pg1 -p 5432 -U repl \
  -D /var/lib/pgsql/16/data \
  -R -X stream -C -S "$(hostname)" \
  --write-recovery-conf

→replのPW入力が出ます

2.3.3. pg2/pg3: 起動

sudo systemctl start postgresql-16

2.3.4. pg1: 確認

sudo -u postgres psql -c "select client_addr,state,sync_state from pg_stat_replication;"

→sync_stateが全てasyncとなること。

2.4 Pgpool-II:3台 Watchdog + VIP 構築

2.4.1. 3台共通:pgpool_node_id

pg1

echo 0 | sudo tee /etc/pgpool-II/pgpool_node_id

pg2

echo 1 | sudo tee /etc/pgpool-II/pgpool_node_id

pg3

echo 2 | sudo tee /etc/pgpool-II/pgpool_node_id

2.4.2. pg1:pgpool.conf(仮置き)

sudo cp -p /etc/pgpool-II/pgpool.conf.sample /etc/pgpool-II/pgpool.conf
sudo chown root:root /etc/pgpool-II/pgpool.conf
sudo chmod 644 /etc/pgpool-II/pgpool.conf
sudo tee -a /etc/pgpool-II/pgpool.conf >/dev/null <<'EOF'

# ===== minimal settings for pg_enc / SR mode =====
listen_addresses = '*'
port = 9999
pcp_port = 9898

backend_clustering_mode = 'streaming_replication'

backend_hostname0 = 'pg1'
backend_port0 = 5432
backend_data_directory0 = '/var/lib/pgsql/16/data'
backend_flag0 = 'ALLOW_TO_FAILOVER'

backend_hostname1 = 'pg2'
backend_port1 = 5432
backend_data_directory1 = '/var/lib/pgsql/16/data'
backend_flag1 = 'ALLOW_TO_FAILOVER'

backend_hostname2 = 'pg3'
backend_port2 = 5432
backend_data_directory2 = '/var/lib/pgsql/16/data'
backend_flag2 = 'ALLOW_TO_FAILOVER'

# pool_passwd を使う前提
health_check_user = 'pgpool'
health_check_password = ''
sr_check_user = 'pgpool'
sr_check_password = ''
EOF

2.4.3. pg1:pool_passwd

sudo -u postgres bash -lc '
set -e
umask 077
openssl rand -base64 32 | tr -d "\n" > ~/.pgpoolkey
chmod 600 ~/.pgpoolkey
ls -l ~/.pgpoolkey
wc -c ~/.pgpoolkey
'
sudo install -o postgres -g postgres -m 600 /dev/null /etc/pgpool-II/pool_passwd
sudo restorecon -v /etc/pgpool-II/pool_passwd 2>/dev/null || true
sudo -u postgres bash -lc 'pg_enc -m -k ~/.pgpoolkey -u pgpool -p'

→pgpoolのPW入力をすること。

sudo cat /etc/pgpool-II/pool_passwd

2.4.4. 3台共通:PCPユーザー(pgpool)

sudo chown -R postgres:postgres /etc/pgpool-II
sudo -u postgres touch /etc/pgpool-II/pcp.conf
sudo pg_md5 -u pgpool -p

→pgpoolパスワードをここで新しく設定し、帰ってきた値を控える

sudo -u postgres vi /etc/pgpool-II/pcp.conf

→以下の記載を入れる。

pgpool:<先ほど控えた値>

sudo chmod 600 /etc/pgpool-II/pcp.conf

2.4.5. 3台共通:sudoers(VIP操作)

sudo visudo -f /etc/sudoers.d/pgpool_vip

中身:

postgres ALL=NOPASSWD: /usr/sbin/ip
postgres ALL=NOPASSWD: /usr/sbin/arping
Defaults:postgres !requiretty

2.4.6. 3台共通:postgres SSH鍵(フェールオーバースクリプト用)

SSHフルメッシュ交換(postgresSSH鍵)

sudo -u postgres bash -lc 'test -f ~/.ssh/id_rsa_pgpool || ssh-keygen -t ed25519 -N "" -f ~/.ssh/id_rsa_pgpool'
sudo -u postgres cat /var/lib/pgsql/.ssh/id_rsa_pgpool.pub

それぞれの公開鍵を控える。

sudo -u postgres touch /var/lib/pgsql/.ssh/authorized_keys
sudo -u postgres chmod 600 /var/lib/pgsql/.ssh/authorized_keys
sudo -u postgres vi /var/lib/pgsql/.ssh/authorized_keys

控えた3台の公開鍵を書き込む。

sudo -u postgres ssh -i /var/lib/pgsql/.ssh/id_rsa_pgpool postgres@pg1 'hostname'
sudo -u postgres ssh -i /var/lib/pgsql/.ssh/id_rsa_pgpool postgres@pg2 'hostname'
sudo -u postgres ssh -i /var/lib/pgsql/.ssh/id_rsa_pgpool postgres@pg3 'hostname'

→yesを入力し、以下の回答が出てくること。(2回やったほうが結果はわかりやすい)

pg1
pg2
pg3

2.4.7. 3台共通:.pgpass(repl / postgres)

REPL_PASSWORDとPOSTGRES_PASSWORDとPGPOOL_PASSWORDは実値に置換する。

sudo -u postgres tee /var/lib/pgsql/.pgpass >/dev/null <<'EOF'
pg1:5432:replication:repl:REPL_PASSWORD
pg2:5432:replication:repl:REPL_PASSWORD
pg3:5432:replication:repl:REPL_PASSWORD
pg1:5432:postgres:postgres:POSTGRES_PASSWORD
pg2:5432:postgres:postgres:POSTGRES_PASSWORD
pg3:5432:postgres:postgres:POSTGRES_PASSWORD
pg1:5432:postgres:pgpool:PGPOOL_PASSWORD
pg2:5432:postgres:pgpool:PGPOOL_PASSWORD
pg3:5432:postgres:pgpool:PGPOOL_PASSWORD
EOF
sudo -u postgres chmod 600 /var/lib/pgsql/.pgpass

2.5 pgpool.conf/pool_hba.conf

2.5.1. pg1/pg2/pg3共通で設定

sudo tee /etc/pgpool-II/pgpool.conf >/dev/null <<'EOF'
########## 基本 ##########
listen_addresses = '*'
port = 9999
pcp_port = 9898

backend_clustering_mode = 'streaming_replication'

########## Backend ##########
backend_hostname0 = 'pg1'
backend_port0 = 5432
backend_weight0 = 1
backend_data_directory0 = '/var/lib/pgsql/16/data'
backend_flag0 = 'ALLOW_TO_FAILOVER'

backend_hostname1 = 'pg2'
backend_port1 = 5432
backend_weight1 = 1
backend_data_directory1 = '/var/lib/pgsql/16/data'
backend_flag1 = 'ALLOW_TO_FAILOVER'

backend_hostname2 = 'pg3'
backend_port2 = 5432
backend_weight2 = 1
backend_data_directory2 = '/var/lib/pgsql/16/data'
backend_flag2 = 'ALLOW_TO_FAILOVER'

########## health / sr check ##########
health_check_period = 5
health_check_timeout = 30
health_check_max_retries = 3
health_check_user = 'pgpool'
health_check_password = 'pgpoolpass'   # pgpool_passwdを使う
health_check_database = 'postgres'

sr_check_period = 5
sr_check_user = 'pgpool'
sr_check_password = 'pgpoolpass'       # pgpool_passwdを使う

########## フェイルオーバ / 追従 ##########
failover_command = '/etc/pgpool-II/failover.sh %d %h %p %D %m %H %M %P %r %R %N %S'
follow_primary_command = '/etc/pgpool-II/follow_primary.sh %d %h %m %H'

########## watchdog + VIP ##########
use_watchdog = on
delegate_ip = '192.168.11.40'

# VIP scripts(ip/arping は実パスに統一)
if_up_cmd   = '/usr/bin/sudo /usr/sbin/ip addr add $_IP_$/24 dev eth0 label eth0:0'
if_down_cmd = '/usr/bin/sudo /usr/sbin/ip addr del $_IP_$/24 dev eth0'
arping_cmd  = '/usr/bin/sudo /usr/sbin/arping -U $_IP_$ -w 1 -I eth0'

# lifcheck: heartbeat(※定義がないと起動時に FATAL になります)
wd_lifecheck_method = 'heartbeat'
wd_interval = 10

heartbeat_hostname0 = 'pg1'
heartbeat_port0 = 9694

heartbeat_hostname1 = 'pg2'
heartbeat_port1 = 9694

heartbeat_hostname2 = 'pg3'
heartbeat_port2 = 9694

# watchdog peers
hostname0 = 'pg1'
wd_port0 = 9000
pgpool_port0 = 9999

hostname1 = 'pg2'
wd_port1 = 9000
pgpool_port1 = 9999

hostname2 = 'pg3'
wd_port2 = 9000
pgpool_port2 = 9999

wd_escalation_command = '/etc/pgpool-II/escalation.sh'

########## pool_hba ##########
enable_pool_hba = on
pool_passwd = '/etc/pgpool-II/pool_passwd'
pool_key = '/var/lib/pgsql/.pgpoolkey'

########## ファイル出力先(Permission denied 回避のため必須) ##########
logdir = '/var/log/pgpool-II'
backend_status_file = '/var/log/pgpool-II/pgpool_status'
wd_ipc_socket_dir = '/var/run/pgpool'
pid_file_name = '/var/run/pgpool/pgpool.pid'

# ---- auto failback ----
auto_failback = on
EOF
sudo tee /etc/pgpool-II/pool_hba.conf <<EOF
# ローカル運用
local   all         all                             trust
host    all         all         127.0.0.1/32         scram-sha-256
host    all         all         ::1/128              scram-sha-256

host    all         all         192.168.11.0/24      scram-sha-256

EOF

2.6. サンプルスクリプト有効化(PG16向けに修正)

2.6.1. 3台共通:配置

  • failover.sh(フェイルオーバーシェル)

以下の動作を行います。

スタンバイ障害なら「レプリケーションスロットを落として終わり」
プライマリ障害なら「新しいメイン(=昇格対象)を promote して終わり」

sudo tee /etc/pgpool-II/failover.sh >/dev/null <<'EOF'
#!/bin/bash
# This script is run by failover_command.
set -o xtrace

FAILED_NODE_ID="$1"
FAILED_NODE_HOST="$2"
FAILED_NODE_PORT="$3"
FAILED_NODE_PGDATA="$4"
NEW_MAIN_NODE_ID="$5"
NEW_MAIN_NODE_HOST="$6"
OLD_MAIN_NODE_ID="$7"
OLD_PRIMARY_NODE_ID="$8"
NEW_MAIN_NODE_PORT="$9"
NEW_MAIN_NODE_PGDATA="${10}"
OLD_PRIMARY_NODE_HOST="${11}"
OLD_PRIMARY_NODE_PORT="${12}"

PGHOME=/usr/pgsql-16
REPL_SLOT_NAME=$(echo "${FAILED_NODE_HOST,,}" | tr -- -. _)
POSTGRESQL_STARTUP_USER=postgres
SSH_KEY_FILE=id_rsa_pgpool
SSH_OPTIONS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/${SSH_KEY_FILE}"

echo failover.sh: start: failed_node_id=$FAILED_NODE_ID failed_host=$FAILED_NODE_HOST \
    old_primary_node_id=$OLD_PRIMARY_NODE_ID new_main_node_id=$NEW_MAIN_NODE_ID new_main_host=$NEW_MAIN_NODE_HOST

# If there's no main node anymore, skip failover.
if [ "$NEW_MAIN_NODE_ID" -lt 0 ]; then
    echo failover.sh: All nodes are down. Skipping failover.
    exit 0
fi

# Test passwordless SSH
ssh -T ${SSH_OPTIONS} ${POSTGRESQL_STARTUP_USER}@${NEW_MAIN_NODE_HOST} ls /tmp > /dev/null
if [ $? -ne 0 ]; then
    echo failover.sh: passwordless SSH to ${POSTGRESQL_STARTUP_USER}@${NEW_MAIN_NODE_HOST} failed.
    exit 1
fi

# If Standby node is down (not old primary), drop replication slot and exit.
if [ "$OLD_PRIMARY_NODE_ID" != "-1" -a "$FAILED_NODE_ID" != "$OLD_PRIMARY_NODE_ID" ]; then
    ${PGHOME}/bin/psql -h ${OLD_PRIMARY_NODE_HOST} -p ${OLD_PRIMARY_NODE_PORT} postgres \
        -c "SELECT pg_drop_replication_slot('${REPL_SLOT_NAME}');"  >/dev/null 2>&1 || true
    echo failover.sh: end: standby node is down. Skipping failover.
    exit 0
fi

# Promote Standby node.
echo failover.sh: primary node is down, promote new_main_node_id=$NEW_MAIN_NODE_ID on ${NEW_MAIN_NODE_HOST}.
ssh -T ${SSH_OPTIONS} ${POSTGRESQL_STARTUP_USER}@${NEW_MAIN_NODE_HOST} \
  ${PGHOME}/bin/pg_ctl -D ${NEW_MAIN_NODE_PGDATA} -w promote

if [ $? -ne 0 ]; then
    echo ERROR: failover.sh: promote failed
    exit 1
fi

echo failover.sh: end: new_main_node_id=$NEW_MAIN_NODE_ID on ${NEW_MAIN_NODE_HOST} was successfully promoted to primary
exit 0
EOF
sudo chown postgres:postgres /etc/pgpool-II/failover.sh
sudo chmod 700 /etc/pgpool-II/failover.sh
  • escalation.sh(VIP取り扱いシェル)

自身がリーダーになった(VIP付与対象になった)際、他のホストのVIPの取り外しを実施します。

sudo tee /etc/pgpool-II/escalation.sh >/dev/null <<'EOF'
#!/bin/bash
# Bring down the virtual IP on other pgpool nodes before bringing it up on this node.
set -o xtrace

POSTGRESQL_STARTUP_USER=postgres
SSH_KEY_FILE=id_rsa_pgpool
SSH_OPTIONS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/${SSH_KEY_FILE}"
SSH_TIMEOUT=5

PGPOOLS=(pg1 pg2 pg3)

VIP=192.168.11.40
DEVICE=eth0
CIDR_NETMASK=24
IP=/usr/sbin/ip

for pgpool in "${PGPOOLS[@]}"; do
  [ "$HOSTNAME" = "${pgpool}" ] && continue

  timeout ${SSH_TIMEOUT} ssh -T ${SSH_OPTIONS} ${POSTGRESQL_STARTUP_USER}@${pgpool} "
    ${IP} addr show dev ${DEVICE} | grep -F ${VIP} > /dev/null 2>&1
  "

  if [ $? -eq 0 ]; then
    timeout ${SSH_TIMEOUT} ssh -T ${SSH_OPTIONS} ${POSTGRESQL_STARTUP_USER}@${pgpool} "
      /usr/bin/sudo ${IP} addr del ${VIP}/${CIDR_NETMASK} dev ${DEVICE}
    " || echo "ERROR: escalation.sh: failed to release VIP on ${pgpool}."
  fi
done
exit 0
EOF
sudo chown postgres:postgres /etc/pgpool-II/escalation.sh
sudo chmod 700 /etc/pgpool-II/escalation.sh
  • follow_primary.sh(スタンバイ追従シェル)

スタンバイとするノードに対し、以下の操作を実施します。

postgresql停止
pg_rewind/basebackupによるスタンバイ化
postgresql開始
pgpoolへのアタッチ

sudo tee /etc/pgpool-II/follow_primary.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
set -o xtrace

NODE_ID="${1:?}"
NODE_HOST="${2:?}"
NEW_PRIMARY_NODE_ID="${3:?}"
NEW_PRIMARY_HOST="${4:?}"

PGDATA="/var/lib/pgsql/16/data"
PRIMARY_PORT="5432"
REPLUSER="repl"

PGHOME="/usr/pgsql-16"
PGBASEBACKUP="${PGHOME}/bin/pg_basebackup"
PGREWIND="${PGHOME}/bin/pg_rewind"
PSQL="${PGHOME}/bin/psql"

# pg_rewind 用(確実に行くなら postgres。必要に応じて変更)
REWIND_USER="postgres"
REWIND_DB="postgres"

POSTGRESQL_STARTUP_USER="postgres"

SSH_KEY_FILE="id_rsa_pgpool"
SSH_BASE_OPTS="-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -i ~/.ssh/${SSH_KEY_FILE} \
-o ConnectTimeout=5 -o ServerAliveInterval=5 -o ServerAliveCountMax=3 -o BatchMode=yes"

SSH_CMD_TIMEOUT="60"
BASEBACKUP_TIMEOUT="1800"
REWIND_TIMEOUT="600"
START_WAIT="60"

REPL_SLOT_NAME="$(echo "${NODE_HOST,,}" | tr -- -. _)"
BACKUP_TS="$(date +%F_%H%M%S)"
BACKUP_DIR="${PGDATA}.bak_${BACKUP_TS}"

log(){ echo "follow_primary.sh: $*"; }

run_ssh() {
  local host="$1"; shift
  timeout "${SSH_CMD_TIMEOUT}" ssh -T ${SSH_BASE_OPTS} "${POSTGRESQL_STARTUP_USER}@${host}" "$@"
}

run_ssh_long() {
  local host="$1"; shift
  timeout "${BASEBACKUP_TIMEOUT}" ssh -T ${SSH_BASE_OPTS} "${POSTGRESQL_STARTUP_USER}@${host}" "$@"
}

run_ssh_rewind() {
  local host="$1"; shift
  timeout "${REWIND_TIMEOUT}" ssh -T ${SSH_BASE_OPTS} "${POSTGRESQL_STARTUP_USER}@${host}" "$@"
}

die_remote() {
  local host="$1"; shift
  log "ERROR: $*"
  run_ssh "${host}" "sudo systemctl --no-pager -l status postgresql-16 || true; sudo journalctl -u postgresql-16 -n 80 --no-pager || true" || true
  exit 1
}

# --- PCP attach (best-effort) ---
PCP_HOST="127.0.0.1"
PCP_PORT="9898"
PCP_ATTACH_NODE="$(command -v pcp_attach_node || true)"
PCP_NODE_INFO="$(command -v pcp_node_info || true)"
PCP_TIMEOUT="3"

pcp_attach_best_effort() {
  local nid="$1"
  [ -n "$PCP_ATTACH_NODE" ] || { log "pcp_attach_node not found, skip"; return 0; }
  if [ -n "$PCP_NODE_INFO" ]; then
    timeout "$PCP_TIMEOUT" "$PCP_NODE_INFO" -h "$PCP_HOST" -p "$PCP_PORT" -U pgpool -n "$nid" >/dev/null 2>&1 || {
      log "PCP not reachable on ${PCP_HOST}:${PCP_PORT}, skip attach"
      return 0
    }
  fi
  log "try pcp_attach_node nid=${nid} (best-effort)"
  timeout "$PCP_TIMEOUT" "$PCP_ATTACH_NODE" -h "$PCP_HOST" -p "$PCP_PORT" -U pgpool -n "$nid" >/dev/null 2>&1 || true
}

# --- standby config helper (pg_basebackup -R 相当を自前で) ---
configure_as_standby() {
  local host="$1"
  log "configure standby.signal + primary_conninfo on ${host}"

  run_ssh "${host}" "
    set -euo pipefail
    sudo -u postgres bash -ceu '
      : \"\${PGDATA:=${PGDATA}}\"

      # standby.signal(PG16はこれでstandby)
      touch \"${PGDATA}/standby.signal\"
      chown postgres:postgres \"${PGDATA}/standby.signal\"

      # primary_conninfo / primary_slot_name を postgresql.auto.conf に入れる
      # 既存行がある場合は置換(無ければ追記)
      AUTO=\"${PGDATA}/postgresql.auto.conf\"
      touch \"\$AUTO\"
      chown postgres:postgres \"\$AUTO\"

      # primary_conninfo を整形(必要に応じて sslmode など追記)
      PC=\"host=${NEW_PRIMARY_HOST} port=${PRIMARY_PORT} user=${REPLUSER} application_name=${NODE_HOST}\"

      # 行置換 or 追記
      grep -q \"^primary_conninfo\" \"\$AUTO\" && sed -i \"s|^primary_conninfo.*|primary_conninfo = '\\''\${PC}'\\''|\" \"\$AUTO\" || echo \"primary_conninfo = '\\''\${PC}'\\''\" >> \"\$AUTO\"
      grep -q \"^primary_slot_name\" \"\$AUTO\" && sed -i \"s|^primary_slot_name.*|primary_slot_name = '\\''${REPL_SLOT_NAME}'\\''|\" \"\$AUTO\" || echo \"primary_slot_name = '\\''${REPL_SLOT_NAME}'\\''\" >> \"\$AUTO\"
    '
  " || die_remote "${host}" "failed to write standby settings"
}

# --- optional: create replication slot on new primary (best-effort) ---
create_slot_best_effort() {
  local host="$1"
  log "best-effort create slot on new primary: ${REPL_SLOT_NAME}"
  # ここは「新プライマリ側」に対して実行する(postgresで実行できる前提)
  run_ssh "${host}" "
    set -euo pipefail
    sudo -u postgres ${PSQL} -h '${NEW_PRIMARY_HOST}' -p '${PRIMARY_PORT}' -d '${REWIND_DB}' -Atc \"
      DO \\\$\\\$BEGIN
        IF NOT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name='${REPL_SLOT_NAME}') THEN
          PERFORM pg_create_physical_replication_slot('${REPL_SLOT_NAME}');
        END IF;
      END\\\$\\\$;
    \" >/dev/null 2>&1 || true
  " || true
}

# --- try pg_rewind. return 0 if success, 1 if not ---
try_pg_rewind() {
  local host="$1"

  log "try pg_rewind on ${host} (if prerequisites ok)"
  # PGDATA が無い/空なら無理なので即失敗扱い
  run_ssh "${host}" "test -d '${PGDATA}' -a -f '${PGDATA}/PG_VERSION'" || {
    log "pg_rewind skipped: PGDATA missing or not initialized on ${host}"
    return 1
  }

  # pg_rewind 実行(失敗してもここでは die しない)
  set +e
  run_ssh_rewind "${host}" "
    set -euo pipefail
    sudo -u postgres '${PGREWIND}' -D '${PGDATA}' \
      --source-server=\"host=${NEW_PRIMARY_HOST} port=${PRIMARY_PORT} user=${REWIND_USER} dbname=${REWIND_DB}\" \
      --progress
  "
  local rc=$?
  set -e

  if [ $rc -eq 0 ]; then
    log "pg_rewind SUCCESS on ${host}"
    return 0
  fi

  log "pg_rewind FAILED on ${host} (rc=${rc}) -> fallback to basebackup"
  return 1
}

log "start node=${NODE_ID} host=${NODE_HOST} new_primary=${NEW_PRIMARY_NODE_ID}(${NEW_PRIMARY_HOST}:${PRIMARY_PORT})"

if [ "${NODE_ID}" = "${NEW_PRIMARY_NODE_ID}" ]; then
  log "this node is new primary -> skip"
  exit 0
fi

run_ssh "${NODE_HOST}" "hostname; id" || { log "ssh failed to ${NODE_HOST}"; exit 1; }
run_ssh "${NODE_HOST}" "sudo -n true" || die_remote "${NODE_HOST}" "sudo requires password (NOPASSWD missing)"

# 1) 停止
log "stop postgresql-16 on ${NODE_HOST}"
run_ssh "${NODE_HOST}" "
  set -euo pipefail
  sudo systemctl stop postgresql-16 || true

  if [ -f '${PGDATA}/postmaster.pid' ]; then
    PID=\$(head -n 1 '${PGDATA}/postmaster.pid' 2>/dev/null || true)
    if [ -n \"\${PID}\" ] && kill -0 \"\${PID}\" 2>/dev/null; then
      echo \"[remote] postgres still running pid=\${PID}, killing...\"
      sudo kill -TERM \"\${PID}\" || true
      sleep 1
      sudo kill -KILL \"\${PID}\" || true
    fi
  fi
  ss -lntp | grep ':5432' || true
" || die_remote "${NODE_HOST}" "failed to stop postgres"

# 2) まず pg_rewind を試す(成功なら basebackup スキップ)
if try_pg_rewind "${NODE_HOST}"; then
  # standby 設定(-R 相当)
  create_slot_best_effort "${NODE_HOST}"
  configure_as_standby "${NODE_HOST}"

  # 起動
  log "start postgresql-16 on ${NODE_HOST} (after pg_rewind)"
  run_ssh "${NODE_HOST}" "
    set -euo pipefail
    sudo systemctl start postgresql-16
  " || die_remote "${NODE_HOST}" "systemctl start failed after pg_rewind"

else
  # 3) rewind失敗時は従来通り:PGDATA退避&空作成 → basebackup
  log "rotate PGDATA on ${NODE_HOST} (for basebackup)"
  run_ssh "${NODE_HOST}" "
    set -euo pipefail
    if [ -d '${PGDATA}' ]; then
      sudo mv '${PGDATA}' '${BACKUP_DIR}'
    fi
    sudo -u postgres mkdir -p '${PGDATA}'
    sudo chown -R postgres:postgres '${PGDATA}'
    sudo chmod 700 '${PGDATA}'
  " || die_remote "${NODE_HOST}" "failed to rotate PGDATA"

  log "pg_basebackup to ${NODE_HOST} from ${NEW_PRIMARY_HOST} slot=${REPL_SLOT_NAME}"
  run_ssh_long "${NODE_HOST}" "
    set -euo pipefail
    '${PGBASEBACKUP}' -h '${NEW_PRIMARY_HOST}' -p '${PRIMARY_PORT}' -U '${REPLUSER}' \
      -D '${PGDATA}' -R -X stream -C -S '${REPL_SLOT_NAME}' --no-password
  " || die_remote "${NODE_HOST}" "pg_basebackup failed (auth/pg_hba/network/slot?)"

  log "start postgresql-16 on ${NODE_HOST} (after basebackup)"
  run_ssh "${NODE_HOST}" "
    set -euo pipefail
    sudo systemctl start postgresql-16
  " || die_remote "${NODE_HOST}" "systemctl start failed after basebackup"
fi

# 4) 起動待ち&standby確認
log "wait up to ${START_WAIT}s for postgres and check recovery on ${NODE_HOST}"
run_ssh "${NODE_HOST}" "
  set -euo pipefail
  for i in \$(seq 1 ${START_WAIT}); do
    if sudo systemctl is-active --quiet postgresql-16; then
      break
    fi
    sleep 1
  done
  sudo systemctl --no-pager -l status postgresql-16 | sed -n '1,25p' || true
  psql -U postgres -d postgres -tAc 'select pg_is_in_recovery();'
" | tail -n 1 | grep -qx 't' || die_remote "${NODE_HOST}" "postgres is not standby after recovery"

pcp_attach_best_effort "${NODE_ID}"

log "done node=${NODE_ID} host=${NODE_HOST}"
exit 0
EOF
sudo chmod 755 /etc/pgpool-II/follow_primary.sh
sudo chown postgres:postgres /etc/pgpool-II/follow_primary.sh
sudo restorecon -v /etc/pgpool-II/follow_primary.sh 2>/dev/null || true
  • postgresユーザーでのsudo操作許可(follow_primary.shで必要)
sudo tee /etc/sudoers.d/postgres_tmp_all >/dev/null <<'EOF'
Defaults:postgres !requiretty
postgres ALL=(ALL) NOPASSWD: ALL
EOF

sudo chmod 440 /etc/sudoers.d/postgres_tmp_all
sudo visudo -cf /etc/sudoers.d/postgres_tmp_all
  • postgres ユーザー用に pgpool-II の PCP コマンドのパスワードファイル作成(follow_primary.shで必要)
sudo -u postgres bash -lc 'umask 077; cat > ~/.pcppass <<EOF
127.0.0.1:9898:pgpool:pgpoolpass
EOF
chmod 600 ~/.pcppass
ls -l ~/.pcppass
'

2.7. pgpool 起動(全台)

2.7.1. pid/書き込み先置き場所作成

sudo install -d -m 755 -o postgres -g postgres /var/run/pgpool /var/log/pgpool-II
sudo restorecon -RFv /var/run/pgpool /var/log/pgpool-II 2>/dev/null || true

sudo tee /etc/tmpfiles.d/pgpool.conf >/dev/null <<'EOF'
d /var/run/pgpool 0755 postgres postgres -
EOF

sudo systemd-tmpfiles --create /etc/tmpfiles.d/pgpool.conf

2.7.2. 起動

sudo systemctl enable --now pgpool-II
sudo systemctl status pgpool-II

2.8. 確認(VIP / watchdog / pool_nodes)

2.8.1. VIPがどこにいるか(3台どれかで)

ip -br addr | grep 192.168.11.40 || true

→3台のどれかでVIPが出ればよい。

2.8.2. Pgpool経由で backend 状態(どこからでも)

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

→backendのステータスが見れること。

2.8.3. watchdog 状態

pcp_watchdog_info -h 127.0.0.1 -p 9898 -U pgpool

→pgpoolのパスワードを入れる。
3台のステータスが見れること。

2.9. アクセス制限更新(pg_hba.conf,pool_hba.conf)

pg1/pg2/pg3で実施

sudo tee /var/lib/pgsql/16/data/pg_hba.conf >/dev/null <<'EOF'
# ===== local =====
local   all             all                                     peer
host    all             all             127.0.0.1/32            scram-sha-256
host    all             all             ::1/128                 scram-sha-256

# ===== Pgpool health/sr_check user (pgpool) =====
# pgpool は同居でも別ノード経由でも backend に接続し得るので、3台のIPを明示許可
host    all             pgpool           192.168.11.37/32       scram-sha-256
host    all             pgpool           192.168.11.38/32       scram-sha-256
host    all             pgpool           192.168.11.39/32       scram-sha-256

# ===== Streaming Replication (repl) =====
# standby が primary に replication 接続するため
host    replication     repl             192.168.11.37/32       scram-sha-256
host    replication     repl             192.168.11.38/32       scram-sha-256
host    replication     repl             192.168.11.39/32       scram-sha-256

# follow_primary動作のため
host    all     postgres   192.168.11.37/32   scram-sha-256
host    all     postgres   192.168.11.38/32   scram-sha-256
host    all     postgres   192.168.11.39/32   scram-sha-256

EOF
sudo tee /etc/pgpool-II/pool_hba.conf <<EOF
# ローカル運用
local   all         all                              scram-sha-256
host    all         all         127.0.0.1/32         scram-sha-256
host    all         all         ::1/128              scram-sha-256

# pg1/pg2/pg3からのアクセス許可
host    all         all         192.168.11.37/32      scram-sha-256
host    all         all         192.168.11.38/32      scram-sha-256
host    all         all         192.168.11.39/32      scram-sha-256

EOF
sudo systemctl reload postgresql-16
sudo systemctl reload pgpool-II

2.10. pgpool認証ファイルコピー

2.10.1.【pg1】/tmp に一時コピーを作る(root)

sudo cp /etc/pgpool-II/pool_passwd /tmp/pool_passwd
sudo cp /var/lib/pgsql/.pgpoolkey /tmp/.pgpoolkey

sudo chown postgres:postgres /tmp/pool_passwd /tmp/.pgpoolkey
sudo chmod 600 /tmp/pool_passwd /tmp/.pgpoolkey

2.10.2.【pg1】postgres SSH で配布

sudo -u postgres scp -i /var/lib/pgsql/.ssh/id_rsa_pgpool \
  /tmp/pool_passwd /tmp/.pgpoolkey \
  postgres@pg2:/tmp/

sudo -u postgres scp -i /var/lib/pgsql/.ssh/id_rsa_pgpool \
  /tmp/pool_passwd /tmp/.pgpoolkey \
  postgres@pg3:/tmp/

2.10.3.【pg2 / pg3】正規配置(root)

sudo mv /tmp/pool_passwd /etc/pgpool-II/pool_passwd
sudo chown postgres:postgres /etc/pgpool-II/pool_passwd
sudo chmod 600 /etc/pgpool-II/pool_passwd
sudo mv /tmp/.pgpoolkey /var/lib/pgsql/.pgpoolkey
sudo chown postgres:postgres /var/lib/pgsql/.pgpoolkey
sudo chmod 600 /var/lib/pgsql/.pgpoolkey

2.10.4. Pgpool 反映(全ノード)

sudo systemctl restart pgpool-II

2.10.5.【後始末】pg1 の /tmp を掃除

sudo rm -f /tmp/pool_passwd /tmp/.pgpoolkey

2.11 postgresql自動起動停止

pgpoolにてpostgresqlの制御を実施させるため、postgresqlの自動起動を停止する。

sudo systemctl disable postgresql-16

3. Hive(hive1 / hive2)

3.1. インストール

sudo apt install -y hive hive-metastore hive-server2
sudo apt install -y openjdk-8-jdk

3.2. hadoop ユーザー作成

sudo useradd -m -g hadoop -s /bin/bash hadoop

3.3. Hadoop 設定作成

sudo tee /etc/hadoop/conf/core-site.xml << 'EOF'
<configuration>
  <property>
    <name>fs.defaultFS</name>
    <value>hdfs://cluster1</value>
  </property>
  <property>
    <name>ha.zookeeper.quorum</name>
    <value>master1:2181,master2:2181,master3:2181</value>
  </property>
  <property>
    <name>hadoop.tmp.dir</name>
    <value>/var/lib/hadoop/tmp</value>
  </property>
</configuration>
EOF
sudo tee /etc/hadoop/conf/hdfs-site.xml << 'EOF'
<configuration>

  <property>
    <name>dfs.nameservices</name>
    <value>cluster1</value>
  </property>

  <property>
    <name>dfs.ha.namenodes.cluster1</name>
    <value>nn1,nn2</value>
  </property>

  <property>
    <name>dfs.namenode.rpc-address.cluster1.nn1</name>
    <value>master1:8020</value>
  </property>

  <property>
    <name>dfs.namenode.rpc-address.cluster1.nn2</name>
    <value>master2:8020</value>
  </property>

  <property>
    <name>dfs.namenode.http-address.cluster1.nn1</name>
    <value>master1:9870</value>
  </property>
  
  <property>
    <name>dfs.namenode.http-address.cluster1.nn2</name>
    <value>master2:9870</value>
  </property>

  <property>
    <name>dfs.namenode.name.dir</name>
    <value>file:///var/lib/hadoop-hdfs/namenode</value>
  </property>

  <property>
    <name>dfs.datanode.data.dir</name>
    <value>file:///var/lib/hadoop-hdfs/datanode</value>
  </property>

  <property>
    <name>dfs.namenode.shared.edits.dir</name>
    <value>qjournal://master1:8485;master2:8485;master3:8485/cluster1</value>
  </property>

  <property>
    <name>dfs.journalnode.edits.dir</name>
    <value>/var/lib/hadoop-hdfs/journalnode</value>
  </property>

  <property>
    <name>dfs.client.failover.proxy.provider.cluster1</name>
    <value>
      org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
    </value>
  </property>

  <property>
    <name>dfs.ha.automatic-failover.enabled</name>
    <value>true</value>
  </property>

  <property>
    <name>dfs.replication</name>
    <value>2</value>
  </property>

  <property>
    <name>dfs.ha.fencing.methods</name>
    <value>sshfence</value>
  </property>

  <property>
    <name>dfs.ha.fencing.ssh.private-key-files</name>
    <value>/home/hadoop/.ssh/id_rsa</value>
  </property>

</configuration>
EOF
sudo tee /etc/hadoop/conf/yarn-site.xml << 'EOF'
<configuration>

  <property>
    <name>yarn.resourcemanager.ha.enabled</name>
    <value>true</value>
  </property>

  <property>
    <name>yarn.resourcemanager.cluster-id</name>
    <value>ycluster</value>
  </property>

  <property>
    <name>yarn.resourcemanager.ha.rm-ids</name>
    <value>rm1,rm2</value>
  </property>

  <property>
    <name>yarn.resourcemanager.hostname.rm1</name>
    <value>master2</value>
  </property>

  <property>
    <name>yarn.resourcemanager.hostname.rm2</name>
    <value>master3</value>
  </property>

  <property>
    <name>yarn.resourcemanager.zk-address</name>
    <value>master1:2181,master2:2181,master3:2181</value>
  </property>

  <property>
    <name>yarn.nodemanager.resource.memory-mb</name>
    <value>512</value>
  </property>

  <property>
    <name>yarn.scheduler.minimum-allocation-mb</name>
    <value>128</value>
  </property>

  <property>
    <name>yarn.scheduler.maximum-allocation-mb</name>
    <value>256</value>
  </property>

  <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
  </property>

  <property>
    <name>yarn.timeline-service.enabled</name>
    <value>true</value>
  </property>

  <property>
    <name>yarn.timeline-service.version</name>
    <value>2.0</value>
  </property>

  <property>
    <name>yarn.timeline-service.fs-writer.root-dir</name>
    <value>/atsv2</value>
  </property>

  <property>
    <name>yarn.timeline-service.reader.webapp.address</name>
    <value>master1:8188</value>
  </property>

  <property>
    <name>yarn.webapp.ui2.enable</name>
    <value>true</value>
  </property>

  <property>
    <name>yarn.log.server.url</name>
    <value>http://master1:19888/jobhistory/logs</value>
  </property>

  <property>
    <name>yarn.resourcemanager.webapp.address.rm1</name>
    <value>master2:8088</value>
  </property>

  <property>
    <name>yarn.resourcemanager.webapp.address.rm2</name>
    <value>master3:8088</value>
  </property>

</configuration>
EOF
sudo tee /etc/hadoop/conf/mapred-site.xml << 'EOF'
<configuration>
  <property>
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
  </property>

  <property>
    <name>yarn.app.mapreduce.am.env</name>
    <value>HADOOP_COMMON_HOME=/usr/lib/hadoop,HADOOP_HDFS_HOME=/usr/lib/hadoop-hdfs,HADOOP_MAPRED_HOME=/usr/lib/hadoop-mapreduce</value>
  </property>

  <property>
    <name>mapreduce.map.env</name>
    <value>HADOOP_COMMON_HOME=/usr/lib/hadoop,HADOOP_HDFS_HOME=/usr/lib/hadoop-hdfs,HADOOP_MAPRED_HOME=/usr/lib/hadoop-mapreduce</value>
  </property>

  <property>
    <name>mapreduce.reduce.env</name>
    <value>HADOOP_COMMON_HOME=/usr/lib/hadoop,HADOOP_HDFS_HOME=/usr/lib/hadoop-hdfs,HADOOP_MAPRED_HOME=/usr/lib/hadoop-mapreduce</value>
  </property>

  <property>
    <name>mapreduce.application.classpath</name>
    <value>/etc/hadoop/conf,/etc/hadoop/conf/*,/usr/lib/hadoop/*,/usr/lib/hadoop/lib/*,/usr/lib/hadoop-hdfs/*,/usr/lib/hadoop-hdfs/lib/*,/usr/lib/hadoop-mapreduce/*,/usr/lib/hadoop-mapreduce/lib/*,/usr/lib/hadoop-yarn/*,/usr/lib/hadoop-yarn/lib/*</value>
  </property>

  <property>
    <name>mapreduce.jobhistory.address</name>
    <value>master1:10020</value>
  </property>

  <property>
    <name>mapreduce.jobhistory.webapp.address</name>
    <value>master1:19888</value>
  </property>

  <property>
    <name>mapreduce.jobhistory.done-dir</name>
    <value>/mr-history/done</value>
  </property>

  <property>
    <name>mapreduce.jobhistory.intermediate-done-dir</name>
    <value>/mr-history/tmp</value>
  </property>

  <property>
    <name>yarn.app.mapreduce.am.command-opts</name>
    <value>-Dlog4j.configuration=file:/etc/hadoop/conf/log4j.properties</value>
  </property>

  <property>
    <name>mapreduce.map.java.opts</name>
    <value>-Dlog4j.configuration=file:/etc/hadoop/conf/log4j.properties</value>
  </property>

  <property>
    <name>mapreduce.reduce.java.opts</name>
    <value>-Dlog4j.configuration=file:/etc/hadoop/conf/log4j.properties</value>
  </property>

  <property>
    <name>mapreduce.job.am.webapp.address</name>
    <value>0.0.0.0:0</value>
  </property>

  <property>
    <name>mapreduce.job.am.webapp.https.address</name>
    <value>0.0.0.0:0</value>
  </property>

  <property>
    <name>mapreduce.shuffle.port</name>
    <value>13562</value>
  </property>
</configuration>
EOF

3.4. hive-site.xml(両ノード共通)

sudo tee /etc/hive/conf/hive-site.xml << 'EOF'
<configuration>

  <property>
    <name>javax.jdo.option.ConnectionURL</name>
    <value>jdbc:postgresql://pg-vip:9999/hive_metastore</value>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionDriverName</name>
    <value>org.postgresql.Driver</value>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionUserName</name>
    <value>hive</value>
  </property>
  <property>
    <name>javax.jdo.option.ConnectionPassword</name>
    <value>HivePasswordHere</value>
  </property>

  <property>
    <name>hive.metastore.uris</name>
    <value>thrift://hive1:9083,thrift://hive2:9083</value>
  </property>
  
  <property>
    <name>hive.metastore.warehouse.dir</name>
    <value>/user/hive/warehouse</value>
  </property>

  <property>
    <name>hive.server2.support.dynamic.service.discovery</name>
    <value>true</value>
  </property>
  <property>
    <name>hive.zookeeper.quorum</name>
    <value>master1:2181,master2:2181,master3:2181</value>
  </property>
  <property>
    <name>hive.server2.zookeeper.namespace</name>
    <value>hiveserver2</value>
  </property>
  
  <property>
    <name>hive.metastore.client.notification.event.poll.interval</name>
    <value>0s</value>
  </property>
  <property>
    <name>hive.metastore.event.db.notification.api.auth</name>
    <value>false</value>
  </property>

  <property>
    <name>hive.server2.enable.doAs</name>
    <value>false</value>
  </property>

</configuration>
EOF

3.5. PostgreSQL JDBC ドライバを Hive に追加

sudo apt install -y libpostgresql-jdbc-java
dpkg -L libpostgresql-jdbc-java | grep -E 'postgresql.*\.jar$'

sudo ln -sf /usr/share/java/postgresql.jar /usr/lib/hive/lib/postgresql.jar
sudo rm -rf /usr/lib/hive/lib/postgresql-9.4.1208.jre7.jar

3.6. hive DB設定

3.6.1. HiveDB作成

pg1で実施。

psql -h pg1 -U postgres -d postgres <<'SQL'

DO $$
BEGIN
  IF NOT EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'hive') THEN
    CREATE ROLE hive LOGIN PASSWORD 'HivePasswordHere';
  END IF;
END $$;

CREATE DATABASE hive_metastore OWNER postgres;

\connect hive_metastore

GRANT CONNECT, TEMP ON DATABASE hive_metastore TO hive;

ALTER SCHEMA public OWNER TO hive;
GRANT USAGE, CREATE ON SCHEMA public TO hive;

GRANT ALL PRIVILEGES ON ALL TABLES    IN SCHEMA public TO hive;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO hive;
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO hive;

ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON TABLES    TO hive;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON SEQUENCES TO hive;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL ON FUNCTIONS TO hive;

SQL

3.6.2. HiveDBアクセス設定

pg1/pg2/pg3で実施

sudo tee -a /var/lib/pgsql/16/data/pg_hba.conf >/dev/null <<'EOF'
# ------------------------------------------------------------
# 3) Hive Metastore
# ------------------------------------------------------------
host    hive_metastore  hive        192.168.11.37/32            scram-sha-256
host    hive_metastore  hive        192.168.11.38/32            scram-sha-256
host    hive_metastore  hive        192.168.11.39/32            scram-sha-256

EOF
sudo tee -a /etc/pgpool-II/pool_hba.conf <<EOF
# ------------------------------------------------------------
# Hive Metastore -> Pgpool VIP
# ------------------------------------------------------------
host    hive_metastore  hive    192.168.11.54/32    scram-sha-256
host    hive_metastore  hive    192.168.11.55/32    scram-sha-256

EOF
sudo systemctl reload postgresql-16
sudo systemctl reload pgpool-II

3.6.3. HiveDBアクセス認証情報配布

  • 【pg1】認証情報作成
sudo -u postgres bash -lc 'pg_enc -m -k ~/.pgpoolkey -u hive -p'
→HivePasswordHereを入れる
  • 【pg1】/tmp に一時コピーを作る(root)
sudo cp /etc/pgpool-II/pool_passwd /tmp/pool_passwd
sudo cp /var/lib/pgsql/.pgpoolkey /tmp/.pgpoolkey

sudo chown postgres:postgres /tmp/pool_passwd /tmp/.pgpoolkey
sudo chmod 600 /tmp/pool_passwd /tmp/.pgpoolkey
  • 【pg1】postgres SSH で配布
sudo -u postgres scp -i /var/lib/pgsql/.ssh/id_rsa_pgpool \
  /tmp/pool_passwd /tmp/.pgpoolkey \
  postgres@pg2:/tmp/

sudo -u postgres scp -i /var/lib/pgsql/.ssh/id_rsa_pgpool \
  /tmp/pool_passwd /tmp/.pgpoolkey \
  postgres@pg3:/tmp/
  • 【pg2 / pg3】正規配置(root)
sudo mv /tmp/pool_passwd /etc/pgpool-II/pool_passwd
sudo chown postgres:postgres /etc/pgpool-II/pool_passwd
sudo chmod 600 /etc/pgpool-II/pool_passwd
sudo mv /tmp/.pgpoolkey /var/lib/pgsql/.pgpoolkey
sudo chown postgres:postgres /var/lib/pgsql/.pgpoolkey
sudo chmod 600 /var/lib/pgsql/.pgpoolkey
  • Pgpool 反映(全ノード)
sudo systemctl restart pgpool-II
  • 【後始末】pg1 の /tmp を掃除
sudo rm -f /tmp/pool_passwd /tmp/.pgpoolkey

3.7. Metastore スキーマ初期化(hive1で1 回のみ)

sudo -u hadoop /usr/lib/hive/bin/schematool -dbType postgres -initSchema

3.8. サービス作成

sudo tee /etc/default/hive <<'EOF'
HIVE_HOME=/usr/lib/hive
HIVE_CONF_DIR=/etc/hive/conf
HADOOP_CONF_DIR=/etc/hadoop/conf
YARN_CONF_DIR=/etc/hadoop/conf
MAPRED_CONF_DIR=/etc/hadoop/conf
JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64
TERM=dumb
EOF
sudo tee /etc/systemd/system/hive-metastore.service <<'EOF'
[Unit]
Description=Apache Hive Metastore Service
After=network.target
Wants=network.target

After=hadoop-hdfs-namenode.service hadoop-hdfs-datanode.service hadoop-yarn-resourcemanager.service hadoop-yarn-nodemanager.service
Wants=hadoop-hdfs-namenode.service hadoop-hdfs-datanode.service hadoop-yarn-resourcemanager.service hadoop-yarn-nodemanager.service

[Service]
Type=simple
User=hive
Group=hive
EnvironmentFile=-/etc/default/hive
Environment="HIVE_CONF_DIR=/etc/hive/conf"

ExecStart=/usr/lib/hive/bin/hive --service metastore
Restart=on-failure
RestartSec=5
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target
EOF
sudo tee /etc/systemd/system/hiveserver2.service <<'EOF'
[Unit]
Description=Apache HiveServer2 Service
After=network.target hive-metastore.service
Wants=network.target hive-metastore.service

[Service]
Type=simple
User=hive
Group=hive
EnvironmentFile=-/etc/default/hive
Environment="HADOOP_CLIENT_OPTS=-Dlog4j2.debug=false"
Environment="HIVE_OPTS=--hiveconf hive.root.logger=INFO,console --hiveconf hive.server2.logging.operation.enabled=true"
Environment="HADOOP_HEAPSIZE=1024"

ExecStartPre=/bin/bash -lc 'for i in {1..30}; do nc -z localhost 9083 && exit 0; sleep 1; done; exit 1'
ExecStart=/usr/lib/hive/bin/hive --service hiveserver2
Restart=on-failure
RestartSec=5
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target
EOF

3.9. HDFS 上に Hive warehouse 作成(master1で実施)

既存のHadoopクラスタに対し、以下の設定を実施すること。

sudo su - hadoop

hdfs dfs -mkdir -p /user/hive/warehouse
hdfs dfs -chown -R hive:hive /user/hive
hdfs dfs -chmod 771 /user/hive
hdfs dfs -chmod 771 /user/hive/warehouse
hdfs dfs -chmod -R 1777 /tmp

exit

3.10. 起動(hive1/hive2)

sudo systemctl enable --now hive-metastore hiveserver2

4. 動作確認(Hive)

4.1. beeline/zeppelin利用確認

それぞれのHive接続で使用するJDBC設定を以下のように変更して、
それぞれ利用できることを確認する。

変更前

'jdbc:hive2://master1:10000/default'

変更後

'jdbc:hive2://master1:2181,master2:2181,master3:2181/;serviceDiscoveryMode=zooKeeper;zooKeeperNamespace=hiveserver2'

5. 動作確認(PostgreSQL)

5.1 準備

5.1.1 確認用端末

psqlコマンドを使用できるホストを用意する。

psqlコマンドを使用できるようにする。

sudo apt install postgresql-client-16

5.1.2 pg1/pg2/pg3設定

例として以下のIP(192.168.11.71)で登録する。

sudo tee -a /etc/pgpool-II/pool_hba.conf <<EOF
# ope1からのアクセス許可(オプション)
host    all         all         192.168.11.71/32    scram-sha-256 

EOF
sudo systemctl reload pgpool-II

5.1.3 動作確認

ope1にて以下のコマンドを入力して応答が返ることを確認する。

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

5.2. 事前確認(共通)

5.2.1. 現在状態(VIP経由で確認)

ope1

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

期待結果

pg1 primary
pg2 standby
pg3 standby
status/pg_status: up

5.3. フェールオーバー(postgresqlサービス停止)

5.3.1. 概要

目的:primary を pg1 → pg2 に自動的にフェールオーバーさせる。
障害注入方法:
pg1のpostgresqlサービスを停止する。

期待する結果:
自動的にpg2へDBプライマリが自動的に切り替わり、外からの接続も実施できること。
pg1/pg3について、自動的にpg2のstandbyとなること。
合わせて、pgpoolのattachも自動的に実施される。

5.3.2. primary(pg1) の PostgreSQL を停止(障害注入)

pg1

sudo systemctl stop postgresql-16
sudo systemctl is-active postgresql-16 || true

期待結果

inactive

数十秒待って再度2つめのコマンドを実施して、activeとなること。

5.3.3. フェールオーバー成立確認(VIP経由)

ope1

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

期待結果(数十秒〜で変化)

pg1 standby
pg2 primary
pg3 standby
status/pg_status: up

5.3.4. 新primary(pg2) 側で “本当にprimaryか” を確認

pg2

sudo -u postgres psql -c "select pg_is_in_recovery();"

期待結果

f(= primary)

5.3.5. レプリケーション確認

pg2

sudo -u postgres psql -c "select client_addr,state,sync_state,application_name from pg_stat_replication;"

期待結果

pg1/pg3 が並ぶ(2行)

5.4. フェールオーバー(primaryホスト停止)

5.4.1. 概要

目的:primary を pg2 → pg1 に自動的にフェールオーバーさせる。
障害注入方法:
pg2ホストを停止する。

期待する結果:
自動的にpg1へDBプライマリが自動的に切り替わり、外からの接続も実施できること。
pg3について、自動的にpg1のstandbyとなること。
合わせて、pgpoolのattachも自動的に実施される。
pg2復旧後、手動操作を行いstandbyとして復旧すること。

5.4.2. primary(pg2) の ノードを停止(障害注入)

pg2

sudo shutdown -h now

5.4.3. フェールオーバー成立確認(VIP経由)

ope1

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

期待結果(数十秒〜で変化)

pg1 primary
pg2 standby,status/pg_status: down
pg3 standby
status/pg_status: up

5.4.4. 新primary(pg1) 側で “本当にprimaryか” を確認

pg1

sudo -u postgres psql -c "select pg_is_in_recovery();"

期待結果

f(= primary)

5.4.5. レプリケーション確認

pg1

sudo -u postgres psql -c "select client_addr,state,sync_state,application_name from pg_stat_replication;"

期待結果

pg3 が並ぶ(1行)

5.4.6. pg2ホスト立ち上げ

落とした元primaryホストを立ち上げる

5.4.7. pg2ホストの再加入

pg2

sudo -u postgres /etc/pgpool-II/follow_primary.sh 1 pg2 0 pg1

5.4.8. フェールオーバー成立確認(VIP経由)

ope1

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

期待結果(数十秒〜で変化)

pg1 primary
pg2 standby
pg3 standby
status/pg_status: up

5.4.9. pg2で “本当にstandbyか” を確認

pg2

sudo -u postgres psql -c "select pg_is_in_recovery();"

期待結果

t(= standby)

5.4.10. レプリケーション確認

pg1

sudo -u postgres psql -c "select client_addr,state,sync_state,application_name from pg_stat_replication;"

期待結果

pg2/pg3 が並ぶ(1行)

5.5. フェイルバック

5.5.1. 概要

目的:
primary を pg1 → pg2 に戻す

リスク:
pgpool稼働中にpg1を止めると、自動判定が走る可能性(pg2に確実に戻したい。)
pg2のスタンバイとしてpg1/pg3が立ち上がらなくなり、クラスタ状態が壊れる

対策:
フェイルバック作業中だけ pgpoolを全台止める
follow_primaryシェルを利用し、pg1/pg3のstanby化を確実に実施する。

5.5.2. pgpool を全台停止(pg1/pg2/pg3)

各ノードで:

sudo systemctl stop pgpool-II
sudo systemctl is-active pgpool-II || true

期待結果

3台とも pgpool-II inactive

5.5.3 primary-standby追いつき確認

pg1:

sudo -u postgres psql -Atc "select pg_current_wal_lsn();"

pg2/pg3:

sudo -u postgres psql -Atc "select pg_last_wal_replay_lsn();"

上記の結果が全台で一致すること。

5.5.4. 現primary(pg1) を停止

pg1

sudo systemctl stop postgresql-16
sudo systemctl is-active postgresql-16 || true

期待結果

pg2 postgresql-16 inactive

5.5.5. pg2 を primary に昇格

pg2

sudo -u postgres /usr/pgsql-16/bin/pg_ctl -D /var/lib/pgsql/16/data -w promote
sudo -u postgres psql -c "select pg_is_in_recovery();"

期待結果

f(pg2 primary)

5.5.6. pg3 を pg2 の standby として作り直し

  • pg3:follow_primaryシェルで作り直す
sudo systemctl stop postgresql-16
sudo -u postgres /etc/pgpool-II/follow_primary.sh 2 pg3 1 pg2
sudo -u postgres psql -c "select pg_is_in_recovery();"

期待結果

t(pg3 standby)

5.5.7. pg1 を pg2 の standby として作り直す

  • pg1:follow_primaryシェルで作り直す
sudo -u postgres /etc/pgpool-II/follow_primary.sh 0 pg1 1 pg2
sudo -u postgres psql -c "select pg_is_in_recovery();"

期待結果

t(pg1 standby)

5.5.8. pg2でレプリケーション確認

pg2

sudo -u postgres psql -c "select client_addr,state,sync_state,application_name from pg_stat_replication;"

期待結果

pg1/pg3 が並ぶ(2行)

5.5.9. pgpool を全台起動

sudo systemctl start pgpool-II
sudo systemctl is-active pgpool-II

5.5.10. VIP経由で最終確認

ope1

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

期待結果

pg1 standby
pg2 primary
pg3 standby
status/pg_status: up

5.6. 全台落としたあとの復帰

5.6.1. 概要

目的:
全台落として復帰させる

作業概要:
pg1をプライマリとしてpostgresqlを立ち上げ、
その後standby(pg2/pg3)のDB同期、立ち上げを実施する。

5.6.2. ノードを全台停止(pg1/pg2/pg3)

各ノードで:

sudo shutdown -h now

5.6.3 pg1/pg2/pg3立ち上げ

正常に立ち上がり、SSHでログインできること。

5.6.4. pg1/pg2/pg3 のpgpool-IIを停止する

pg1/pg2/pg3

sudo systemctl stop pgpool-II
sudo systemctl is-active pgpool-II || true

期待結果

5.6.5. pg1 のpostgresqlを立ち上げて、primaryとする

pg1

sudo systemctl start postgresql-16
sudo -u postgres /usr/pgsql-16/bin/pg_ctl -D /var/lib/pgsql/16/data -w promote
sudo -u postgres psql -c "select pg_is_in_recovery();"

"pg_ctl: cannot promote server; server is not in standby mode"と出る場合は無視してよい。

期待結果

f(pg1 primary)

5.6.6. pg2/pg3 を pg1 の standby として作り直し

pg2/pg3

sudo systemctl stop postgresql-16
sudo mv /var/lib/pgsql/16/data /var/lib/pgsql/16/data.old.$(date +%F-%H%M%S)
sudo install -d -o postgres -g postgres -m 700 /var/lib/pgsql/16/data
sudo restorecon -RFv /var/lib/pgsql/16/data || true
sudo -u postgres /usr/pgsql-16/bin/pg_basebackup \
  -h pg1 -p 5432 -U repl \
  -D /var/lib/pgsql/16/data \
  -R -X stream -S "$(hostname)" \
  --write-recovery-conf
sudo systemctl start postgresql-16
sudo -u postgres psql -c "select pg_is_in_recovery();"

期待結果

t(pg2/pg3 standby)

5.6.7. pg1でレプリケーション確認

pg1

sudo -u postgres psql -c "select client_addr,state,sync_state,application_name from pg_stat_replication;"

期待結果

pg2/pg3 が並ぶ(2行)

5.6.8. pgpool を全台起動

sudo systemctl start pgpool-II
sudo systemctl is-active pgpool-II

5.6.9. VIP経由で最終確認

ope1

psql -h 192.168.11.40 -p 9999 -U pgpool -d postgres -c "SHOW pool_nodes;"

期待結果

pg1 primary
pg2 standby
pg3 standby
status/pg_status: up

1
0
6

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?