144

How to Connect to Redis with Unix Sockets in Docker

 6 years ago
source link: https://medium.com/@jonbaldie/how-to-connect-to-redis-with-unix-sockets-in-docker-9e94e01b7acd
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
1*xcm7a5kEuHxnfCT_eCoUCg.jpeg
Ready to squeeze even more speed out of Redis?

How to Connect to Redis with Unix Sockets in Docker

Connecting to Redis via Unix sockets is usually faster than connecting via TCP/IP.

That’s because in general, Unix sockets have much less overhead. They’re essentially just files that Unix-based systems can read. The downside of that being that only local connections are possible.

At 10M+ pulls, Redis is the fourth most downloaded Docker image, and most systems are set up to connect to Redis via Docker’s own TCP bridge networking.

Docker’s own TCP bridge networking is all fine and dandy, but wouldn’t you like to squeeze out some more speed?

Granted, the increase is small, but it’s not insignificant. Here are some rough comparisons from my own tests:

time redis-benchmark -h 127.0.0.1 -p 6379

48.92 real 36.43 user 11.85 sys

time redis-benchmark -s /tmp/redis.sock

42.90 real 34.96 user 7.42 sys

A 14% speed difference is significant and we should take advantage of this even when using Docker.

But hang on a minute, aren’t Docker containers self-contained and separate? How can we use Unix sockets in that kind of environment?

The answer is that we need to take advantage of shareable Docker volumes.

Say we have a PHP container that runs our app code, with a Redis client built in, that connects to a Redis container.

We need to create a separate container, purely to be the base for a volume we’re going to share with PHP and Redis.

We’ll put the volume on /tmp/docker/ , and tell Redis to put the redis.sock file in that folder.

Wonderfully, this generic folder may also be used for any other files or data you want to share across containers.

We can use the busybox image for this volume container because this container won’t actually be doing anything other than holding the volume.

In the config for the PHP and Redis containers, we use the volumes_from option to extra the same volume from the busybox container.

So our docker-compose.yml file will look a bit like this:

services:
tmp:
image: busybox
command: chmod -R 777 /tmp/docker
volumes:
- /tmp/docker/ php:
image: php
// other app bootstrapping options
volumes_from:
- tmp redis:
image: redis
command: redis-server /etc/redis.conf
volumes:
- /redis/redis.conf:/etc/redis.conf
volumes_from:
- tmp

The important bit is the tmp service and the volumes_from options in the other containers. This is just an illustrative example and of course assumes that you’re correctly copying across redis.conf into the Redis container.

You do need to make sure that Redis is being started with redis.conf, because we need to explicitly tell Redis to create a socket file available for connections.

In your redis.conf file, add the following lines:

unixsocket /tmp/docker/redis.sock
unixsocketperm 777

This will tell Redis to create /tmp/docker/redis.sock upon startup and give it file permissions of 777. I’ve no doubt that ‘777’ will be controversial but it’s up to you — I find that in a contained Docker environment this is perfectly safe.

Then because of the Docker volume we set up, when we up these containers, /tmp/docker/ will be available to the PHP container too, and we can access it in our app code.

Then in your PHP application, tell it to connect to Redis via this Unix socket. If you’re using the popular Predis package, you would do this:

$client = new Predis\Client([
'scheme' => 'unix',
'path' => '/tmp/docker/redis.sock',
]);

If you’re using Laravel, you need to do a bit more work, because the default setup assumes you want to connect to Redis via TCP. So in your.env file, add the following:

REDIS_SCHEME=unix
REDIS_PATH=/tmp/docker/redis.sock

Then in config/database.php, edit the 'redis' section so it looks like the following:

'redis' => [    'client' => 'predis',    'default' => [
// 'host' => env('REDIS_HOST', '127.0.0.1'),
// 'password' => env('REDIS_PASSWORD', null),
// 'port' => env('REDIS_PORT', 6379),
'scheme' => env('REDIS_SCHEME'),
'path' => env('REDIS_PATH'),
'database' => 0,
],],

Live Results

I did the benchmark again, except this time within the setup of one of my apps that runs PHP and relies heavily on Redis.

I was a bit naughty and ran these on my live production server, but I’m of the frame of mind that this is a solid test of how my production environment holds up under load.

time --verbose docker-compose exec redis redis-benchmark -h 127.0.0.1 -p 6379

Command being timed: “docker-compose exec redis redis-benchmark -h 127.0.0.1 -p 6379”
User time (seconds): 0.35
System time (seconds): 0.09
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 1:21.64
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 25344
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 31
Minor (reclaiming a frame) page faults: 14686
Voluntary context switches: 1229
Involuntary context switches: 293
Swaps: 0
File system inputs: 22640
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0

time --verbose docker-compose exec redis redis-benchmark -s /tmp/docker/redis.sock

Command being timed: “docker-compose exec redis-server redis-benchmark -s /tmp/docker/redis.sock”
User time (seconds): 0.37
System time (seconds): 0.04
Percent of CPU this job got: 0%
Elapsed (wall clock) time (h:mm:ss or m:ss): 1:06.77
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 25232
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 46
Minor (reclaiming a frame) page faults: 14708
Voluntary context switches: 1167
Involuntary context switches: 294
Swaps: 0
File system inputs: 21024
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0

The TCP connection makes the benchmark 22% longer than the test using Unix sockets.

I hope this post helps you, if you have any comments don’t forget to hit that ‘Response’ button below, maybe even give me a clap if you feel like this post has helped you. 👍🏻⚡️💪🏻

I have a quick question for you now, since you’re probably a developer if you’re reading this.

Are you making the most common mistakes that most developers make in SQL queries? Want my 2-step algorithm on the perfect index?

Download my free report, MySQL Worst Practices.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK