I have a simple C++ service (API endpoint) that increases a counter every time the API is called. When the caller posts data to http://10.0.0.1/add the counter has to be incremented by 1 and return the value of the counter to the caller.
Things get more complicated when the service is getting dockerized. When two instances of the same service run the addition has to be done atomically, ie the counter value is stored in a database and each docker instance has to acquire a lock get the old value, add one, return to the caller and unlock.
When the instances are processes in the same Linux machine, we used shared memory to efficiently lock, read, write and unlock the shared data and the performance was accepted. However when we use dockers and a database the performance is low. The results are OK, however the performance is low.
What is the canonical way between instances of dockerized properties to perform operations like the one described above? Is there a "shared memory" feature for containerized processes?
It looks like for your case database is overhead. You just need some distribute lightweight key-value storage with shared key lock support. Here are some candidates:
The
--ipc
option ofdocker run
enables shared-memory access between containers:This article provides some demonstration of its usage.
I was facing a similar problem, and decided to dig in it head on.
The only thing that goes fast is domain sockets. So i created a small c-program that listens on a domain socket, on a shared volume /sockets.
see a working concept on test on gitlab.com.
counter.c
does the job, listens on sockets/count.sock and on receipt of a single char in a datagram:for concept testing:
counter --interval=1000000
=> starts the countertest_counter --repeats=100000 stress
=> sents 100k request to the sockettest_counter reset
set's counter to 0test_counter --quiet --strip result
returns the counter without\n
test_counter [count]
increments the counter and returns result.2 docker containers are build:
count
&test
repoand to test, I used docker-compose.yml in a gitlab-runner:
to start test:
Concept Test Success full!!! see test Job
cavecat:
for client implementation, client socket cannot be bind as auto, but need to be given a name, see in test we use the hostname, mapped in the same /sockets volume. Also they need to be different for each client.