Gil's blog

Zappa vs Mangum

Submitted by gil on

Zappa and Mangum[1] are Python libraries that parse events from Amazon's API Gateway and feed them into a Python WSGI or ASGI application. This allows you to put API Gateway in front of a Lambda runtime, have Lambda execute the service requests that come in through API Gateway, and code your service logic in any Python web framework.

But what framework should you use for your next serverless REST API? I say Mangum. Both are mature products and Zappa appears to have been around longer and has more features implemented to show for it. But there are some key features, ranging from nice to have to increasingly required, that Mangum is delivering on and Zappa isn't that makes me recommend Mangum for future uses.

First, Zappa's maintainership hasn't been great. There is constant activity on Zappa, but a lot of low-hanging bug fixes and feature improvements, like the ones I am detailing here, haven't been implemented. Even if it is possible for Zappa to catch up and get these things knocked out the lack of responsible maintainership points to a dying project.

Zappa goes beyond being a shim library to handle WSGI requests and has grown up a small ecosystem of functionality, including the ability to package Lambda zip deployments on your behalf, deploy lambdas for you, create CloudFormation JSON to manage your configuration outside of Zappa, invoke one-off functionality in Lambda outside of the API Gateway request cycle (like a maintenance command), and tail Lambda logs in real time. This is all extremely useful stuff and makes Zappa much more appealing than the bare-bones Mangum. However, Zappa's functionality has slowed its ability to keep up with the latest AWS features. Zappa can only assemble Lambda deployment zip files for x86 Lambdas, not the new, cost-effective Graviton 64-bit ARM CPUs. It also only supports v1 of the API Gateway events, locking you out of a simpler and more cost-effective v2 deployment. Finally, Zappa does not have any way to pass the original Lambda event on to your application code and only extracts the minimum data from the event required to invoke a WSGI request (omitting things such as the IP address of the original request made to API Gateway). This is a really unfortunate one-two punch where Zappa isn't even letting you work around its shortcomings.

If you jump to Mangum you'll have a bit more of a pull ahead of you. There's no tooling to package and deploy a Lambda for you so you'll have to do some DevOps work to create that pipeline. But if you dig in and get it done yourself you could assemble a Docker image for Lambda on the the Graviton CPUs, something not available to you at all with Zappa. Using a Docker image lets you get around the 50 MB limit on zip files for the Lambda deployment. If you are using one of the many WSGI-only web frameworks you may be put off by Mangum's lack of support for WSGI. However, there is an open source WSGI-to-ASGI adapter that will let you connect any existing WSGI code into Mangum, so ASGI-only is not as limiting as it sounds. Mangum is also doing a better job at parsing the API Gateway event payloads, supports the latest version of API Gateway, and even lets you write WebSocket APIs.

Taking the tradeoffs into account, even though Mangum does not offer as much overall functionality as Zappa does right now, it still supports the core, important functionality that you'll increasingly need to use in the future, like 64-bit ARM Lambdas, support for the new AWS APIs, and support for ASGI frameworks. For those reasons I recommend using Mangum for new API Gateway projects with Python.


[1] Zappa is named after musician Frank Zappa who needs no introduction. Mangum is named after Jeff Mangum, of the band Neutral Milk Hotel, best known for an album about Anne Frank and "semen stains the mountaintops."

ngx_brotli for Debian bullseye and buster

Submitted by gil on

UPDATE: nginx support for brotli is now in Debian!. I've removed my fork as I am no longer maintaining it, please move onto Debian's official package.

Debian does not yet ship ngx_brotli (libnginx-mod-brotli) so I've compiled Ondřej Surý's work so it can be used by everyone on Debian bullseye (Debian 11) and buster (Debian 10).

To install, download the latest version of the .deb from the GitHub releases page and install it with:

sudo dpkg -i libnginx-mod-brotli*.deb

Next, you must enable the module:

sudo ln -s /usr/share/nginx/modules-available/mod-brotli.conf /etc/nginx/modules-enabled/50-mod-brotli.conf

Edit your nginx configuration in /etc/nginx to make use of ngx_brotli. Typically, this means adding brotli_static on; or brotli on; to the relevant parts of your configuration.

Finally, restart nginx to load the new configuration and modules:

sudo systemctl restart nginx

And that's it!

Frequently asked questions

Help! I'm trying to install a security update for nginx or update nginx on my system. Apt is forcing me to uninstall libnginx-mod-brotli because its dependencies are unmet. What do I do?

You must install the version of libnginx-mod-brotli that precisely matches the version of nginx on your system. Download a new version from the GitHub releases page and reinstall that. If a new version is not available yet please open an issue on the GitHub page and I will upload a new version as soon as I can. It may be prudent to uninstall libnginx-mod-brotli before updating nginx and re-install the new version of libnginx-mod-brotli immediately after updating nginx to avoid complications with apt.

Can you provide an apt repo with this package in it?

Maybe later!

Demand for computing power

Submitted by gil on

I'm putting my prediction hat on again, let's come back in a year and see how well I've done.

It's well known that Intel has fallen behind TSMC's fab technology. I think this is the beginning of a trend that will drive up the cost for computing power across the market. Big buyers of semiconductors, who carefully forecast their own growth in demand for computing power, also estimate the lower costs and improved performance that come with each generation and use that to guide their budgets. When Intel starts stumbling and comes up short, with chips that offer less computation or more electricity draw than expected, these buyers suffer as they now have to increase the volume of their buys of chips that aren't as marginally effective as expected. It's a big capital demand up front and a higher total cost over the lifetime of the hardware. Increased demand from the biggest volume buyers means increased cost to the smaller buyers who are also suffering from the higher total cost and missed performance of those chips. Our old hardware doesn't go away, and the new supply of chips doesn't disappear. But this is a big enough supply chain disruption to drive up the cost of computing power for a decade.

So what does this mean for the software industry? The cost of self-hosting is going up but so is the cost of cloud computing. If capital costs are high expect businesses to lower headcounts and hire fewer engineers to do more. I expect that we'll see a move away from productive but computationally inefficient ecosystems like Python and Ruby and towards more computationally efficient ecosystems like Rust, Swift and C++. I don't know if Java, C# and Javascript - the languages with top-tier JITs - are in one category or the other, but they're probably more efficient than not. They might suffer more from the decrease in headcounts over their increased capital costs.

Disk caching in the year 2020

Submitted by gil on

In the previous blog post I went over the design of storage systems and how they protect themselves from data loss in the face of disk failure or unclean shutdowns. If you’re putting together the hardware yourself modern Linux systems and modern hardware give you endless cost, performance and durability tradeoffs for whatever system you want. But 2020 also gives us the cloud, and storage systems in the cloud whose durability far exceeds whatever you could build yourself. Cloud providers also have the scale to amortize the insane costs of these exotic, durable, and yet still performant system designs across their broad user bases, bringing down their prices and making them accessible to us mortals. In the year 2020, if you’re in the cloud, durability just isn’t a concern to you so it is time to start focusing on performance.

Caching basics in 2020

2020 also brings affordable, reliable and speedy SSDs, and if you’re designing a system yourself you want to have some way to take advantage of SSD performance. Building everything out of SSDs isn’t an awful choice, it’ll be simple and probably won’t even cost that much. However, the expected usage of most storage systems will have some bulk of data rarely read or written giving an opportunity to reduce marginal costs with tiered storage. If you have a way to keep cold data on slower but cheaper magnetic disks and can use SSDs when appropriate this tiered storage design gives you the speed benefits of SSDs when you need them the most and the cost benefits of magnetic disks.

Tiered storage introduces complexity back into the storage system, increasing operational overhead and the risk of data loss. If you can implement tiered storage at the application layer you have some of the best tools available to you to tame that complexity. For example, a filer could keep some file shares known to be cold, like backups, directly on magnetic storage and others known to be hot directly on SSD storage. A database could have tablespaces for slow and fast storage and assign cold and hot tables to each. You could keep table indexes in fast storage with reduced reliability knowing that disk failures in the fast storage won’t cause unrecoverable data loss. These are all simple systems, with well-understood failure modes and controlled operational complexity. They also give you the most benefit from SSD performance because their simplicity skips the CPU and I/O overhead introduced by more complex systems.

But what if your application layer doesn’t give you tiered storage? What if you can’t afford the operational complexity required to maintain it yourself? Delegating where the data goes initially is easy, but moving it around is harder. And assumptions can change, with cold data becoming warm, and you need continuous feedback to make and question your storage decisions. Caching is the next choice, where the system makes decisions on where to keep data automatically. It’s usable anywhere and can bring its benefits to every storage system but it comes at the cost of potentially suboptimal usage of the fast storage and a potentially increased risk of data loss.

Caches typically implement multiple caching algorithms, giving you more tradeoffs between speed, durability and cost. Writeback caching has all data written to fast storage first and later copied asynchronously to the slow storage. It gives the best performance as cache reads can use data from the newest writes immediately and writes go at the speed of the fast pool. But should your fast storage system suffer data loss before the asynchronous copy finishes you’ll have permanent data loss. Your system performance also hinges on the intelligence of the writeback cache algorithm more than other algorithms. Imagine a system that does backups - if the writeback cache is unable to determine that backup writes are cold and shouldn’t fill up the cache you’ll wind up evicting all the useful data for extremely cold data. This logic can’t be simplified or formalized for general use and requires tuning and measurement.

Writearound caching has writes go directly to slow storage and only reads make use of the cache. It’s a blunt tool, unable to improve write speeds, and unable to cache recently written data, but it never has to implement the dark art algorithms like writeback does to get good performance against pathological workloads. You also won’t lose data if your cache disk dies. There is also writethrough caching where writes are done to both fast and slow disks at the same time, improving the cache hit rate of recently written data but still limiting your write speed to the speed of the slow disk.

The previous blog post introduced the RAID write hole and a few techniques to close it. If you’re building your own storage system you are probably considering RAID and using one of those techniques to improve the durability of the system. Journaling is a well-supported and reliable way to close the write hole and under the hood these journals are often just writeback/writethrough/writearound caches, with all of the benefits and drawbacks as described above. In other words, a RAID array of magnetic disks with large enough SSD journals is also a RAID array with SSD cache. Journal disk failure is still a threat, putting the less aggressive cache algorithms into strong consideration, because an unfortunate disk failure in a writeback journal results in losing all data on the entire array.

The storage available to you in the cloud shifts your priorities the other way. Durability is a given as discussed earlier and you’re now looking to squeeze what performance you can out of your design. More aggressive caching algorithms like the writeback cache are now in scope and should be seriously considered, even for ordinary cloud setups.

Finally, I want to cover the Linux buffer and page caches, just for completeness. Your application's I/O hits these first and all of the other cache systems later. If a cache hit is done here any other disk caching code is never run at all. A 2017 summary of the history, current state and future of these Linux caches is on LWN. The page cache carves system memory up into equally sized pages, typically 4 kilobytes, and maintains attributes on each page's uses. A page could cache a region of data on a disk, meaning that the page's contents directly correspond to 4 kilobytes on a disk somewhere. A read request fills that cached page and future reads can be serviced by that page. A write to the disk updates the cached page and marks it as dirty, signalling the kernel to rewrite the corresponding data on the disk at its leisure. The buffer cache is a legacy API, internal to the kernel, that is implemented on top of the page cache. This API works with smaller units of data, called blocks, that are mapped onto relevant page cache entries for each file. Reads and writes to blocks are passed through to the page cache subsystem. The buffer cache was only separate from the page cache in much older kernels. The modern API for I/O is built around I/O requests and the bio struct, instead of stateful buffer cache blocks, and allows for I/O requests to be batched, reordered, or executed in parallel.

Disk caching in 2020

So what cache options are available to us on a modern system? As mentioned in the previous section, you can always just buy a bunch of RAM and you’ll get some in-memory caching provided by the kernel's page cache out of the box. If you’re using a RAID array there are ways to use the array’s journal as a cache. Modern kernels come with more exotic tools, though, and I will cover a few of them.

bcache, introduced in 2010, ships with most kernels. To use bcache you format your backing (slow) disk or logical volume with bcache and create whatever filesystem you want on top of the resulting bcache device. You then enable caching on the backing device by formatting a cache device (your SSD) and attaching it to the backing disk via sysfs. bcache implements writeback, writethrough and writearound caching, with the ability to switch between cache algorithms at runtime, and has implemented its own code to identify read patterns that shouldn’t be cached. The filesystem also exposes plenty of statistics and tunables for those who need to measure the performance of their system. Failure of the cache disk in writeback cache mode results in data loss. However, you still get a saving throw with fsck as bcache keeps the filesystem data on the backing store in its correct order. I’m very optimistic about bcache, I think it’s a good option for those rolling their own hardware and in the cloud and part 3 of this blog series will go through a bcache setup in the cloud.

Linux’s LVM also surfaces a device mapper target called dm-cache that provides similar caching on top of logical volumes. It’s configured through the typical LVM command line tools and is shipped with most kernels. dm-cache offers writethrough and writeback modes and the ability to safely stop caching on a logical volume. For whatever reason it seems that lvmcache is not nearly as popular as bcache. It’s not that much more complex to get started with lvmcache over bcache but I suspect the overhead of having to wade through the massive LVM documentation and familiarize yourself with LVM terminology is enough to keep many away.

ZFS has ARC, its own sophisticated cache algorithm that heavily ties into the overall design of ZFS. Writes are initially kept in RAM (ARC) and asynchronously committed to disk. L2ARC periodically grabs the data most likely to be evicted from ARC and persists it to its own disk. Later reads that result in an ARC cache miss can then be read out of L2ARC if the data exists there. This is similar to writearound caching in that it’ll only cache previously read data and the failure of the L2ARC disk doesn’t risk data loss. Your workload only benefits from L2ARC when the working set of hot reads is larger than the size of your ARC cache - not because L2ARC is bad, but because you just don’t need it until ARC is exhausted.

Another ZFS feature that comes up when discussing ZFS performance is the ZFS Intent Log, or ZIL. It’s a journal used to guarantee the durability of writes of filesystem metadata and user data and is not a cache. To improve the overall speed of writes and reduce the I/O load on the main ZFS disks the ZIL is often moved to a fast SSD disk in a configuration called SLOG. Even in this configuration the ZIL is still not a cache: it is only ever read from when the filesystem has an unclean shutdown and has to be restored to a consistent state. It comes up because it is also relevant to users looking to improve their ZFS performance in the same way that caching is a way to improve ZFS performance. By adding a SLOG you get the improved write performance of writeback caching but only the improved write performance, and with L2ARC you get improved reads of cache hits but only for reads that were cache hits. To take advantage of SSD read and write performance in ZFS you have to add both SLOG and L2ARC to your filesystem, requiring at least one SSD for L2ARC and two for SLOG.

I get the feeling that ZFS was really intended for general purpose filesystems and filers with general purpose workloads. The design is optimized for write durability whenever it can (a good, safe default!) and does a good job getting there. A dedicated ZFS appliance can soak up all the RAM you can throw at it and can continue to scale with separate, additional disk clusters for the ZIL and the L2ARC. And even if you were to put databases or other applications that carefully micromanage their writes onto a ZFS filesystem you’ll still be able to get SSD write improvements from an SLOG on a SSD. But suppose you had a database on ZFS and you wanted to keep the entire index on fast storage. This seems like a good use case for L2ARC as the size of your indexes on a non-trivial database will exceed the size of RAM. Because L2ARC can only cache data previously read you’d have to come up with some sort of cache warming to get your index on the SSD, and only until very recently could L2ARC caches persist across clean system restarts. It makes more sense to put the indexes on their own tablespaces that are explicitly located on SSD disks. ZFS gives you the tools to do this but there is no real set it and forget it architecture like with a true writethrough SSD cache. The combination of ZFS and Linux also seems to be geared towards filers. The Linux kernel still maintains its normal page cache alongside ARC and the same data can be cached in both places redundantly. There is also the risk that Linux soaks up cache hits first in a large page cache and ARC rarely gets a chance to grow. Systems that exhibit either behavior have to set a large, minimum ARC size to keep the page cache small and force hits into ARC - something you can really only get away with on a device dedicated to storage like a filer.

Btrfs does not yet have its own caching functionality.

For the next and final blog post in this series, I’m going to walk through what bcache looks like in the cloud and try and get some benchmarks.

Durability in the year 2020

Submitted by gil on

It is the year 2020 and we still don’t have great answers to data durability in the face of unclean shutdowns. Unclean shutdowns are things like power outages, system faults and unlucky kernel panics and preventing data loss when they happen is a hard problem. I’m going to talk through a few ways these can cause data loss in this blog post but you can probably come up with new ones on your own - exotic failures that no system will ever handle correctly. In the year 2020, the conventional wisdom is still true. Always take backups, and RAID is no substitute for backups.

How do we deal with these unclean shutdowns? If minimizing data loss from unclean shutdown is in scope for your system you should put serious consideration into putting time and money into functionality that minimizes the chance of unclean shutdowns. If you fear power outages you invest in battery-powered uninterruptible power supplies. If you fear kernel panics you should run stable distro kernels with simple, widely tested software like ext4/xfs and mdraid.

Even in the face of these unclean shutdowns there are some systems that do a better job at dodging fate, getting lucky and persisting good data than others. There’s RAID level 1, a classic simple design: data is written to two disks simultaneously and writes are acknowledged when both disks finish writing. If the application layer is properly using write barriers and not progressing until the write completes you’ll not be committing transactions and losing data afterwards. But if you get unlucky with an unclean shutdown gone very wrong you could have some exotic data loss. The recovery mode for an unclean RAID 1 array as done by md is to copy the unclean blocks from the first available device in the array to the rest of the drives. Should the unclean shutdown cause any issues with the data written to that first drive you’ll have undetected corruption.

RAID levels 3, 4 and 5 introduce parity data that can validate disk content and recreate corrupted or missing data from bad or missing disks, avoiding some of the corruption problems with RAID level 1. But they have their own weakness - the famous write hole, where data previously written safely to the array is damaged because of an unclean shutdown during a later write. These RAID levels write data out as stripes, larger chunks of data that can potentially contain unrelated older data alongside the new data you’re trying to write. Any problems that happen while writing out a stripe risk glitching the entire stripe and result in data loss.

Linux’s md has picked up a few solutions to closing the write hole in recent years. It now supports a journal, where the array’s write status is continually written to a separate disk. If an unclean shutdown happens it is now possible to identify the stripes in the array that were mid-write and unwind or correct the array’s data by replaying the transaction log on the journal disk. And the journal doesn’t just close the write hole problem, it also can help speed up array writes by optionally using the journal as a writethrough cache. In this mode the actual data in the write request is first committed to the journal disk and only later flushed to the array. If you use a speedy SSD for your journal disk you now get much faster write speeds and the same resistance to individual disk failure of a RAID array.

But if you have to use a separate disk for the journal aren’t you back to square one? What happens if the journal's disk fails, either from normal operations or as part of an unclean shutdown? If the journal disk fails you will have data loss. RAID level 1 is certainly a solution here, and it seems like the failure modes for RAID 1 are slim enough, especially for modern SSDs, that it makes a real improvement to the overall reliability of the system. In recent times the improved software support and hardware availability of persistent memory (PMEM) means that you could build a system with a fast, reliable journal disk that survives power outages. On Linux, PMEM hardware is exposed to the system as an ordinary block device, can be put into a RAID array of its own, and used by mdadm as a journal device, giving you a journal resistant to the failure of any one PMEM DIMM.

md also gained the Partial Parity Log in recent years, a new technique for writing RAID level 5’s parity data. It incorporates parity data about the previous state of a stripe into the write done for the updated state of the stripe, allowing for the previously written data to be recovered in case of failure and closing the write hole. Extra data must be written and read, slowing array performance, and there is still an opportunity for data loss with newly written data as the PPL only calculates its extra parity data for old data in the stripe and not the new write. But on the flip side the PPL doesn’t require a separate journal disk as it writes the extra parity data directly into the array, sidestepping a potential I/O bottleneck in the journal disk and any durability issues with it. But this extra parity data computed by the PPL increases the I/O and CPU load of writes, lowering write performance overall.

The ZFS filesystem, known for its rampant layering violations, actually does a pretty good job at taking advantage of its situation and providing a durable filesystem in the face of unclean shutdowns. ZFS on Linux is mature, stable, and used by many. Its RAID-Z design closes the write hole by having variably-sized stripes, shrunk down to the size of each write. Previously written data won’t be included in a stripe and thus can’t be damaged during writes of new data. The filesystem’s metadata is also mutated with copy-on-write semantics instead of in place, so all unclean shutdowns can be rolled back to a previously good state. It’s just a really solid design and it delivers robustness without any of the elaborate workarounds described earlier. These design choices come with the tradeoff of decreased performance but often not large enough to turn use cases away from it. If you are going to be maintaining hardware yourself ZFS should be on your radar.

Finally, btrfs is still hanging around. I remember reading about it on lwn.net in 07, my freshman year of college, and thinking that this was the filesystem of the future, comparable with ZFS on features but GPLed and developed in-tree. But as the years went by the team never really pulled it together, despite corporate backing from a few places, and btrfs has left a trail of users burnt by bugs and big unfixed issues even in cutting-edge kernels. This mailing list post was posted in June of 2020 and lists a shocking number of workarounds for data loss bugs. I really do not trust btrfs to do well in any unclean shutdown.

Durability in the face of unclean shutdowns and other issues is an important thing to have, but the cost/performance/durability tradeoff can often lean in favor of reducing the probability of unclean shutdown with battery backup instead of complicating the design of the storage system. Many businesses and individuals also no longer manage their own hardware and operate in the cloud. The cloud block devices used for bulk storage are internally redundant and extremely durable. Unclean shutdowns rarely happen as cloud hardware runs in datacenters with uninterruptible power systems and live migration of server instances. In the cloud you have endless hardware available to you and it's extremely durable, swinging the system design pendulum away from durability and back towards performance. In the next post I’ll explore the performance tradeoffs of storage systems.

The Year of ARM on the Desktop

Submitted by gil on

The big news of this year's WWDC is the announcement that Apple's moving desktop Macs onto Apple Silicon, ARM CPUs manufactured by Apple and the first real push at ARM desktops in the industry.

For Apple, there's a lot of risk here, but with that risk comes lots of opportunity. The transition could go very poorly, harming Apple's profits and market share. Rosetta 2, the binary translation layer Apple is shipping with macOS 11, is an unknown. It may not work well, it may have an unacceptable performance penalty for users. The transition to the new architecture could go poorly for developers, delaying the availability of native ARM software and further discouraging users from upgrading. There could be an unacceptable regression in CPU performance. And if there are issues, the longer Apple takes to get on top of them the more users they'll lose in the transition.

But there is lots of opportunity for Apple to do well here. Apple Silicon's performance, energy use, or the ratio of the two could beat Intel's hardware, giving Apple hardware a market advantage. It seems very likely that energy use will be greatly improved over Intel. Tight coupling of hardware and the operating system, possibly introducing more information about trusted execution contexts to the CPU, could open the door to innovative new fixes to Spectre-type bugs. Even if Apple's CPUs never beat the performance of Intel's CPUs a clever new design could turn into an advantage Intel can't replicate and narrow the performance gap between Intel and Apple.

Where do I see this going? I expect PC hardware manufactures to start experimenting with ARM desktop machines today. These machines wouldn't be usable for anything beyond Linux and bootstrapping efforts right now. Instead, they give the hardware manufacturers experience with designing and manufacturing these systems in the event that ARM does come to replace Intel generally across the industry. And if that does happen, we are in for exciting times. I would say it'll take about a year, starting today, for the first ARM desktop hardware to come out. Then we have to see if Apple's gamble paid off, which won't be clear for another year or two. Once that happens, the race is on to ditch Intel and I figure Microsoft is going to need two years to get something shippable. The world outside of Microsoft will take another year or two beyond that to start shipping ARM software. The exact timelines are up in the air but if the industry switches to ARM on the desktop you're looking at years of stagnation in the PC world while Apple has years of lead time on ARM.

As for the Hackintosh, the conventional wisdom is that Apple will stop shipping Intel versions of macOS in three to four years, the new ARM macOS will have hard requirements on Apple-only hardware and that will be the end of Hackintosh as a platform. I think you'll never have a fully compatible Hackintosh, there will definitely be Apple-specific hardware required for full functionality. But not all users require all functionality so as long as Apple hasn't wedded the operating system to Apple-exclusive hardware there is hope for a usable ARM Hackintosh. I don't think secure boot, signed code and the like are going to be a threat to Hackintosh. Those are useful parts of the security model on a real Mac, but on a Hackintosh where you control the boot process it'll be possible to bypass them without impacting system functionality. The real threat to Hackintosh might look like important hardware that can't be emulated efficiently or a toolchain that deeply integrates with Apple Silicon-specific functionality, requiring binary patching of the entire system, not just a few kernel drivers.

It's interesting that the Intel to ARM transition is going to be the reverse of the PPC to Intel transition in some ways. Before, Apple was coming onto a platform with extensive hardware, driver support and lots of understanding around how those all work. Because ARM on the desktop is so new there is a lack of all of that, complicating efforts at bringing up a Hackintosh system that isn't just a tech demo. Drivers are going to be all new, and graphics drivers are going to be a particularly sore point. Reliable, performant graphics drivers are required for most desktop PC use cases and none of that is going to exist for years. If we're going to see a stagnant period where the PC industry spends a few years transitioning to ARM the Hackintosh will have an even longer stagnant period.

Personally, I think we'll have some ARM Hackintoshes. Apple will treat the Hackintosh on ARM like they treat the Hackintosh on Intel: they'll mostly look the other way, not chase after the communities and not heavily integrate the operating system with Apple-specific hardware. I don't know if ARM will take over on PC desktops but I don't think it's an impossible outcome. Microsoft can pull it off, they'll have to make some platform users unhappy, it'll take them a while to pull off, but it can be done under threat of losing their entire PC business. But even if this all comes to pass I think we are definitely looking at a dark age of Hackintosh lasting as long as five years or more as people work on new hardware, drivers and hacks.

As for the official Apple hardware I don't think Apple Silicon will compete against AMD or Intel on performance right away, if ever. But I don't think the outcome where Apple gets a performance edge after applying creative shared execution environment mitigations is impossible. For most users the ARM laptops will be a nice improvement over past models: better battery life, roughly the same CPU performance, maybe some thinner hardware and an even wider gap between what you get from Apple hardware and what you get from PC hardware. And I think you will see Microsoft making an ARM "Windows", although who knows if it'll be a full port with backwards compatibility like Apple or a subset of today's Windows. I also don't know if they'll be very reactive (starting work now) or reluctantly reactive (starting work in a year or two when Apple sets the industry direction) but I think the forward-thinking leadership Microsoft has now means they're already taking this seriously.

Compiled bjoern packages

Submitted by gil on

bjoern is a WSGI-compatible web server for Python web applications. It supports both Python 2 and Python 3. Unfortunately the authors don't provide any binary packages but I've created compiled binary wheels for bjoern for Python 2 and 3 for Debian Jessie, Stretch and Buster and Ubuntu Xenial, Trusty and Bionic.

To install the package:

  1. Install libev with sudo aptitude install libev4
  2. Find out the release you have installed with source /etc/os-release; echo $PRETTY_NAME
    This will output a line of text like Debian GNU/Linux 9 (stretch). In this example stretch is the name of the release. Write that down somewhere.
  3. Source your virtualenv. You're using a virtualenv, right?
  4. Browse to the bjoern releases page and find the wheels for your release. In my example, they would be stretch-bjoern-2.2.3-cp27-cp27mu-linux_x86_64.whl and stretch-bjoern-2.2.3-cp35-cp35m-linux_x86_64.whl.
  5. Download the Python 2 (cp27) or Python 3 (cp3X) wheel for the version of Python your project uses.
  6. Rename the file to remove the release prefix. In my example, stretch-bjoern-2.2.3-cp35-cp35m-linux_x86_64.whl becomes bjoern-2.2.3-cp35-cp35m-linux_x86_64.whl
  7. Use pip install to install the wheel in your virtualenv. In my example, I would do pip install bjoern-2.2.3-cp35-cp35m-linux_x86_64.whl

Note that the renaming step appears to be optional; pip will throw some errors when you try to install the wheel but the bjoern wheel appears to be installed correctly anyway.

Debian packages for netatalk 3

Submitted by gil on

netatalk hasn't been packaged with Debian for a few years now. If you don't want to get your hands dirty with compiling the package you can download compiled (binary) deb packages of netatalk version 3 from my GitHub releases. Right now I have packages for netatalk version 3.1.12 and 3.1.11 for for Debian buster, stretch and jessie.

To install the packages:

  1. Find out the release of Debian you have installed with source /etc/os-release; echo $PRETTY_NAME
    This will output a line of text like Debian GNU/Linux 9 (stretch). In this example stretch is the name of the Debian release. Write that down somewhere.
  2. Find the appropriate packages for your Debian release on the releases page. Out of the several packages for your release you'll need to download the libatalk18 and netatalk packages. So for my example, I would download the files stretch_libatalk18_3.1.12-1_amd64.deb and stretch_netatalk_3.1.12-1_amd64.deb.
  3. Download both .deb packages to your local machine through the browser or with wget.
  4. Install both packages at the same time with dpkg -i. In my example, I would do sudo dpkg -i ./stretch_libatalk18_3.1.12-1_amd64.deb ./stretch_netatalk_3.1.12-1_amd64.deb