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

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

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

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

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

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

Главный  результат  применения  паттерна  Ambassador  к  шар-дированным сервисам — разделение обязанностей между кон-тейнером  приложения  и  шардирующим  прокси.  Контейнер  54 Часть I. Одноузловые паттерны проектирования

приложения знает, что ему надо взаимодействовать с сервисом  хранения,  находящимся  на  локальном  компьютере,  а  шарди-рующий прокси содержит только тот код, который отвечает за  корректное шардирование запросов.

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

Практикум. Шардируем Redis-хранилище Redis  —  высокопроизводительное хранилище  типа  «ключ  —  значение»,  которое  можно  использовать  в  качестве  кэша  или  более  постоянного  места  хранения  данных.  В  этом  примере  мы  задействуем  его  в  качестве  кэша.  Начнем  с  развертывания  шардированного  Redis  на  кластер  Kubernetes.  Для  этого  об-ратимся к API  StatefulSet , поскольку он дает каждому шарду  уникальные DNS-имена, которыми мы воспользуемся при на-стройке прокси.

StatefulSet  для Redis будет выглядеть следующим образом: apiVersion: apps/v1beta1

kind: StatefulSet

metadata:

name: sharded-redis

spec:

serviceName: "redis"

replicas: 3

template:

metadata:

labels:

app: redis

spec:

Глава 3. Паттерн Ambassador 55

terminationGracePeriodSeconds: 10

containers:

- name: redis

image: redis

ports:

- containerPort: 6379

name: redis

Сохраните этот код в файле  redis-shards.yaml , который можно  развернуть командой  kubectl  create  -f  redis-shards.yaml . Она  создаст три контейнера с запущенным Redis. Их можно увидеть,  выполнив команду  kubectl  get  pods . Результат будет таким: sharded-redis-[0,1,2]

Очевидно,  недостаточно  лишь  запустить  несколько  копий  Redis — нам также необходимы имена, по которым к ним мож-но  обращаться.  Воспользуемся  для  этого  Kubernetes  Service,  который назначит DNS-имена созданным репликам. Он будет  выглядеть следующим образом:

apiVersion: v1

kind: Service

metadata:

name: redis

labels:

app: redis

spec:

ports:

- port: 6379

name: redis

clusterIP: None

selector:

app: redis

Сохраните  этот  код  в  файле  redis-shards.yaml   и  разверните  полученный  файл  командой  kubectl   create   -f   redis-shards. yaml . Теперь у вас должны появиться DNS-записи для  sharded-redis-0.redis ,  sharded-redis-1.redis   и  т.  д.  Воспользуем-ся  этими  именами  для  настройки  прокси-сервера  twemproxy. 

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

Это  легковесный,  высокопроизводительный  прокси-сервер  для  memcached  и  Redis,  который  изначально  был  разработан  в Twitter. Его исходный код теперь доступен на GitHub ( https:// github.com/twitter/twemproxy ).

Следующая конфигурация настроит twemproxy на использова-ние созданных нами копий Redis.

redis:

listen: 127.0.0.1:6379

hash: fnv1a_64

distribution: ketama

auto_eject_hosts: true

redis: true

timeout: 400

server_retry_timeout: 2000

server_failure_limit: 1

servers:

- sharded-redis-0.redis:6379:1

- sharded-redis-1.redis:6379:1

- sharded-redis-2.redis:6379:1

Из  конфигурационного  файла  видно,  что  запросы  к  Redis  об-служиваются по адресу  localhost:6379 , так что контейнер прило-жения может получить доступ к контейнеру-послу. Его можно  развернуть  в  «посольскую»  группу  контейнеров,  используя  Kubernetes-объект  ConfigMap ,  который  можно  создать  такой  командой: