Как атомизировать обновление счетчика, разделяемого между экземплярами Docker
У меня есть простая служба С++ (конечная точка API), которая увеличивает счетчик каждый раз, когда вызывается API. Когда вызывающий абонент отправляет данные в http://10.0.0.1/add, счетчик должен увеличиваться на 1 и возвращать значение счетчика вызывающему.
Все становится сложнее, когда служба получает докеры. Когда два экземпляра одного и того же сервиса запускаются, добавление должно выполняться атомарно, то есть значение счетчика сохраняется в базе данных, и каждый экземпляр докера должен получить блокировку, получить старое значение, добавить один, вернуться к вызывающей стороне и разблокировать.
Когда экземпляры являются процессами на одной машине Linux, мы использовали общую память для эффективной блокировки, чтения, записи и разблокировки общих данных, и производительность была принята. Однако, когда мы используем докеры и базу данных, производительность низкая. Результаты в порядке, однако производительность низкая.
Каков канонический путь между экземплярами докционированных свойств для выполнения операций, подобных описанным выше? Есть ли функция "разделяемой памяти" для контейнерных процессов?
Ответы
Ответ 1
Похоже, что для вашей базы данных case накладные расходы. Вам просто нужно распределить легкое хранилище ключей с поддержкой общей блокировки ключей. Вот некоторые кандидаты:
Ответ 2
Параметр --ipc
docker run
обеспечивает доступ к общей памяти между контейнерами:
Настройки IPC (-ipc)
--ipc=""
: установите режим IPC для контейнера,
'container:<name|id>'
: повторное использование другого пространства имен IPC контейнера
'host'
: используйте пространство имен IPC хоста внутри контейнера
По умолчанию все контейнеры имеют пространство имен IPC.
Пространство имен IPC (POSIX/SysV IPC) обеспечивает разделение именованных общих сегменты памяти, семафоры и очереди сообщений.
Общие сегменты памяти используются для ускорения межпроцессного взаимодействия связь на скорости памяти, а не через трубы или через сетевой стек. Общая память обычно используется базами данных и (как правило, C/OpenMPI, С++/с использованием библиотек boost) приложений для научных вычислений и финансовых услуг. Если эти типы приложений разбиты на вам может потребоваться совместное использование механизмов IPC для контейнеры.
В этой статье представлена некоторая демонстрация ее использования.
Ответ 3
У меня возникла аналогичная проблема, и я решил загнать ее в голову.
Единственное, что происходит быстро, это сокеты домена. Поэтому я создал небольшую c-программу, которая прослушивает сокет домена, в общем томе/сокетах.
см. рабочую концепцию test на gitlab.com.
counter.c
выполняет эту работу, слушает сокеты /count.sock и
при получении единственного char в дейтаграмме:
- '+': он увеличит счетчик и вернет счет как u_int64_t
- '0': сбрасывает счетчик и возвращает значение 0 как u_int64_t
- '=': возвращает счетчик как u_int64_t без приращения
- '-': число декрементов с одним и возвращает count как u_int64_t
для тестирования концепции:
-
counter --interval=1000000
= > запускает счетчик
-
test_counter --repeats=100000 stress
= > отправляет запрос 100k в сокет
-
test_counter reset
установить счетчик 0
-
test_counter --quiet --strip result
возвращает счетчик без \n
-
test_counter [count]
увеличивает счетчик и возвращает результат.
2 контейнера докеров собраны: count
и test
repo
и для тестирования я использовал docker-compose.yml в gitlab-runner:
my-test:
image: dockregi.gioxa.com/dgoo2308/dockersocket:test
links:
- counter
entrypoint:
- /test_counter
- --repeats=${REPEATS}
- --timeout=200
- stress
volumes:
- './sockets:/sockets'
counter:
image: dockregi.gioxa.com/dgoo2308/dockersocket:count
volumes:
- './sockets:/sockets'
entrypoint:
- /counter
- --start_delay=100
- --interval=${TARGET}
чтобы начать тест:
mkdir sockets
docker-compose pull --parallel
docker-compose up -d
docker-compose scale my-test=$SCALE
Полноценный тест на тестирование!!! см. тестовое задание
cavecat:
для реализации клиента клиентский сокет не может быть привязан как автоматический, но ему нужно дать имя, см. в тесте мы используем имя хоста, отображаемое в том же томе/сокетах.
Также они должны быть разными для каждого клиента.