Распределенные системы. Паттерны проектирования - [20]

Шрифт
Интервал

тоспособности, делая, например, запросы к базе данных? Оркестраторы  контейнеров  наподобие  Kubernetes  также  по-зволяют  задавать  сценарии  оболочки,  проверяющие  работо-способность контейнера. Имея такую возможность, мы можем  написать сложный сценарий оболочки, выполняющий несколь-ко диагностических запросов к базе данных, чтобы определить  степень ее работоспособности. Но где хранить такой сценарий  и как следить за его версиями?

Нетрудно догадаться, как решить эту проблему, — можно исполь-зовать  контейнер-адаптер.  База  данных  работает  в  контейнере  приложения,  который  имеет  общий  с  контейнером-адаптером  сетевой  интерфейс.  Контейнер-адаптер  —  простой  контейнер,  который  содержит  только  сценарий  оболочки,  оценивающий  работоспособность базы данных. Этот сценарий можно настроить  в  качестве  комплексного  средства  проверки  контейнера  СУБД,  выполняющего любую диагностику, необходимую нашему при-

ложению.  Если  контейнер  приложения  когда-либо  не  пройдет  проверку, он будет автоматически перезапущен. Практикум. Комплексный мониторинг работоспособности MySQL

Допустим, вы хотите следить за работоспособностью базы дан-ных  MySQL  путем  периодического  выполнения  запросов,  со-ответствующих  рабочей  нагрузке  вашего  приложения.  Одним  из  вариантов  будет  добавить  в  контейнер  MySQL  проверку  работоспособности, отвечающую вашим требованиям. В общем  случае,  однако,  это  не  очень  желательное  решение,  поскольку  74 Часть I. Одноузловые паттерны проектирования

оно  требует  преобразования  базового  MySQL-образа,  а  также  обновления модифицированного образа по мере выхода новых  версий базового образа.

В  этом  случае  использование  паттерна  Adapter  гораздо  более  привлекательно,  нежели  добавление  проверок  работоспособ-ности  непосредственно  в  базовый  образ.  Вместо  того  чтобы  модифицировать  существующий  контейнер  с  MySQL,  можно  добавить  к  типовому  MySQL-контейнеру  контейнер-адаптер,  который  бы  проверял  состояние  базы  данных.  Учитывая,  что  адаптер  проверяет  работоспособность  посредством  протокола  HTTP, все сводится к определению процесса проверки работо-способности  базы  данных  в  терминах  интерфейса,  предостав-ляемого адаптером.

Исходный текст такого адаптера довольно прост и выглядит на  языке Go следующим образом (очевидно, что его можно реали-зовать и на другом языке):

package main

import (

"database/sql"

"flag"

"fmt"

"net/http"

_ "github.com/go-sql-driver/mysql"

)

var (

user = flag.String("user", "", "Имя пользователя базы данных") passwd = flag.String("password", "", "Пароль к базе данных") db = flag.String("database", "", "К какой базе данных необходимо подключиться")

query = flag.String("query", "", "Тестовый запрос") addr = flag.String("address", "localhost:8080", "По какому IP-адресу принимать запросы")

Глава 4. Адаптеры 75

// Пример использования:

// db-check --query="SELECT * from my-cool-table" \ // --user=bdburns \

// --passwd="you wish"

//

func main() {

flag.Parse()

db, err := sql.Open("localhost", fmt.Sprintf("%s:%s@/%s", *user, *passwd, *db))

if err != nil {

fmt.Printf("Ошибка подключения к базе данных: %v", err)

}

// Простой веб-обработчик, выполняющий запрос http.HandleFunc("", func(res http.ResponseWriter, req *http.Request) {

_, err := db.Exec(*query)

if err != nil {

res.WriteHeader(http.StatusInternalServerError)

res.Write([]byte(err.Error()))

return

}

res.WriteHeader(http.StatusOK)

res.Write([]byte("OK"))

return

})

// Запуск сервера

http.ListenAndServe(*addr, nil)

}

Затем  мы  можем  собрать  контейнер-адаптер  и  поместить  его  в группу, которая будет выглядеть следующим образом: apiVersion: v1

kind: Pod

metadata:

name: adapter-example-health

namespace: default

spec:

containers:

- image: mysql

name: mysql

76 Часть I. Одноузловые паттерны проектирования

- image: brendanburns/mysql-adapter

name: adapter

Контейнер  mysql  остается неизменным, при этом необходимую  обратную связь можно получить от контейнера-адаптера. На  первый  взгляд  может  показаться,  что  такой  вариант  при-менения  паттерна  Adapter  является  излишним.  Мы,  конечно,  можем  собрать  свой  собственный  образ,  который  знает,  как  проверять работоспособность экземпляра  mysql . Это верно, но  подобный  подход  игнорирует  преимущества,  следующие  из  модульности.  Если  каждый  разработчик  будет  реализовывать  свою  собственную  модификацию  контейнера  со  встроенной  проверкой работоспособности, то потеряется возможность по-вторного (или совместного) его использования. Напротив, если применять паттерны вроде Adapter для разра-ботки  модульных  решений,  состоящих  из  нескольких  контей-неров, то приложение естественным образом декомпозируется  на части, которые можно использовать повторно. Адаптер, раз-работанный для проверки работоспособности  mysql , может быть  совместно/повторно использован многими людьми. Кроме того,  разработчики могут применять паттерн Adapter, используя об-щий  контейнер  для  проверки  работоспособности,  не  вдаваясь  в  детали  наблюдения  за  базами  данных  mysql .  Таким  образом,  модульность в целом и паттерн Adapter в частности не только  способствуют совместному применению кода, но и позволяют  воспользоваться знаниями других людей.