# Big performance differences: Debian (Bullseye) vs Alpine-based Redis images (Docker)

**URL:** <https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723>\
**Category:** 🏷️ General\
**Tags:** docker, performance, alpine\_linux, redis, docker-compose\
**Created:** [May 9, 2023, 1:25am UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723 "2023-05-09T01:25:29Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![jtr](https://help.nextcloud.com/letter_avatar/jtr/32/5_5575768a8748004e209b776fc1b2916d.png) [@jtr](https://help.nextcloud.com/u/jtr)\
**Post date:** [May 9, 2023, 1:25am UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723/1 "2023-05-09T01:25:30Z")

</div>

I recently benchmarked something I’d been curious about for awhile. I thought this community might find some of my findings interesting.

Particularly considering the popularity of Alpine based Docker containers and the importance of Redis to Nextcloud.

I run most of my deployments in Docker, and Alpine-based containers are extremely common. They’re often the default in example Docker instructions and example Compose files.

I wanted to assess what, if any, performance impact arose from using Alpine (which is musl libc based) versus Debian (which is glibc based). There are other trade-off and advantages to both, but my interest here was performance. If you don’t know what I’m even referring to that’s okay - you can still benefit.

Redis comes with a nice little benchmarking tool that makes quick and dirty testing easy. It’s modestly called `redis-benchmark`. You can run the same tests I did using the general default test based like so:

`time redis-benchmark -q`

The differences were far more dramatic than I expected.

Here are two representative samplings from of my test runs. I simply used the standard available Docker images available for Redis. Redis gives the user the choice of which variant container OS to run - Alpine or Bullseye (aka: Debian) - by way of appending the appropriate tag to your image name in your Docker Compose file or in your CLI syntax. This is fairly typical for most available commonly used off-the-shelf Docker images. All tests were done on the same hardware back to back around a half dozen times each.

A representative pair of results are below.

After testing and concluding which variant _I_ preferred to run, I promptly transitioned (particularly given it’s as easy as just changing which image is referenced in my Compose files). Can you guess which I chose? (Hint: The big picture number is the _real_ wall clock time it took to run each benchmark - so the lower that figure is the better. I’ve added asterisks below to call that figure out).

**Redis v7.0.10 Alpine Docker Image**  
_TCP (Localhost)_

```auto
PING_INLINE: 95969.28 requests per second, p50=0.263 msec
PING_MBULK: 94607.38 requests per second, p50=0.263 msec
SET: 96153.85 requests per second, p50=0.263 msec
GET: 96246.39 requests per second, p50=0.263 msec
INCR: 97370.98 requests per second, p50=0.255 msec
LPUSH: 97276.27 requests per second, p50=0.255 msec
RPUSH: 97560.98 requests per second, p50=0.255 msec
LPOP: 96525.09 requests per second, p50=0.263 msec
RPOP: 96246.39 requests per second, p50=0.263 msec
SADD: 96432.02 requests per second, p50=0.263 msec
HSET: 96618.36 requests per second, p50=0.263 msec
SPOP: 96805.42 requests per second, p50=0.263 msec
ZADD: 95877.28 requests per second, p50=0.263 msec
ZPOPMIN: 97560.98 requests per second, p50=0.255 msec
LPUSH (needed to benchmark LRANGE): 97943.19 requests per second, p50=0.255 msec
LRANGE_100 (first 100 elements): 31496.06 requests per second, p50=0.791 msec
LRANGE_300 (first 300 elements): 12377.77 requests per second, p50=2.007 msec
LRANGE_500 (first 500 elements): 8471.70 requests per second, p50=2.935 msec
LRANGE_600 (first 600 elements): 7355.10 requests per second, p50=3.407 msec
MSET (10 keys): 94250.71 requests per second, p50=0.263 msec

**real 0m 53.29s**
user 0m 28.02s
sys 0m 24.99s

```

**Redis v7.0.10 Bullseye (Debian) Docker Image**  
_TCP (localhost)_

```auto
PING_INLINE: 99700.90 requests per second, p50=0.255 msec
PING_MBULK: 99502.48 requests per second, p50=0.255 msec
SET: 99403.58 requests per second, p50=0.255 msec
GET: 99800.40 requests per second, p50=0.255 msec
INCR: 99601.60 requests per second, p50=0.255 msec
LPUSH: 99108.03 requests per second, p50=0.255 msec
RPUSH: 98135.42 requests per second, p50=0.255 msec
LPOP: 98716.68 requests per second, p50=0.255 msec
RPOP: 99108.03 requests per second, p50=0.255 msec
SADD: 98522.17 requests per second, p50=0.255 msec
HSET: 98135.42 requests per second, p50=0.255 msec
SPOP: 97087.38 requests per second, p50=0.255 msec
ZADD: 98716.68 requests per second, p50=0.255 msec
ZPOPMIN: 99800.40 requests per second, p50=0.255 msec
LPUSH (needed to benchmark LRANGE): 99601.60 requests per second, p50=0.255 msec
LRANGE_100 (first 100 elements): 59988.00 requests per second, p50=0.415 msec
LRANGE_300 (first 300 elements): 26553.37 requests per second, p50=0.911 msec
LRANGE_500 (first 500 elements): 18723.09 requests per second, p50=1.303 msec
LRANGE_600 (first 600 elements): 16520.73 requests per second, p50=1.495 msec
MSET (10 keys): 97656.24 requests per second, p50=0.255 msec

**real 0m33.045s**
user 0m17.631s
sys 0m15.112s

```

Caveat: As with all generalized benchmarking, the real performance benefit depends on the _specific_ use case. Digging into that will have to wait for another day.

---

<div class="post-metadata">

**Author:** ![dugite-code](https://help.nextcloud.com/user_avatar/help.nextcloud.com/dugite-code/32/6434_2.png) [@dugite-code](https://help.nextcloud.com/u/dugite-code)\
**Post date:** [May 9, 2023, 7:03am UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723/2 "2023-05-09T07:03:18Z")

</div>

That’s a surprising difference. I have read that there are similar performance improvements reported for other applications when comparing Alpine with other distro containers. It’s always described as Alpine being aimed at minimizing storage size vs light weight operations.

I wonder if the Nextcloud container and DB containers see similar performance differences?

---

<div class="post-metadata">

**Author:** ![dugite-code](https://help.nextcloud.com/user_avatar/help.nextcloud.com/dugite-code/32/6434_2.png) [@dugite-code](https://help.nextcloud.com/u/dugite-code)\
**Post date:** [May 9, 2023, 8:11am UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723/3 "2023-05-09T08:11:04Z")

</div>

I did some reading and found this interesting discussion regarding why there is such a difference

> Yes. It is known that some workloads, mostly involving malloc, and heavy  
> amounts of C string operations benchmark poorly verses glibc.
> 
> This is largely because the security hardening features of musl and  
> Alpine are not zero cost, but also because musl does not contain  
> micro-architecture specific optimizations, meaning that on glibc you  
> might get strlen/strcpy type functions that are hand-tuned for the exact  
> CPU you are using.
> 
> In practice though, performance is adequate for most workloads.

[https://lists.alpinelinux.org/~alpine/users/\<6df8863e77b970b466dbfc9a3a5c2bcec3199f48.camel%40aquilenet.fr\>](https://lists.alpinelinux.org/%7Ealpine/users/%3C6df8863e77b970b466dbfc9a3a5c2bcec3199f48.camel%40aquilenet.fr%3E)

---

<div class="post-metadata">

**Author:** ![wwe](https://help.nextcloud.com/user_avatar/help.nextcloud.com/wwe/32/72963_2.png) [@wwe](https://help.nextcloud.com/u/wwe)\
**Post date:** [February 27, 2024, 8:48am UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723/4 "2024-02-27T08:48:02Z")

</div>

I just found this topic and really surprised about result. My tests with current version confirm the findings with slightly different numbers. while the numbers from benchmark tool differ only slightly the time difference is huge 0m42s vs 1m5s I would have never expected this!

the conclusion remains the same: redis based on Debian perfroms way faster than Alpine!

## redis:alpine:7.2.4

```auto
PING_INLINE: 72568.94 requests per second, p50=0.335 msec
PING_MBULK: 75642.96 requests per second, p50=0.335 msec
SET: 75872.54 requests per second, p50=0.335 msec
GET: 76511.09 requests per second, p50=0.335 msec
INCR: 76335.88 requests per second, p50=0.335 msec
LPUSH: 76045.62 requests per second, p50=0.327 msec
RPUSH: 76745.97 requests per second, p50=0.327 msec
LPOP: 75930.14 requests per second, p50=0.335 msec
RPOP: 75872.54 requests per second, p50=0.335 msec
SADD: 76452.60 requests per second, p50=0.327 msec
HSET: 76103.50 requests per second, p50=0.335 msec
SPOP: 76628.36 requests per second, p50=0.327 msec
ZADD: 75872.54 requests per second, p50=0.335 msec
ZPOPMIN: 75018.76 requests per second, p50=0.335 msec
LPUSH (needed to benchmark LRANGE): 76569.68 requests per second, p50=0.327 msec
LRANGE_100 (first 100 elements): 21687.27 requests per second, p50=1.103 msec
LRANGE_300 (first 300 elements): 11984.66 requests per second, p50=2.063 msec
LRANGE_500 (first 500 elements): 7208.77 requests per second, p50=3.415 msec
LRANGE_600 (first 600 elements): 6277.86 requests per second, p50=3.927 msec
MSET (10 keys): 75872.54 requests per second, p50=0.335 msec
XADD: 76277.65 requests per second, p50=0.335 msec

real 1m5.312s
user 0m0.027s
sys 0m0.011s

```

## redis:bookworm:7.2.4

```auto
PING_INLINE: 77519.38 requests per second, p50=0.327 msec
PING_MBULK: 77220.08 requests per second, p50=0.327 msec
SET: 77760.50 requests per second, p50=0.327 msec
GET: 78003.12 requests per second, p50=0.327 msec
INCR: 73800.73 requests per second, p50=0.327 msec
LPUSH: 76045.62 requests per second, p50=0.327 msec
RPUSH: 76745.97 requests per second, p50=0.327 msec
LPOP: 74906.37 requests per second, p50=0.327 msec
RPOP: 77881.62 requests per second, p50=0.327 msec
SADD: 77579.52 requests per second, p50=0.327 msec
HSET: 77101.00 requests per second, p50=0.327 msec
SPOP: 78308.54 requests per second, p50=0.327 msec
ZADD: 76511.09 requests per second, p50=0.327 msec
ZPOPMIN: 77101.00 requests per second, p50=0.327 msec
LPUSH (needed to benchmark LRANGE): 77339.52 requests per second, p50=0.327 msec
LRANGE_100 (first 100 elements): 51652.89 requests per second, p50=0.479 msec
LRANGE_300 (first 300 elements): 24378.35 requests per second, p50=0.999 msec
LRANGE_500 (first 500 elements): 16815.20 requests per second, p50=1.415 msec
LRANGE_600 (first 600 elements): 13800.72 requests per second, p50=1.663 msec
MSET (10 keys): 75872.54 requests per second, p50=0.327 msec
XADD: 76569.68 requests per second, p50=0.327 msec

real 0m41.515s
user 0m0.015s
sys 0m0.016s

```

---

<div class="post-metadata">

**Author:** ![jtr](https://help.nextcloud.com/letter_avatar/jtr/32/5_5575768a8748004e209b776fc1b2916d.png) [@jtr](https://help.nextcloud.com/u/jtr)\
**Post date:** [February 27, 2024, 2:33pm UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723/5 "2024-02-27T14:33:34Z")

</div>

Yeah, the bulk of the benchmark differences are in the LRANGE element retrieval tests.

---

<div class="post-metadata">

**Author:** ![ernolf](https://help.nextcloud.com/user_avatar/help.nextcloud.com/ernolf/32/77874_2.png) [@ernolf](https://help.nextcloud.com/u/ernolf)\
**Post date:** [July 12, 2024, 11:10am UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723/6 "2024-07-12T11:10:42Z")

</div>

> [@jtr](#):
>
> the bulk of the benchmark differences are in the LRANGE element retrieval tests

Yes, exactly.  
This makes it to a purely academic question with no reference to nextcloud, as this operation is not used anywhere in Nextcloud or its apps.

Here it lies unused in the source folder: [Code search results · GitHub](https://github.com/search?q=repo%3Anextcloud%2Fserver+%22+LRANGE%22&type=code)

This is how you can monitor it yourself:

```sh
redis-cli MONITOR | while read line; do if [["$line" == *"LRANGE"*]]; then echo "$line"; fi; done

```

You can run this while you’re on vacation and when you come back, there will still be no hit. 😉

My conclusion: The “Big” in the title is sensationalism. In practice, these are imperceptible differences.  
The advantages of musl-libc outweigh the disadvantages here.

What this looks like for other databases such as PostgreSQL, MariaDB/MySQL would have to be tested separately using adequate practical benchmark tools.

Has anyone done that so far?

The question then is whether it affects typical use cases of nextcloud, since its development is consistently geared towards optimization - (keyword indexes).

* * *

Much and good luck,  
ernolf

---

<div class="post-metadata">

**Author:** ![szaimen](https://help.nextcloud.com/user_avatar/help.nextcloud.com/szaimen/32/63019_2.png) [@szaimen](https://help.nextcloud.com/u/szaimen)\
**Post date:** [July 12, 2024, 11:29am UTC](https://help.nextcloud.com/t/big-performance-differences-debian-bullseye-vs-alpine-based-redis-images-docker/161723/7 "2024-07-12T11:29:58Z")

</div>

> [@ernolf](#):
>
> What this looks like for other databases such as PostgreSQL, MariaDB/MySQL would have to be tested separately using adequate practical benchmark tools.
> 
> Has anyone done that so far?

I would also be interested in such test results for postgres 🙂
