Рубрики
Uncategorized

Подключение секвенирования к кластеру PostgreSQL

В этом руководстве я подключаю приложение Node.js с секвенированием к кластеру PostgreSQL, чтобы написать на первичный узел и прочитать от узлов в режиме ожидания. Помечено Postgres, Node, DevOps, JavaScript.

Пролог

В оформлении Предыдущий пост Я показал, как автоматизировать PostgreSQL-толерантный кластер с блуждающим и несчастным.

Этот вид установки делает нашу базу данных Cluster устойчивым к сбою сервера и сохраняет данные, доступные без необходимости взаимодействия человека. Но как насчет приложений, использующих эту базу данных? Они тоже нелепируются?

Orms, как Sequelize есть Прочитайте репликацию Особенности, которые позволяют определить ваши основные и резервные узлы в соединении базы данных. Но что произойдет, если ваш основной узел, который отвечает за операции записи, находится в автономном режиме, и ваше приложение должно продолжать сохранять данные в вашей базе данных?

Один из способов решить это, добавляя дополнительный слой в систему — слой балансировки нагрузки — с использованием почтовых сторонних инструментов, таких как PGBouncer или PGPool-II Или даже правильно настроен Haproxy пример. Помимо сложности, привезенной этим методом, вы также можете представлять нежелательные Одиночная точка провала Отказ

Другим способом является использование плавающего IP-адреса/виртуального IP-адреса для назначения текущей главной базе данных, поэтому приложение знает, какой узел он должен подключаться при выполнении операций записи, даже если другой узел занимает первичную роль.

Мы будем использовать цифровой океан для создания сервера и плавающего назначения IP, но стратегия также работает с другими облачными поставщиками, которые поддерживают плавающие IP.

Цели

  • Подключение Nodejs Приложение с Sequelize к PostgreSQL кластер для того, чтобы написать на первичный узел и прочитать от резервных узлов;
  • Создать и назначить A Цифровой океан плавающий IP (aka flip) к нашему текущему узлу первичной базы данных;
  • сделать Repmgr Взаимодействовать с Цифровой океан CLI переназначить Flip на новый главный узел по акциям;
  • Держите этот переключение прозрачным для Nodejs Применение, поэтому вся система работает без человеческой помощи.

До реквизиты

  • А Цифровой океан Учетная запись и API-токен ( Создать учетную запись, используя мой реферал, чтобы получить бесплатные кредиты )
  • А PostgreSQL кластер с Repmgr на Цифровой океан (Вы можете схватить Anbible Playbook в этом Учебное пособие настроить его или просто использовать кластер с потоковой репликацией и имитировать сбой + ручной продвижение);
  • Nodejs и NPM установлен (я использую nodejs v12 с npm v6);
  • А PostgreSQL Пользователь с аутентификацией пароля, которые принимают удаленные соединения с хоста вашего приложения (я буду использовать Postgres : 123456 ).

Настройте свой кластер

Создайте свои капли

Создайте 3 капли, предпочтительно с операционной системой Ubuntu 20.04:

  • PG1 (первичный)
  • PG2 (режим ожидания)
  • PG3 (свидетель)

Чтобы сделать конфигурации работать более гладким, добавьте вашу публичную клавишу SSH при создании капель. Вы также можете использовать ключевую пару, которую я предоставил на Github для целей тестирования.

Если вы хотите использовать только 2 капельки, вы можете игнорировать третий узел, так как это будет постгресусь.

ПРИМЕЧАНИЕ. Если вы используете SSH-закрытый ключ, который публично передается в Интернете, ваш кластер может взломать.

Назначьте плавающий IP на ваш основной узел

Создайте плавающий IP-адрес и назначьте его на свой основной узел (PG1).

Настроить PostgreSQL с Repmgr

Как указано ранее, вы можете использовать Anisible Playbook из последнего поста Ускорить конфигурацию. Скачать его из Github и вставить свой шлюз и капельки IPv4 адреса на group_vars/all.yaml. :

client_ip: ""
node1_ip: ""
node2_ip: ""
node3_ip: ""
pg_version: "12"

Примечание. Я предполагаю, что вы будете запустить ваше приложение локально на вашем компьютере, и он подключится к вашим каплям через сетевой шлюз

Если вы не знаете свой текущий адрес общественного шлюза, вы можете запустить:

curl ifconfig.io -4

Создать Anbible Файл инвентаря и добавить PlayBook host_vars для каждого хоста. Я назвал мою Digitalocean :

[all]
pg1 ansible_host= connection_host="" node_id=1 role="primary"
pg2 ansible_host= connection_host="" node_id=2 role="standby"
pg3 ansible_host= connection_host="" node_id=3 role="witness"

Добавьте капельки в список известных хостов SSH:

ssh root@ exit
ssh root@ exit
ssh root@ exit

Теперь запустите PlayBook с:

ansible-playbook playbook.yaml -i digitalocean -e "ansible_ssh_user=root"
  • Аргумент рассказывает Anbible бежать на хостах Мы указали
  • -e « передает переменную среды для создания Anbible Connect, как root Пользователь.

Nodejs Application

Давайте напишем простое приложение, которое манипулирует Страны Таблица. Имейте в виду плюрализация в секвенировании Для объектов JavaScript и имена таблиц базы данных по умолчанию. Установите это с:

mkdir sequelize-postgresql-cluster
cd sequelize-postgresql-cluster
npm init -y
npm install pg sequelize

Теперь отредактируйте index.js со следующим:

const { Sequelize } = require('sequelize');

const primary_ipv4 = ''
const standby_ipv4 = ''

// new Sequelize(database, username, password)
const sequelize = new Sequelize('postgres', 'postgres', '123456', {
  dialect: 'postgres',
  port: 5432,
  replication: {
    read: [
      { host: standby_ipv4 },
      { host: primary_ipv4 }
      // witness node has no data, only metadata
    ],
    write: { host: primary_ipv4 }
  },
  pool: {
    max: 10,
    idle: 30000
  },
})

// connect to DB
async function connect() {
  console.log('Checking database connection...');
  try {
    await sequelize.authenticate();
    console.log('Connection has been established successfully.');
  } catch (error) {
    console.error('Unable to connect to the database:', error);
    process.exit(1);
  }
}

Код выше создал Sequelize Объект подключения с именем Sequelize и настроили адреса наших серверов в нем. соединить Функция проверяет соединение с базой данных. Убедитесь, что ваше приложение может подключиться к нему правильно, прежде чем продолжить.

// model
const Country = sequelize.define('Country', {
  country_id: {
    type: Sequelize.INTEGER, autoIncrement: true, primaryKey: true
  },
  name: Sequelize.STRING,
  is_eu_member: Sequelize.BOOLEAN
},
{
  timestamps: false
});

async function create_table() {
  await sequelize.sync({force: true});
  console.log("create table countries")
};

// insert country
async function insertCountry() {
  const pt = await Country.create({ name: "Portugal", is_eu_member: true });
  console.log("pt created - country_id: ", pt.country_id);
}

// select all countries
async function findAllCountries() {
  const countries = await Country.findAll();
  console.log("All countries:", JSON.stringify(countries, null, 2));
}

async function run() {
  await create_table()
  await insertCountry()
  await findAllCountries()
  await sequelize.close();
}

run()

Страна это наш Sequelize Модель, объект JavaScript, который представляет таблицу базы данных. create_table () , insertsountry () и FindallCountries () Функции самоснаженны. Они будут вызваться через Беги () функция.

Запустите свое приложение с помощью:

node index.js

Это создаст Страны Таблица на PostgreSQL База данных, вставьте строку в нее и чтение данных таблицы. Из-за потоковой репликации эти данные будут автоматически реплицироваться в режим ожидания.

(Необязательно) Тест текущего состояния первичной неудачи

Если вы выполните этот шаг, вам нужно вернуть продвижение PostgreSQL и вернуться к начальному состоянию кластера. Есть инструкции для этого в упомянутый учебник .

Выключите свой PG1 капелька (Это можно сделать через интерфейс цифрового океана). Из-за Repmgrd Конфигурация, режим ожидания ( PG2 ) продвигает себя в основную роль, поэтому ваш кластер базы данных продолжает работать. Эта акция заставит ваше приложение все еще умеет читать данные, но не писать. Действуйте, возвращая кластер в предыдущий статус, с PG1 Быть основным узлом.

Используйте плавающий IP

Добавьте плавающий IP-адрес в ваш объект подключения к базе данных приложений

Чтобы воспользоваться плавающим IP, вставьте его в переменную и отредактируйте объект записи Sequelize объект.

// insert this line
const floating_ipv4 = 'your_floating_ip_goes_here'
(...)
// change primary_ipv4 to floating_ipv4
write: { host: floating_ipv4 }

Конфигурация цифрового океана CLI

Как мы настроим PG2 Узел для взаимодействия с цифровым океаном и переназначить плавающий IP на свой IPv4 адрес, мы должны настроить Доктл на этом сервере. Доступ PG2 и сделать следующее:

# as superuser
curl -sL https://github.com/digitalocean/doctl/releases/download/v1.46.0/doctl-1.46.0-linux-amd64.tar.gz | tar -xzv
sudo mv ~/doctl /usr/local/bin
# as postgres
doctl auth init
# insert Digital Ocean API token

Примечание. При использовании в производстве защитите переменную токена API в сценарии конфигурации CLI Digital Ocean и будьте осторожны с переназначенными разрешениями скрипта.

Поместите скрипт ниже на /var/lib/postgresql/proomote-Suctsy.sh с привилегиями исполнения. Он продвигает режим ожидания к первичному, подтверждению Доктл Конфигурация проекта и переназначивает плавающий IP на PG2 Отказ

#!/usr/bin/env bash
# assign digital ocean floating ip address to postgres cluster promoted standby node
# this script is expected to run automatically on a standby node during its automated promotion

# promote PostgreSQL standby to primary
repmgr standby promote -f /etc/repmgr.conf

PROJECT_EXISTS=$(doctl projects list | wc -l)

if [ 2 -gt $PROJECT_EXISTS ]; then
  echo "doctl CLI is not properly configured. Exiting."
  exit 1
fi

CURRENT_NODE_ASSIGNED_NAME=$(doctl compute floating-ip list | awk '{print $4}' | tail -n 1) # pg1
STANDBY_NODE_NAME=$(doctl compute droplet list | grep "pg2" | awk '{print $2}') # pg2
STANDBY_NODE_ID=$(doctl compute droplet list | grep "pg2" | awk '{print $1}') # 
FLOATING_IP_ADDRESS=$(doctl compute floating-ip list | awk '{print $1}' | tail -n 1) # 

echo "$FLOATING_IP_ADDRESS is currently assigned to $CURRENT_NODE_ASSIGNED_NAME. Reassigning to $STANDBY_NODE_NAME."

# remote address change
doctl compute floating-ip-action assign $FLOATING_IP_ADDRESS $STANDBY_NODE_ID

Добавьте скрипт в команду Provote Repmgr

Теперь отредактируйте PG2. Repmgr.conf Файл, чтобы вызвать наши Proomote-suctsisty.sh скрипт на продвижение времени.

promote_command = '/var/lib/postgresql/promote-standby.sh'

Беги Сервис PostgreSQL Restart && Repmgrd применять изменения.

Окончательный статус Первичный неудачный тест

В отличие от ранее, когда вы выключаете PG1 , PG2 Не только продвигает себя, но также берет на себя плавающий IP, который приложение в настоящее время использует для выполнения операций записи. Как PG2 Был уже в Sequelize Переменная читать Массив, теперь он способен и единственную ответственность за данные чтения и записи. Подождите минуту, чтобы продвижение было произойти и снова проверить приложение:

node index.js

Вывод

Изобразите себя в лодке на реке (да, это ссылка на Битлз). Если обе ваши весла ломаются, и только один может быть закреплен на месте, движение лодки станет дефектным, и будет трудно продолжить поездку.

В нашем конкретном случае, прежде чем иметь плавающий IP, ваше приложение восстановит возможности чтения данных через поведение неисправности базы данных — но он не сможет выполнить пишеты в этом состоянии. Теперь, когда ваше приложение следует за новым основным узлом базы данных в автоматических акциях, вы можете залечить кластер и вернуть его в исходное состояние в запланированных условиях и без пропуска, поскольку функции приложений защищены.

Вы можете найти исходный код в этом посте на Github Отказ

Оригинал: «https://dev.to/jscrambler/connecting-sequelize-to-a-postgresql-cluster-4l3p»