Database/MySQL, MariaDB

ProxySQL과 Orchestrator의 simple STONITH

BabyTT 2022. 9. 3. 12:03

STONITH (Shoot The Other Node In The Head)

재설정하거나 전원을 차단하여 문제가 생긴 노드를 클러스터에서 제외 시키는 테크닉

 

multi-DC 구조에서 ProxySQL이 routing 과 proxying 을 해주는데 DC1 번의 primary MySQL 노드에서 잠시 이상이 생겼을 때 Orachestrator health check 에서 이상이 생김을 감지하고 DC2 의 다른 노드를 primary로 승격시킬 수 있다.

하지만 잠깐 동안 발생했던 문제의 DC1 의 노드가 정상으로 돌아올 때 문제가 발생할 수 있다. ProxySQL이 이 노드를 다시 read-write 가 가능하다고 지정하려는 경쟁적인 상황이 발생할 수 있고, Orchestrator 가 다시  node를 먼저 찾게 도록 ProxySQL 에서 offline 기간을 늘릴 수 있다. 이 때 예측 가능한 행위를 할 수 있도록하는 추가적인 계층이 필요한데 이게  STONITH로 노드가 cluster 에서 제외되면서 발생할 수 있는 위험성을 줄이기 위해 사용한다.

 

Orchestrator hook 을 이용하지만 ProxySQL 의 내장된 Scheduler를 통해서 더 쉽게 구현할 수 있다. downtimed로 마킹된 노드를 Orchestrator를 참조하여 proxysql 에서 동일하게 표시되도록 하는 proxy-oc-tool.sh 스크립트를 활용한다.

  • MySQL node1이 fail 상태일 때 Orchestrator는 node2를 새로운 Primary로 선택한다.
  • node1 이 read_only 상태를 변경하거나 replication을 업데이트할 수 없는 연결 불가 상태일 때 복구 불가 상태로 downtimed 로 표시된다.
  • node1 이 online 이 되면 ProxySQL이 Orchestrator 보다 먼저 확인하여 다시 클러스터에 조인 시킬 수 있다. 이 때 호스트 그룹에 2개의 쓰기 가능 노드가 생길 수 있다.
  • 이 상황을 방지하기 위해 Orachestrator가 downtime으로 마킹하자마자 스크립트는 OFFLINE_SOFT로 변경하고 ProxySQL에서 쓰기가능한 그룹에 조인되지 못하도록 한다.
  • 여기서 node1을 한번 수정하면 replica로 다시 붙여지고 downtimed 표시가 삭제된다. 그리고 자동으로 ONLINE 으로 표시를 변경한다.
  • 또한 DC1이 DC2 및 AWS에서 완전히 연결이 끊긴 경우 Orchestrator의 raft-leader에 연결할 수 없으며 모든 노드를 OFFLINE_SOFT로 설정하여 DC1에서 isolated 쓰기를 방지한다.

 

ProxySQL에 스크립트를 추가하는 방법

더보기

* 권한 조정

https://gist.githubusercontent.com/dotmanila/1a78ef67da86473c70c7c55d3f6fda89/raw/b671fed06686803e626c1541b69a2a9d20e6bce5/proxy-oc-tool.sh
chmod 0755 proxy-oc-tool.sh
mv proxy-oc-tool.sh /usr/bin/
#!/bin/bash

export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
export ORCHESTRATOR_API="$1"

OC=orchestrator-client
PSQL='mysql --defaults-file=/etc/proxysql/user.cnf -P6032 -h127.1'
VER=$(date +%s)

$OC -c raft-leader > /dev/null 2>&1
HASQUORUM=$?

if [ "x${HASQUORUM}" != "x0" ]; then
  echo "Orchestrator quorum is lost!"
  
  sessions=$($PSQL -BNe "select SessionID from stats_mysql_processlist" | xargs)
  echo "Terminating existing connections $sessions"
  if [ ! -z "$sessions" -a "$sessions" != " " ]; then
    for session in $sessions; do
      echo "KILL CONNECTION $session"
      $PSQL -e "KILL CONNECTION $session";
    done
  fi

  echo "Setting ALL to OFFLINE_SOFT"
  $PSQL -BNe "UPDATE mysql_servers SET status = 'OFFLINE_SOFT', comment = 'proxysql-oc-helper-${VER}'"
  $PSQL -BNe "LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;"
  exit 0
fi

for h in $($OC -c downtimed|cut -d':' -f1); do
  echo "Setting $h to OFFLINE_SOFT"
  $PSQL -BNe "UPDATE mysql_servers SET status = 'OFFLINE_SOFT', comment = 'proxysql-oc-helper-${VER}' WHERE hostname = '$h'"

  _status=$($PSQL -BNe "SELECT DISTINCT status FROM runtime_mysql_servers WHERE hostname = '$h'")
  if [ "x${_status}" != 'xOFFLINE_SOFT' -a "x${_status}" != 'x' ]; then
    $PSQL -BNe "LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;"
  fi
done

_sql="SELECT hostname FROM mysql_servers WHERE status = 'OFFLINE_SOFT' AND comment LIKE 'proxysql-oc-helper-%' AND comment <> 'proxysql-oc-helper-${VER}'"
for h in $($PSQL -BNe "${_sql}"); do
  echo "Setting $h back to ONLINE"
  $PSQL -BNe "UPDATE mysql_servers SET status = 'ONLINE' WHERE hostname = '$h'"
  $PSQL -BNe "LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK;"
done

* ProxySQL 에서 scheduler 설정

INSERT INTO scheduler (interval_ms, filename) 
  VALUES (5000, '/usr/bin/proxy-oc-tool.sh');
LOAD SCHEDULER TO RUNTIME;
SAVE SCHEDULER TO DISK;

 

제외되는 노드는 read-only check 가 완료되기까지 약 10초 소요되기 때문에 이 간격을 ProxySQL에서 5초로 셋팅한다.  이 방법으로 ProxySQL보다 앞서 죽은 노드를 OFFLINE-SOFT로 마킹할 수 있도록 한다.

 

 

참조 :

https://www.percona.com/blog/2019/04/02/simple-stonith-proxysql-orchestrator/

 

Simple STONITH with ProxySQL and Orchestrator - Percona Database Performance Blog

You can achieve simple STONITH for MySQL using ProxySQL and Orchestrator. Jervin Real takes a look at how to set up the basic requirement.

www.percona.com