<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>calabro.io</title>
  <subtitle>Browse aymeric&#39;s, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.</subtitle>
  <id>https://aggr.aymericbeaumet.com/sources/calabro.io/</id>
  <link rel="alternate" type="text/html" href="https://aggr.aymericbeaumet.com/sources/calabro.io/"/>
  <link rel="self" type="application/atom+xml" href="https://aggr.aymericbeaumet.com/sources/calabro.io/atom.xml"/>
  <updated>2026-10-19T20:50:08+00:00</updated>
  <author>
    <name>aymeric&#39;s</name>
  </author>
  <generator version="2.0.0" uri="https://github.com/aymericbeaumet/aggr">aggr</generator>
  <entry>
    <id>urn:aggr:item:46713ff69bf81579c87b6ef8b5fb451129b04f02</id>
    <title type="text">One Hash Bloom Filters</title>
    <link rel="alternate" type="text/html" href="https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-19-one-hash-bloom-filters/"/>
    <link rel="via" type="text/html" href="https://calabro.io/ohbf"/>
    <published>2026-10-19T20:50:08+00:00</published>
    <updated>2026-10-19T20:50:08+00:00</updated>
    <author>
      <name>jcalabro</name>
    </author>
    <category term="news"/>
    <source>
      <title>Hacker News: Front Page</title>
    </source>
    <summary type="text">Note: as always, all my public writing is written by hand by me. Overview A bloom filter is a probabilistic data structure that allows you to quickly and cheaply answer the question &quot;is key X in this set?&quot; with either &quot;definitely not&quot; or…</summary>
    <content type="html">&lt;p&gt;&lt;em&gt;Note: as always, all my public writing is written by hand by me.&lt;/em&gt;&lt;/p&gt;
&lt;h4&gt;Overview&lt;/h4&gt;
&lt;p&gt;A &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://en.wikipedia.org/wiki/Bloom_filter&quot;&gt;bloom filter&lt;/a&gt; is a probabilistic data structure that allows you to quickly and cheaply answer the question &lt;em&gt;&amp;quot;is key X in this set?&amp;quot;&lt;/em&gt; with either &lt;em&gt;&amp;quot;definitely not&amp;quot;&lt;/em&gt; or &lt;em&gt;&amp;quot;probably&amp;quot;&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;You pick a false positive rate that is acceptable for your workload and hardware, add keys to the set, and check for their existence later on.&lt;/p&gt;
&lt;p&gt;Bloom filters use a small amount of memory compared to the cardinality of the set, and are computationally very cheap. For these reasons, they&#39;re frequently used in high performance data systems.&lt;/p&gt;
&lt;p&gt;For example, a database might keep an in-memory bloom filter and check it before actually going to disk when looking up rows. This saves substantial amounts of very slow disk IO.&lt;/p&gt;
&lt;p&gt;We also use them all over the place in the &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://bsky.app&quot;&gt;Bluesky&lt;/a&gt; backend. They allow us to save &lt;em&gt;millions&lt;/em&gt; of queries per second against our Scylla database when looking up blocks, mutes, labels, and more. For instance, we can often answer the question &lt;em&gt;&amp;quot;does user X block user Y&amp;quot;&lt;/em&gt; without even hitting the database.&lt;/p&gt;
&lt;p&gt;Here&#39;s the last several days of some of our bloom filter positive hit rates:&lt;/p&gt;
&lt;p&gt;&lt;picture class=&quot;article-picture article-picture-fallback&quot; style=&quot;--image-ratio:16 / 9&quot;&gt;&lt;img src=&quot;https://calabro.io/static/posts/bsky-bloom-filter-positive-rate.png&quot; alt=&quot;Image of the bloom filter postitive rate we have in production&quot; loading=&quot;eager&quot; decoding=&quot;async&quot; fetchpriority=&quot;high&quot; referrerpolicy=&quot;no-referrer&quot; class=&quot;progressive-image&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;The above yellow line has a roughly 1% positive rate, which means that 99% of the time, we can completely skip querying our database. This has been critical in our ability to scale the site and operate the site cheaply.&lt;/p&gt;
&lt;h4&gt;Traditional Bloom Filters&lt;/h4&gt;
&lt;p&gt;A bloom filter is an array of bits and &lt;em&gt;k&lt;/em&gt; hash functions. You choose the size of the array and &lt;em&gt;k&lt;/em&gt; before hand, and want to right-size it to your workload to achieve a specific false positive rate.&lt;/p&gt;
&lt;p&gt;To add a key to the set, run it through the &lt;em&gt;k&lt;/em&gt; hash functions and set the bits at each of those locations.&lt;/p&gt;
&lt;p&gt;To check if a a key is in the set, hash it &lt;em&gt;k&lt;/em&gt; times and check each resulting location in the bit array. If any bits are zero, the key was never added. If all bits are set to one, it might be in the set.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of a potential positive:&lt;/p&gt;
&lt;p&gt;&lt;picture class=&quot;article-picture article-picture-fallback&quot; style=&quot;--image-ratio:16 / 9&quot;&gt;&lt;img src=&quot;https://calabro.io/static/posts/bsky-bloom-filter-traditional-all-one.png&quot; alt=&quot;Image showing how if all hash function items are one, then the item may be in the set&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;low&quot; referrerpolicy=&quot;no-referrer&quot; class=&quot;progressive-image&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;And a definite negative:&lt;/p&gt;
&lt;p&gt;&lt;picture class=&quot;article-picture article-picture-fallback&quot; style=&quot;--image-ratio:16 / 9&quot;&gt;&lt;img src=&quot;https://calabro.io/static/posts/bsky-bloom-filter-traditional-any-zero.png&quot; alt=&quot;Image showing how if any hash function items are zero, then the item is definitely not in the set&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;low&quot; referrerpolicy=&quot;no-referrer&quot; class=&quot;progressive-image&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;Pretty simple!&lt;/p&gt;
&lt;h4&gt;Double Hashing&lt;/h4&gt;
&lt;p&gt;While &lt;em&gt;much&lt;/em&gt; cheaper than going to disk, computing &lt;em&gt;k&lt;/em&gt; independent hashes per key is still a bit expensive for very high performance systems.&lt;/p&gt;
&lt;p&gt;In 2008, Kirsch and Mitzenmacher wrote a &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.eecs.harvard.edu/~michaelm/postscripts/rsa2008.pdf&quot;&gt;paper&lt;/a&gt; demonstrating that two hashes can get you the same output. The math is far over my head, but if you derive the &lt;em&gt;i&lt;/em&gt;-th location as &lt;code&gt;(hash_1 + i*hash_2) % n&lt;/code&gt;, then the false positive rate is effectively the same as using &lt;em&gt;k&lt;/em&gt; independent hashes. Phew!&lt;/p&gt;
&lt;p&gt;&lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/bits-and-blooms/bloom&quot;&gt;bits-and-blooms/bloom&lt;/a&gt; maintained by &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://lemire.me/blog/&quot;&gt;Daniel Lemire&lt;/a&gt; (a huge inspiration of mine, you should buy his &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://www.amazon.com/dp/B0HF4JT75J&quot;&gt;book&lt;/a&gt;) is a fantastic double hash bloom filter implementation written in go. It runs 128-bit murmur3 twice to get four 64-bit values, then combines them to produce all &lt;em&gt;k&lt;/em&gt; bit locations. We used this in production at Bluesky for a long time.&lt;/p&gt;
&lt;p&gt;For the Bluesky backend, we essentially do a &lt;code&gt;SELECT * FROM blocks&lt;/code&gt;, mutes, list items, etc. every time one the processes starts, and add all the items to the bloom filter. There&#39;s also a real time &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://atproto.com&quot;&gt;atproto&lt;/a&gt; firehose consumer inserting items in to bloom filters (even during process startup), so there is a race condition if you&#39;re not careful.&lt;/p&gt;
&lt;p&gt;The problem with the &lt;code&gt;bits-and-blooms&lt;/code&gt; library is that it&#39;s not internally thread-safe, so we needed to wrap all bloom filter access in a &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://pkg.go.dev/sync&quot;&gt;mutex&lt;/a&gt; lest we suffer a data race. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://pkg.go.dev/net/http/pprof&quot;&gt;pprof&lt;/a&gt; showed that mutex contention was actually the bottleneck in launching the process. A single deploy used to take 90 minutes to roll out fully because of this!&lt;/p&gt;
&lt;p&gt;So my colleague &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://jazco.dev/&quot;&gt;Jasmine&lt;/a&gt; forked the library and created &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/jazware/atomic-bloom&quot;&gt;atomic-bloom&lt;/a&gt;, which uses &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://pkg.go.dev/sync/atomic&quot;&gt;atomic&lt;/a&gt; CPU instructions to do the same logic, but safely and without mutexes. This led to substantially less contention and was massively faster than the mutex-based approach. Our deploys dropped from 90 minutes to about 15, which enabled us to ship faster and with greater confidence. Awesome!&lt;/p&gt;
&lt;h4&gt;One Hash&lt;/h4&gt;
&lt;p&gt;Can we go further?&lt;/p&gt;
&lt;p&gt;For Bluesky, the answer is &lt;strong&gt;no&lt;/strong&gt;. Contention was our original problem, not the number of hash functions or other factors, thus by &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://en.wikipedia.org/wiki/Amdahl%27s_law&quot;&gt;Amdahl&#39;s Law&lt;/a&gt; we did not receive any further speedup resulting in a noticeable impact. However, it&#39;s still fun to go deeper and learn something new!&lt;/p&gt;
&lt;p&gt;As part of our research on bloom filter techniques, we came across &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://yangtonghome.github.io/uploads/One_Hashing.pdf&quot;&gt;this paper&lt;/a&gt; from Lu et al. that uses &lt;em&gt;even more math&lt;/em&gt; to show how to do bloom filters using only a single hash.&lt;/p&gt;
&lt;p&gt;Here&#39;s an overview of how it works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Instead of one big bit array, split that into &lt;em&gt;k&lt;/em&gt; array partitions of fixed sizes&lt;/li&gt;
&lt;li&gt;Each partition has a different size, and all the sizes are &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://en.wikipedia.org/wiki/Coprime_integers&quot;&gt;pairwise coprime&lt;/a&gt;, meaning that no two sizes share a common factor other than one&lt;/li&gt;
&lt;li&gt;You hash the given key once to get &lt;em&gt;hash&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The bit position in partition &lt;em&gt;p&lt;/em&gt; is &lt;code&gt;hash%size_p&lt;/code&gt; (the size of the partition)&lt;/li&gt;
&lt;li&gt;Since you have &lt;em&gt;k&lt;/em&gt; partitions, you get &lt;em&gt;k&lt;/em&gt; bit positions to check out of that single hash&lt;/li&gt;
&lt;li&gt;You can use those &lt;em&gt;k&lt;/em&gt; bit positions as you would with other bloom filter types!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With this technique in hand, I made &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/jcalabro/gloom&quot;&gt;jcalabro/gloom&lt;/a&gt;, a one-hash bloom filter (OHBF) implementation in go. This has been live in the Bluesky backend for the past 9 months and has been holding up quite well. It&#39;s also used in &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/bluesky-social/jetstream&quot;&gt;jetstream&lt;/a&gt;, our high performance sync service.&lt;/p&gt;
&lt;p&gt;Here&#39;s an example of how it&#39;s used:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Go&quot;&gt;&lt;span class=&quot;syntax-source syntax-go&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-go&quot;&gt;package&lt;/span&gt; main

&lt;span class=&quot;syntax-meta syntax-import syntax-go&quot;&gt;&lt;span class=&quot;syntax-keyword syntax-control syntax-import syntax-go&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-import syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;
    &lt;span class=&quot;syntax-string syntax-quoted syntax-double syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-begin syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;fmt&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-end syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;syntax-string syntax-quoted syntax-double syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-begin syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;sync&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-end syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;syntax-string syntax-quoted syntax-double syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-begin syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;github.com/jcalabro/gloom&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-end syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;syntax-meta syntax-function syntax-declaration syntax-go&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-go&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;syntax-entity syntax-name syntax-function syntax-go&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-go&quot;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-go&quot;&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt; &lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-begin syntax-go&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;
    &lt;span class=&quot;syntax-comment syntax-line syntax-double-slash syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-comment syntax-go&quot;&gt;//&lt;/span&gt; Create a thread-safe atomic bloom filter with:
&lt;/span&gt;    &lt;span class=&quot;syntax-comment syntax-line syntax-double-slash syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-comment syntax-go&quot;&gt;//&lt;/span&gt;    - Expected capacity of 1 million items
&lt;/span&gt;    &lt;span class=&quot;syntax-comment syntax-line syntax-double-slash syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-comment syntax-go&quot;&gt;//&lt;/span&gt;    - Approximate false positive rate of 1%
&lt;/span&gt;    &lt;span class=&quot;syntax-meta syntax-initialization syntax-short syntax-go&quot;&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-initialize syntax-go&quot;&gt;:=&lt;/span&gt;&lt;/span&gt; gloom&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;NewAtomic&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;1_000_000&lt;span class=&quot;syntax-punctuation syntax-separator syntax-go&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-float syntax-decimal syntax-go&quot;&gt;0.01&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

&lt;span class=&quot;syntax-meta syntax-initialization syntax-explicit syntax-go&quot;&gt;    &lt;span class=&quot;syntax-storage syntax-type syntax-go&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;wg&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-initialization syntax-explicit syntax-go&quot;&gt; sync&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-member syntax-go&quot;&gt;WaitGroup&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;syntax-keyword syntax-control syntax-go&quot;&gt;defer&lt;/span&gt; wg&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;Wait&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

    &lt;span class=&quot;syntax-keyword syntax-control syntax-go&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-initialization syntax-short syntax-go&quot;&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-initialize syntax-go&quot;&gt;:=&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-control syntax-go&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-go&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-begin syntax-go&quot;&gt;{&lt;/span&gt;
        wg&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;Go&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-declaration syntax-anonymous syntax-go&quot;&gt;&lt;span class=&quot;syntax-storage syntax-type syntax-go&quot;&gt;func&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-parameters syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt; &lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-begin syntax-go&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;
            &lt;span class=&quot;syntax-keyword syntax-control syntax-go&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-initialization syntax-short syntax-go&quot;&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;j&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-initialize syntax-go&quot;&gt;:=&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-control syntax-go&quot;&gt;range&lt;/span&gt; &lt;span class=&quot;syntax-constant syntax-numeric syntax-integer syntax-decimal syntax-go&quot;&gt;100000&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-begin syntax-go&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;syntax-meta syntax-initialization syntax-short syntax-go&quot;&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-initialize syntax-go&quot;&gt;:=&lt;/span&gt;&lt;/span&gt; fmt&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;Sprintf&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-string syntax-quoted syntax-double syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-begin syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;key-&lt;span class=&quot;syntax-constant syntax-other syntax-placeholder syntax-go&quot;&gt;%d&lt;/span&gt;-&lt;span class=&quot;syntax-constant syntax-other syntax-placeholder syntax-go&quot;&gt;%d&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-end syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-go&quot;&gt;,&lt;/span&gt; i&lt;span class=&quot;syntax-punctuation syntax-separator syntax-go&quot;&gt;,&lt;/span&gt; j&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;

                &lt;span class=&quot;syntax-keyword syntax-control syntax-go&quot;&gt;if&lt;/span&gt; f&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;TestString&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-begin syntax-go&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;syntax-comment syntax-line syntax-double-slash syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-comment syntax-go&quot;&gt;//&lt;/span&gt; always a false positive since the key isn&amp;#39;t in the set
&lt;/span&gt;                    fmt&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;Printf&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-string syntax-quoted syntax-double syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-begin syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;found a false positive: &lt;span class=&quot;syntax-constant syntax-other syntax-placeholder syntax-go&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;syntax-constant syntax-character syntax-escape syntax-go&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-string syntax-end syntax-go&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-punctuation syntax-separator syntax-go&quot;&gt;,&lt;/span&gt; str&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-end syntax-go&quot;&gt;}&lt;/span&gt;&lt;/span&gt;

                f&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;AddString&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-end syntax-go&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
        &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-end syntax-go&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-end syntax-go&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-block syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-block syntax-end syntax-go&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, let&#39;s step through how it works under the hood in more detail. Here&#39;s some sample go code that shows how we select the block index as well as &lt;code&gt;h&lt;/code&gt; for a given key we want to check:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-go&quot;&gt;&lt;span class=&quot;code-snippet&quot; data-language=&quot;Go&quot;&gt;&lt;span class=&quot;syntax-source syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-initialization syntax-short syntax-go&quot;&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;hash&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-initialize syntax-go&quot;&gt;:=&lt;/span&gt;&lt;/span&gt; xxh3&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-function syntax-go&quot;&gt;Hash128&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-begin syntax-go&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-function-call syntax-method syntax-go&quot;&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-group syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-group syntax-end syntax-go&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;syntax-comment syntax-line syntax-double-slash syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-comment syntax-go&quot;&gt;//&lt;/span&gt; calculate the 128-bit hash
&lt;/span&gt;
&lt;span class=&quot;syntax-meta syntax-initialization syntax-short syntax-go&quot;&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-initialize syntax-go&quot;&gt;:=&lt;/span&gt;&lt;/span&gt; hash&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-member syntax-go&quot;&gt;Hi&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-go&quot;&gt;%&lt;/span&gt; numBlocks &lt;span class=&quot;syntax-comment syntax-line syntax-double-slash syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-comment syntax-go&quot;&gt;//&lt;/span&gt; high 64 bits pick the block
&lt;/span&gt;&lt;span class=&quot;syntax-meta syntax-initialization syntax-short syntax-go&quot;&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-go&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;syntax-keyword syntax-operator syntax-initialize syntax-go&quot;&gt;:=&lt;/span&gt;&lt;/span&gt; hash&lt;span class=&quot;syntax-punctuation syntax-accessor syntax-go&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;syntax-variable syntax-other syntax-member syntax-go&quot;&gt;Lo&lt;/span&gt;                 &lt;span class=&quot;syntax-comment syntax-line syntax-double-slash syntax-go&quot;&gt;&lt;span class=&quot;syntax-punctuation syntax-definition syntax-comment syntax-go&quot;&gt;//&lt;/span&gt; low 64 bits are the hash we&amp;#39;ll check
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, you check your bloom filter as follows:&lt;/p&gt;
&lt;p&gt;&lt;picture class=&quot;article-picture article-picture-fallback&quot; style=&quot;--image-ratio:16 / 9&quot;&gt;&lt;img src=&quot;https://calabro.io/static/posts/bsky-bloom-filter-one-hash.png&quot; alt=&quot;Image showing one hash bloom filters work&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot; fetchpriority=&quot;low&quot; referrerpolicy=&quot;no-referrer&quot; class=&quot;progressive-image&quot;&gt;&lt;/picture&gt;&lt;/p&gt;
&lt;p&gt;In addition to being a single hash, it also does some fun performance optimization techniques.&lt;/p&gt;
&lt;p&gt;First, we split the bloom filter into many 64-byte blocks to match common CPU cache line size. Next, since go&#39;s allocator doesn&#39;t ensure that those block allocations are &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://learn.arm.com/learning-paths/cross-platform/memory-latency/latency-and-cache-alignment/&quot;&gt;cache aligned&lt;/a&gt;, we slightly over-allocate and use &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://pkg.go.dev/unsafe&quot;&gt;unsafe&lt;/a&gt; to ensure alignment. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/jcalabro/gloom/blob/41399c29b47251fe3822e64cbb934c609f7b29c8/bloom.go#L90-L99&quot;&gt;See here&lt;/a&gt; for the implementation.&lt;/p&gt;
&lt;p&gt;These two techniques combined guarantee that in the worst case, a bloom filter lookup only takes one cache miss. Nice!&lt;/p&gt;
&lt;p&gt;There&#39;s another fun &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/&quot;&gt;optimization&lt;/a&gt; from Daniel Lemire that allows you to select which block to check with a single &lt;code&gt;MUL&lt;/code&gt; instruction rather than modulo, which requires an expensive division instruction.&lt;/p&gt;
&lt;p&gt;The final interesting optimization I&#39;ll talk about is the &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/jcalabro/gloom/tree/bf26d4b6e5e9e0a86e48ad444dd4e85740a90ceb#high-throughput-concurrent-writes&quot;&gt;ShardedAtomicFilter&lt;/a&gt;. At Bluesky, I managed a large fleet of top of the line bare metal servers. In order to eke the most performance out of those systems, it&#39;s good to avoid having multiple cores fight over the same data. &lt;code&gt;ShardedAtomicFilter&lt;/code&gt; spreads writes over many backing filter shards, which reduces the likelihood of contention.&lt;/p&gt;
&lt;h4&gt;Conclusion&lt;/h4&gt;
&lt;p&gt;Bloom filters (and &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://lemire.me/en/publication/spe2016roaring/&quot;&gt;roaring bitmaps&lt;/a&gt;) &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://bsky.app/profile/jaz.sh/post/3mizi7ns23s2u&quot;&gt;make the world go around&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Hopefully this was an interesting little exploration in to how they work. If you&#39;re interested in fun low-level engineering details, consider &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://bsky.app/profile/calabro.io/&quot;&gt;following me on Bluesky&lt;/a&gt; or subscribing to this blog via atproto, RSS or similar.&lt;/p&gt;
&lt;p&gt;Side note: I&#39;ve been working on a novel observability suite that pushes the state of the art. &lt;a target=&quot;_blank&quot; rel=&quot;noopener noreferrer&quot; href=&quot;https://github.com/microscope-dev/microscope&quot;&gt;Star it on github&lt;/a&gt; and keep an eye out for more discussion in the near future!&lt;/p&gt;
</content>
  </entry>
</feed>
