4 ms·
A few weeks ago, I decided to lock myself in my apartment and write a build system. I have always felt like developers wait ages for Docker, and I wanted to se
by jrockway 3y ago
A few weeks ago, I decided to lock myself in my apartment and write a build system. I have always felt like developers wait ages for Docker, and I wanted to see why. (Cycle times on the app I develop are a minute for my crazy combination of shell scripts that I use, or up to 5 minutes for what most of my teammates do. This is incomprehensibly unproductive.)
It turns out, it's all super crazy at every level. Things like Docker use incredibly slow algorithms like SHA256 and gzip by default. For example, it takes 6 seconds to gzip a 150MB binary, while zstd -fast=3 achieves the same ratio and does it in 100 milliseconds! The OCI image spec allows Zstandard compression, so this is something you can just do to save build time and container startup time. (gzip, unsurprisingly, is not a speed demon when decompressing either.) SHA256, used everywhere in the OCI ecosystem, is also glacial; a significant amount of CPU used by starting or building containers is just running this algorithm. Blake3 is 17 times faster! (Blake2b, a fast and more-trusted hash than blake3, is about 6x faster.) But unfortunately, Docker/OCI only support SHA256, so you are stuck waiting every time you build or pull a container. (On the building side, you actually have to compute layer SHA256s twice; once for the compressed data and once for the uncompressed data.
I don't know what happens if you don't do this, I just filled in every field the way the standard mandated and things worked.)
This was on HN a couple years ago and was a real eye opener for me: https://jolynch.github.io/posts/use_fast_data_algorithms/ https://jolynch.github.io/posts/use_fast_data_algorithms/
There are also things that Dockerfiles preclude, like building each layer in parallel. I don't use layers or shell commands for anything; I just put binaries into a layer. With a builder that doesn't use Dockerfiles, you can build all the layers in parallel and push some of the earlier layers while the later ones are building. (One of the reasons I wrote my own image assembler is because we produce builds for each architecture. The build machine has to run an arm64 qemu emulator so that a Dockerfile-based build can run `[` to select the right third-party binary to extract. This is crazy to me; the decision is static and unchanging, so no code needs to be run. But I know that it's designed for stuff like "FROM debian; RUN apt-get update; RUN apt-get upgrade" which is ... not needed for anything I do.)
The other thing that surprises me about pushing images is how slow a localhost->localhost container push is. I haven't looked into why because the standard registry code makes me cry, but I plan to just write a registry that stores blobs on disk, share the disk between the build environment and the k8s cluster (hostpath provisioner or whatever), and have the build system just write the artifacts it's building into that directory; thus there is no push step required. When the build is complete, the artifacts are available for k8s to "pull".
The whole thing is a work in progress, but with a week of hacking I got the cycle time down from 1 minute to about 5 seconds, and many more improvements are available. (Eventually I plan to build everything with Bazel and remote execution, but I needed the container builder piece for multi-architecture releases; Bazel will have to be invoked independently for each architecture because of its design, and then the various artifacts have to be assembled into the final image list.)
- oconnor663 3y ago> Blake3 is 17 times faster! (Blake2b, a fast and more-trusted hash than blake3, is about 6x faster.) I'm a little surprised to see that 6x figure. Just going off the red bar chart at blake2.net, I wouldn't expect to see much more than a 2x difference, unless you're measuring a sub-optimal SHA256 implementation. And recent x86 CPUs have hardware acceleration for SHA256, which makes it faster than BLAKE2b. But those CPUs also have wide vector registers and lots of cores, so BLAKE3's relative advantage tends to grow even as BLAKE2b falls behind. But in any case, yes, builds and containers tend to be great use cases for BLAKE3. You've got big files that are getting hashed over and over, and they're likely to be in cache. An expensive AWS machine can hit crazy numbers like 100 GB/s on that sort of workload, where the bottleneck ends up being memory bandwidth rather than CPU speed.
- jrockway 3y agoYeah, I'm not using any special implementation of sha256. Just crypto/sha256 from the standard library. It's also worth noting that I'm testing on a zen2 chip. I have read a lot of papers saying that sha2 is much faster because CPUs have special support; didn't see it in practice. (No AVX-512 here, but I believe those algorithms predate AVX-512 anyway.)
- saltcured 3y agoThe normal sha256sum CLI program in Fedora Linux seems to use these extensions. On a couple older Intel x86_64 systems without the extension, I get around 300 MiB/s hashing a ~15 MB file. On a Ryzen 3700u laptop I get around 1250 MiB/s. And I also get around 1380 MiB/s on an an aarch64 ARM vCPU on AWS (t4g instance type).
- jiggawatts 3y agoIt’s included with the AES-NI instruction set, which is quite old now and included on most computers.