linux - hub - Cómo actualizar atómicamente un contador compartido entre instancias de Docker
docker hub (3)
Tengo un servicio C ++ simple (punto final API) que aumenta un contador cada vez que se llama a la API. Cuando la persona que llama publica datos en http://10.0.0.1/add, el contador debe incrementarse en 1 y devolver el valor del contador a la persona que llama.
Las cosas se vuelven más complicadas cuando el servicio está siendo encajado. Cuando se ejecutan dos instancias del mismo servicio, la adición tiene que hacerse atómicamente, es decir, el valor del contador se almacena en una base de datos y cada instancia de acoplador debe adquirir un bloqueo obtener el valor anterior, agregar uno, regresar al llamador y desbloquearse.
Cuando las instancias son procesos en la misma máquina Linux, utilizamos la memoria compartida para bloquear, leer, escribir y desbloquear eficientemente los datos compartidos y se aceptó el rendimiento. Sin embargo, cuando usamos estibadores y una base de datos, el rendimiento es bajo. Los resultados están bien, sin embargo, el rendimiento es bajo.
¿Cuál es la forma canónica entre instancias de propiedades dockerized para realizar operaciones como la descrita anteriormente? ¿Hay una función de "memoria compartida" para los procesos en contenedores?
Parece que su base de datos de casos está sobrecargada. Solo necesita distribuir el almacenamiento ligero-valor ligero con soporte de bloqueo de clave compartido. Aquí hay algunos candidatos:
- etcd ( https://coreos.com/etcd )
- cónsul ( https://www.consul.io , especialmente https://www.consul.io/docs/commands/lock.html )
- redis ( http://redis.io )
La opción --ipc
de docker run
habilita el acceso a memoria compartida entre contenedores:
Configuración de IPC (--ipc)
--ipc=""
: configura el modo IPC para el contenedor,
''container:<name|id>''
: reutiliza el espacio de nombres IPC de otro contenedor
''host''
: use el espacio de nombres IPC del host dentro del contenedorPor defecto, todos los contenedores tienen habilitado el espacio de nombres IPC.
El espacio de nombres IPC (POSIX / SysV IPC) proporciona la separación de segmentos de memoria compartida nombrados, semáforos y colas de mensajes.
Los segmentos de memoria compartida se usan para acelerar la comunicación entre procesos a la velocidad de la memoria, en lugar de a través de las tuberías o a través de la pila de la red. La memoria compartida es comúnmente utilizada por las bases de datos y las aplicaciones personalizadas (generalmente C / OpenMPI, C ++ / using boost libraries) de alto rendimiento para la informática científica y las industrias de servicios financieros. Si estos tipos de aplicaciones se dividen en varios contenedores, es posible que deba compartir los mecanismos de IPC de los contenedores.
Este artículo proporciona alguna demostración de su uso.
Estaba enfrentando un problema similar y decidí investigarlo.
Lo único que pasa rápido son los sockets de dominio. Así que creé un pequeño c-programa que escucha en un socket de dominio, en un volumen / sockets compartidos.
ver un concepto de trabajo en prueba en gitlab.com.
counter.c
hace el trabajo, escucha en sockets / count.sock y al recibir un solo carácter en un datagrama:
- ''+'': aumentará el conteo y devolverá el conteo como u_int64_t
- ''0'': restablece el recuento y devuelve el valor 0 como u_int64_t
- ''='': devuelve el recuento como u_int64_t, sin incremento
- ''-'': decremento cuenta con uno y devuelve conteo como u_int64_t
para la prueba de concepto:
-
counter --interval=1000000
=> inicia el contador -
test_counter --repeats=100000 stress
=> indica 100k petición al socket -
test_counter reset
el contador del conjunto a 0 -
test_counter --quiet --strip result
devuelve el contador sin/n
-
test_counter [count]
incrementa el contador y devuelve el resultado.
Se construyen 2 contenedores docker: count
y test
y para probar, utilicé docker-compose.yml en un 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}
para comenzar la prueba:
mkdir sockets
docker-compose pull --parallel
docker-compose up -d
docker-compose scale my-test=$SCALE
Prueba de concepto de éxito completo !!! ver prueba Job
cavecat:
para la implementación del cliente, el socket del cliente no puede vincularse como automático, sino que necesita un nombre, ver en la prueba que usamos el nombre del servidor, mapeado en el mismo volumen / sockets. También deben ser diferentes para cada cliente.