
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/">
    <channel>
        <title><![CDATA[ The Cloudflare Blog ]]></title>
        <description><![CDATA[ Get the latest news on how products at Cloudflare are built, technologies used, and join the teams helping to build a better Internet. ]]></description>
        <link>https://blog.cloudflare.com</link>
        <atom:link href="https://blog.cloudflare.com/" rel="self" type="application/rss+xml"/>
        <language>en-us</language>
        <image>
            <url>https://blog.cloudflare.com/favicon.png</url>
            <title>The Cloudflare Blog</title>
            <link>https://blog.cloudflare.com</link>
        </image>
        <lastBuildDate>Tue, 07 Apr 2026 17:49:36 GMT</lastBuildDate>
        <item>
            <title><![CDATA[Go and enhance your calm: demolishing an HTTP/2 interop problem]]></title>
            <link>https://blog.cloudflare.com/go-and-enhance-your-calm/</link>
            <pubDate>Fri, 31 Oct 2025 13:00:00 GMT</pubDate>
            <description><![CDATA[ HTTP/2 implementations often respond to suspected attacks by closing the connection with an ENHANCE_YOUR_CALM error code. Learn how a common pattern of using Go's HTTP/2 client can lead to unintended errors and the solution to avoiding them. ]]></description>
            <content:encoded><![CDATA[ <p>In September 2025, a thread popped up in our internal engineering chat room asking, "Which part of our stack would be responsible for sending <code>ErrCode=ENHANCE_YOUR_CALM</code> to an HTTP/2 client?" Two internal microservices were experiencing a critical error preventing their communication and the team needed a timely answer.</p><p>In this blog post, we describe the background to well-known HTTP/2 attacks that trigger Cloudflare defences, which close connections. We then document an easy-to-make mistake using Go's standard library that can cause clients to send PING flood attacks and how you can avoid it.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OL6xA151F9JNR4S0wE0DG/f6ae4b0a261da5d189d82ccfa401104e/image1.png" />
          </figure>
    <div>
      <h3>HTTP/2 is powerful – but it can be easy to misuse</h3>
      <a href="#http-2-is-powerful-but-it-can-be-easy-to-misuse">
        
      </a>
    </div>
    <p><a href="https://www.rfc-editor.org/rfc/rfc9113"><u>HTTP/2</u></a> defines a binary wire format for encoding <a href="https://www.rfc-editor.org/rfc/rfc9110.html"><u>HTTP semantics</u></a>. Request and response messages are encoded as a series of HEADERS and DATA frames, each associated with a logical stream, sent over a TCP connection using TLS. There are also control frames that relate to the management of streams or the connection as a whole. For example, SETTINGS frames advertise properties of an endpoint, WINDOW_UPDATE frames provide flow control credit to a peer so that it can send data, RST_STREAM can be used to cancel or reject a request or response, while GOAWAY can be used to signal graceful or immediate connection closure.</p><p>HTTP/2 provides many powerful features that have legitimate uses. However, with great power comes responsibility and opportunity for accidental or intentional misuse. The specification details a number of <a href="https://datatracker.ietf.org/doc/html/rfc9113#section-10.5"><u>denial-of-service considerations</u></a>. Implementations are advised to harden themselves: "An endpoint that doesn't monitor use of these features exposes itself to a risk of denial of service. Implementations SHOULD track the use of these features and set limits on their use."</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/71AXf477FP8u9znjdqXIh9/d6d22049a3f5f5488b8b7e9ac7f832a9/image3.png" />
          </figure><p>Cloudflare implements many different HTTP/2 defenses, developed over years in order to protect our systems and our customers. Some notable examples include mitigations added in 2019 to address "<a href="https://blog.cloudflare.com/on-the-recent-http-2-dos-attacks/"><u>Netflix vulnerabilities</u></a>" and in 2023 to mitigate <a href="https://blog.cloudflare.com/technical-breakdown-http2-rapid-reset-ddos-attack/"><u>Rapid Reset</u></a> and <a href="https://blog.cloudflare.com/madeyoureset-an-http-2-vulnerability-thwarted-by-rapid-reset-mitigations/"><u>similar</u></a> style attacks.</p><p>When Cloudflare detects that HTTP/2 client behaviour is likely malicious, we close the connection using the GOAWAY frame and include the error code <a href="https://www.rfc-editor.org/rfc/rfc9113#ENHANCE_YOUR_CALM"><code><u>ENHANCE_YOUR_CALM</u></code></a>.</p><p>One of the well-known and common attacks is <a href="https://www.cve.org/CVERecord?id=CVE-2019-9512"><u>CVE-2019-9512</u></a>, aka PING flood: "The attacker sends continual pings to an HTTP/2 peer, causing the peer to build an internal queue of responses. Depending on how efficiently this data is queued, this can consume excess CPU, memory, or both." Sending a <a href="https://www.rfc-editor.org/rfc/rfc9113#section-6.7"><u>PING frame</u></a> causes the peer to respond with a PING acknowledgement (indicated by an ACK flag). This allows for checking the liveness of the HTTP connection, along with measuring the layer 7 round-trip time – both useful things. The requirement to acknowledge a PING, however, provides the potential attack vector since it generates work for the peer.</p><p>A client that PINGs the Cloudflare edge too frequently will trigger our <a href="https://www.cve.org/CVERecord?id=CVE-2019-9512"><u>CVE-2019-9512</u></a> mitigations, causing us to close the connection. Shortly after we <a href="https://blog.cloudflare.com/road-to-grpc/"><u>launched support for gRPC</u></a> in 2020, we encountered interoperability issues with some gRPC clients that sent many PINGs as part of a <a href="https://grpc.io/blog/grpc-go-perf-improvements/#bdp-estimation-and-dynamic-flow-control-window"><u>performance optimization for window tuning</u></a>. We also discovered that the Rust Hyper crate had a feature called Adaptive Window that emulated the design and triggered a similar <a href="https://github.com/hyperium/hyper/issues/2526"><u>problem</u></a> until Hyper made a <a href="https://github.com/hyperium/hyper/pull/2550"><u>fix</u></a>.</p>
    <div>
      <h3>Solving a microservice miscommunication mystery</h3>
      <a href="#solving-a-microservice-miscommunication-mystery">
        
      </a>
    </div>
    <p>When that thread popped up asking which part of our stack was responsible for sending the <code>ENHANCE_YOUR_CALM</code> error code, it was regarding a client communicating over HTTP/2 between two internal microservices.</p><p>We suspected that this was an HTTP/2 mitigation issue and confirmed it was a PING flood mitigation in our logs. But taking a step back, you may wonder why two internal microservices are communicating over the Cloudflare edge at all, and therefore hitting our mitigations. In this case, communicating over the edge provides us with several advantages:</p><ol><li><p>We get to dogfood our edge infrastructure and discover issues like this!</p></li><li><p>We can use Cloudflare Access for authentication. This allows our microservices to be accessed securely by both other services (using service tokens) and engineers (which is invaluable for debugging).</p></li><li><p>Internal services that are written with Cloudflare Workers can easily communicate with services that are accessible at the edge.</p></li></ol>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6v9oBdn5spdqw1BjDW1bS3/a9b36ef9252d580a79c978eb366f7a7a/image2.png" />
          </figure><p>The question remained: Why was this client behaving this way? We traded some ideas as we attempted to get to the bottom of the issue.</p><p>The client had a configuration that would indicate that it didn't need to PING very frequently:</p>
            <pre><code>t2.PingTimeout = 2 * time.Second
t2.ReadIdleTimeout = 5 * time.Second</code></pre>
            <p>However, in situations like this it is generally a good idea to establish ground truth about what is really happening "on the wire." For instance, grabbing a packet capture that can be dissected and explored in Wireshark can provide unequivocal evidence of precisely what was sent over the network. The next best option is detailed/trace logging at the sender or receiver, although sometimes logging can be misleading, so caveat emptor.</p><p>In our particular case, it was simpler to use logging with <code>GODEBUG=http2debug=2</code>. We built a simplified minimal reproduction of the client that triggered the error, helping to eliminate other potential variables. We did some group log analysis, combined with diving into some of the Go standard library code to understand what it was really doing. Issac Asimov is commonly credited with the quote "The most exciting phrase to hear in science, the one that heralds new discoveries, is not 'Eureka!' but 'That's funny...'" and sure enough, within the hour someone declared–

<i>the funny part I see is this:</i></p>
            <pre><code>2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote RST_STREAM stream=9 len=4 ErrCode=CANCEL
2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote PING len=8 ping="j\xe7\xd6R\xdaw\xf8+"</code></pre>
            <p><i>every ping seems to be preceded by a RST_STREAM</i></p><p>Observant readers will recall the earlier mention of Rapid Reset. However, our logs clearly indicated ENHANCE_YOUR_CALM being triggered due to the PING flood. A bit of searching landed us on this <a href="https://groups.google.com/g/grpc-io/c/sWYYQJXHCAQ/m/SWFHxw9IAgAJ"><u>mailing list thread</u></a> and the comment "Sending a PING frame along with an RST_STREAM allows a client to distinguish between an unresponsive server and a slow response." That seemed quite relevant. We also found <a href="https://go-review.googlesource.com/c/net/+/632995"><u>a change that was committed</u></a> related to this topic. This partly answered why there were so many PINGs, but it also raised a new question: Why so many stream resets?

So we went back to the logs and built up a little more context about the interaction:</p>
            <pre><code>2025/09/02 17:33:18 http2: Transport received DATA flags=END_STREAM stream=47 len=0 data=""
2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote RST_STREAM stream=47 len=4 ErrCode=CANCEL
2025/09/02 17:33:18 http2: Framer 0x14000624540: wrote PING len=8 ping="\x97W\x02\xfa&gt;\xa8\xabi"</code></pre>
            <p>The interesting thing here is that the server had sent a DATA frame with the END_STREAM flag set. Per the HTTP/2 stream <a href="https://www.rfc-editor.org/rfc/rfc9113#section-5.1"><u>state machine</u></a>, the stream should have transitioned to <b>closed</b> when a frame with END_STREAM was processed. The client doesn't need to do anything in this state – sending a RST_STREAM is entirely unnecessary.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/R0Bbw1SFYwcyb280RdwjY/578628489c97f67a5ac877a55f4f3e3b/image6.png" />
          </figure><p>A little more digging and noodling and an engineer proclaimed:

<i>I noticed that the reset+ping only happens when you call r</i><code><i>esp.Body.Close()</i></code></p><p><i>I believe Go's HTTP library doesn't actually read the response body automatically, but keeps the stream open for you to use until you call r</i><code><i>esp.Body.Close()</i></code><i>, which you can do at any point you like.</i></p><p>The hilarious thing in our example was that there wasn't actually any HTTP body to read. From the earlier example: <code>received DATA flags=END_STREAM stream=47 len=0 data=""</code>.</p><p>Science and engineering are at times weird and counterintuitive. We decided to tweak our client to read the (absent) body via <code>io.Copy(io.Discard, resp.Body)</code> before closing it. </p><p>Sure enough, this immediately stopped the client sending both a useless RST_STREAM and, by association, a PING frame. </p><p>Mystery solved?</p><p>To prove we had fixed the root cause, the production client was updated with a similar fix. A few hours later, all the ENHANCE_YOUR_CALM closures were eliminated.</p>
    <div>
      <h3>Reading bodies in Go can be unintuitive</h3>
      <a href="#reading-bodies-in-go-can-be-unintuitive">
        
      </a>
    </div>
    <p>It’s worth noting that in some situations, ensuring the response body is always read can sometimes be unintuitive in Go. For example, at first glance it appears that the response body will always be read in the following example:</p>
            <pre><code>resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer resp.Body.Close()

if err := json.NewDecoder(resp.Body).Decode(&amp;respBody); err != nil {
	return err
}</code></pre>
            <p>However, <code>json.Decoder</code> stops reading as soon as it finds a complete JSON document or errors. If the response body contains multiple JSON documents or invalid JSON, then the entire response body may still not be read.</p><p>Therefore, in our clients, we’ve started replacing <code>defer response.Body.Close()</code> with the following pattern to ensure that response bodies are always fully read:</p>
            <pre><code>resp, err := http.DefaultClient.Do(req)
if err != nil {
	return err
}
defer func() {
	io.Copy(io.Discard, resp.Body)
	resp.Body.Close()
}()

if err := json.NewDecoder(resp.Body).Decode(&amp;respBody); err != nil {
	return err
}</code></pre>
            
    <div>
      <h2>Actions to take if you encounter ENHANCE_YOUR_CALM</h2>
      <a href="#actions-to-take-if-you-encounter-enhance_your_calm">
        
      </a>
    </div>
    <p>HTTP/2 is a protocol with several features. Many implementations have implemented hardening to protect themselves from misuse of features, which can trigger a connection to be closed. The recommended error code for closing connections in such conditions is ENHANCE_YOUR_CALM. There are numerous HTTP/2 implementations and APIs, which may drive the use of HTTP/2 features in unexpected ways that could appear like attacks.</p><p>If you have an HTTP/2 client that encounters closures with ENHANCE_YOUR_CALM, we recommend that you try to establish ground truth with packet captures (including TLS decryption keys via mechanisms like <a href="https://wiki.wireshark.org/TLS#using-the-pre-master-secret"><u>SSLKEYLOGFILE</u></a>) and/or detailed trace logging. Look for patterns of frequent or repeated frames that might be similar to malicious traffic. Adjusting your client may help avoid it getting misclassified as an attacker.</p><p>If you use Go, we recommend always reading HTTP/2 response bodies (even if empty) in order to avoid sending unnecessary RST_STREAM and PING frames. This is especially important if you use a single connection for multiple requests, which can cause a high frequency of these frames.</p><p>This was also a great reminder of the advantages of dogfooding our own products within our internal services. When we run into issues like this one, our learnings can benefit our customers with similar setups.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6doWYOkW3zbafkANt31knv/b00387716b1971d61eb8b4915ee58783/image5.png" />
          </figure><p></p> ]]></content:encoded>
            <category><![CDATA[HTTP2]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[DDoS]]></category>
            <guid isPermaLink="false">sucWiZHlaWXeLFddHtkk1</guid>
            <dc:creator>Lucas Pardue</dc:creator>
            <dc:creator>Zak Cutner</dc:creator>
        </item>
        <item>
            <title><![CDATA[How we found a bug in Go's arm64 compiler]]></title>
            <link>https://blog.cloudflare.com/how-we-found-a-bug-in-gos-arm64-compiler/</link>
            <pubDate>Wed, 08 Oct 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ 84 million requests a second means even rare bugs appear often. We'll reveal how we discovered a race condition in the Go arm64 compiler and got it fixed. ]]></description>
            <content:encoded><![CDATA[ <p>Every second, 84 million HTTP requests are hitting Cloudflare across our fleet of data centers in 330 cities. It means that even the rarest of bugs can show up frequently. In fact, it was our scale that recently led us to discover a bug in Go's arm64 compiler which causes a race condition in the generated code.</p><p>This post breaks down how we first encountered the bug, investigated it, and ultimately drove to the root cause.</p>
    <div>
      <h2>Investigating a strange panic</h2>
      <a href="#investigating-a-strange-panic">
        
      </a>
    </div>
    <p>We run a service in our network which configures the kernel to handle traffic for some products like <a href="https://www.cloudflare.com/network-services/products/magic-transit/"><u>Magic Transit</u></a> and <a href="https://www.cloudflare.com/network-services/products/magic-wan/"><u>Magic WAN</u></a>. Our monitoring watches this closely, and it started to observe very sporadic panics on arm64 machines.</p><p>We first saw one with a fatal error stating that <a href="https://github.com/golang/go/blob/c0ee2fd4e309ef0b8f4ab6f4860e2626c8e00802/src/runtime/traceback.go#L566"><u>traceback did not unwind completely</u></a>. That error suggests that invariants were violated when traversing the stack, likely because of stack corruption. After a brief investigation we decided that it was probably rare stack memory corruption. This was a largely idle control plane service where unplanned restarts have negligible impact, and so we felt that following up was not a priority unless it kept happening.</p><p>And then it kept happening. </p>
    <div>
      <h4>Coredumps per hour</h4>
      <a href="#coredumps-per-hour">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7ohMD2ph3I9l7lbZQWZ4xl/243e679d8293565fc6a55a670c9f3583/BLOG-2906_2.png" />
          </figure><p>When we first saw this bug we saw that the fatal errors correlated with recovered panics. These were caused by some old code which used panic/recover as error handling. </p><p>At this point, our theory was: </p><ol><li><p>All of the fatal panics happen within stack unwinding.</p></li><li><p>We correlated an increased volume of recovered panics with these fatal panics.</p></li><li><p>Recovering a panic unwinds goroutine stacks to call deferred functions.</p></li><li><p>A related <a href="https://github.com/golang/go/issues/73259"><u>Go issue (#73259)</u></a> reported an arm64 stack unwinding crash.</p></li><li><p>Let’s stop using panic/recover for error handling and wait out the upstream fix?</p></li></ol><p>So we did that and watched as fatal panics stopped occurring as the release rolled out. Fatal panics gone, our theoretical mitigation seemed to work, and this was no longer our problem. We subscribed to the upstream issue so we could update when it was resolved and put it out of our minds.</p><p>But, this turned out to be a much stranger bug than expected. Putting it out of our minds was premature as the same class of fatal panics came back at a much higher rate. A month later, we were seeing up to 30 daily fatal panics with no real discernible cause; while that might account for only one machine a day in less than 10% of our data centers, we found it concerning that we didn’t understand the cause. The first thing we checked was the number of recovered panics, to match our previous pattern, but there were none. More interestingly, we could not correlate this increased rate of fatal panics with anything. A release? Infrastructure changes? The position of Mars? </p><p>At this point we felt like we needed to dive deeper to better understand the root cause. Pattern matching and hoping was clearly insufficient. </p><p>We saw two classes of this bug -- a crash while accessing invalid memory and an explicitly checked fatal error. </p>
    <div>
      <h4>Fatal Error</h4>
      <a href="#fatal-error">
        
      </a>
    </div>
    
            <pre><code>goroutine 153 gp=0x4000105340 m=324 mp=0x400639ea08 [GC worker (active)]:
/usr/local/go/src/runtime/asm_arm64.s:244 +0x6c fp=0x7ff97fffe870 sp=0x7ff97fffe860 pc=0x55558d4098fc
runtime.systemstack(0x0)
       /usr/local/go/src/runtime/mgc.go:1508 +0x68 fp=0x7ff97fffe860 sp=0x7ff97fffe810 pc=0x55558d3a9408
runtime.gcBgMarkWorker.func2()
       /usr/local/go/src/runtime/mgcmark.go:1102
runtime.gcDrainMarkWorkerIdle(...)
       /usr/local/go/src/runtime/mgcmark.go:1188 +0x434 fp=0x7ff97fffe810 sp=0x7ff97fffe7a0 pc=0x55558d3ad514
runtime.gcDrain(0x400005bc50, 0x7)
       /usr/local/go/src/runtime/mgcmark.go:212 +0x1c8 fp=0x7ff97fffe7a0 sp=0x7ff97fffe6f0 pc=0x55558d3ab248
runtime.markroot(0x400005bc50, 0x17e6, 0x1)
       /usr/local/go/src/runtime/mgcmark.go:238 +0xa8 fp=0x7ff97fffe6f0 sp=0x7ff97fffe6a0 pc=0x55558d3ab578
runtime.markroot.func1()
       /usr/local/go/src/runtime/mgcmark.go:887 +0x290 fp=0x7ff97fffe6a0 sp=0x7ff97fffe560 pc=0x55558d3acaa0
runtime.scanstack(0x4014494380, 0x400005bc50)
       /usr/local/go/src/runtime/traceback.go:447 +0x2ac fp=0x7ff97fffe560 sp=0x7ff97fffe4d0 pc=0x55558d3eeb7c
runtime.(*unwinder).next(0x7ff97fffe5b0?)
       /usr/local/go/src/runtime/traceback.go:566 +0x110 fp=0x7ff97fffe4d0 sp=0x7ff97fffe490 pc=0x55558d3eed40
runtime.(*unwinder).finishInternal(0x7ff97fffe4f8?)
       /usr/local/go/src/runtime/panic.go:1073 +0x38 fp=0x7ff97fffe490 sp=0x7ff97fffe460 pc=0x55558d403388
runtime.throw({0x55558de6aa27?, 0x7ff97fffe638?})
runtime stack:
fatal error: traceback did not unwind completely
       stack=[0x4015d6a000-0x4015d8a000
runtime: g8221077: frame.sp=0x4015d784c0 top=0x4015d89fd0</code></pre>
            <p></p>
    <div>
      <h4>Segmentation fault</h4>
      <a href="#segmentation-fault">
        
      </a>
    </div>
    
            <pre><code>goroutine 187 gp=0x40003aea80 m=13 mp=0x40003ca008 [GC worker (active)]:
       /usr/local/go/src/runtime/asm_arm64.s:244 +0x6c fp=0x7fff2afde870 sp=0x7fff2afde860 pc=0x55557e2d98fc
runtime.systemstack(0x0)
       /usr/local/go/src/runtime/mgc.go:1489 +0x94 fp=0x7fff2afde860 sp=0x7fff2afde810 pc=0x55557e279434
runtime.gcBgMarkWorker.func2()
       /usr/local/go/src/runtime/mgcmark.go:1112
runtime.gcDrainMarkWorkerDedicated(...)
       /usr/local/go/src/runtime/mgcmark.go:1188 +0x434 fp=0x7fff2afde810 sp=0x7fff2afde7a0 pc=0x55557e27d514
runtime.gcDrain(0x4000059750, 0x3)
       /usr/local/go/src/runtime/mgcmark.go:212 +0x1c8 fp=0x7fff2afde7a0 sp=0x7fff2afde6f0 pc=0x55557e27b248
runtime.markroot(0x4000059750, 0xb8, 0x1)
       /usr/local/go/src/runtime/mgcmark.go:238 +0xa8 fp=0x7fff2afde6f0 sp=0x7fff2afde6a0 pc=0x55557e27b578
runtime.markroot.func1()
       /usr/local/go/src/runtime/mgcmark.go:887 +0x290 fp=0x7fff2afde6a0 sp=0x7fff2afde560 pc=0x55557e27caa0
runtime.scanstack(0x40042cc000, 0x4000059750)
       /usr/local/go/src/runtime/traceback.go:458 +0x188 fp=0x7fff2afde560 sp=0x7fff2afde4d0 pc=0x55557e2bea58
runtime.(*unwinder).next(0x7fff2afde5b0)
goroutine 0 gp=0x40003af880 m=13 mp=0x40003ca008 [idle]:
PC=0x55557e2bea58 m=13 sigcode=1 addr=0x118
SIGSEGV: segmentation violation</code></pre>
            <p></p><p></p><p>Now we could observe some clear patterns. Both errors occur when unwinding the stack in <code>(*unwinder).next</code>. In one case we saw an intentional<a href="https://github.com/golang/go/blob/b3251514531123d7fd007682389bce7428d159a0/src/runtime/traceback.go#L566"> <u>fatal error</u></a> as the runtime identified that unwinding could not complete and the stack was in a bad state. In the other case there was a direct memory access error that happened while trying to unwind the stack. The segfault was discussed in the <a href="https://github.com/golang/go/issues/73259#issuecomment-2786818812"><u>GitHub issue</u></a> and a Go engineer identified it as dereference of a go scheduler struct, <a href="https://github.com/golang/go/blob/924fe98902cdebf20825ab5d1e4edfc0fed2966f/src/runtime/runtime2.go#L536"><u>m</u></a>, when<a href="https://github.com/golang/go/blob/b3251514531123d7fd007682389bce7428d159a0/src/runtime/traceback.go#L458"> <u>unwinding</u></a>.   </p>
    <div>
      <h3>A review of Go scheduler structs</h3>
      <a href="#a-review-of-go-scheduler-structs">
        
      </a>
    </div>
    <p>Go uses a lightweight userspace scheduler to manage concurrency. Many goroutines are scheduled on a smaller number of kernel threads – this is often referred to as M:N scheduling. Any individual goroutine can be scheduled on any kernel thread. The scheduler has three core types – <a href="https://github.com/golang/go/blob/924fe98902cdebf20825ab5d1e4edfc0fed2966f/src/runtime/runtime2.go#L394"><code><u>g</u></code></a>  (the goroutine), <a href="https://github.com/golang/go/blob/924fe98902cdebf20825ab5d1e4edfc0fed2966f/src/runtime/runtime2.go#L536"><code><u>m</u></code></a> (the kernel thread, or “machine”), and <a href="https://github.com/golang/go/blob/924fe98902cdebf20825ab5d1e4edfc0fed2966f/src/runtime/runtime2.go#L644"><code><u>p</u></code></a> (the physical execution context, or  “processor”). For a goroutine to be scheduled a free <code>m</code> must acquire a free <code>p</code>, which will execute a g. Each <code>g</code> contains a field for its m if it is currently running, otherwise it will be <b>nil</b>. This is all the context needed for this post but the <a href="https://github.com/golang/go/blob/master/src/runtime/HACKING.md#gs-ms-ps"><u>go runtime docs</u></a> explore this more comprehensively. </p><p>At this point we can start to make inferences on what’s happening: the program crashes because we try to unwind a goroutine stack which is invalid. In the first backtrace, if a <a href="https://github.com/golang/go/blob/b3251514531123d7fd007682389bce7428d159a0/src/runtime/traceback.go#L446"><u>return address is null, we call </u><code><u>finishInternal</u></code><u> and abort because the stack was not fully unwound</u></a>. The segmentation fault case in the second backtrace is a bit more interesting: if instead the return address is non-zero but not a function then the unwinder code assumes that the goroutine is currently running. It'll then dereference m and fault by accessing <code>m.incgo</code> (the offset of <code>incgo</code> into <code>struct m</code> is 0x118, the faulting memory access). </p><p>What, then, is causing this corruption? The traces were difficult to get anything useful from – our service has hundreds if not thousands of active goroutines. It was fairly clear from the beginning that the panic was remote from the actual bug. The crashes were all observed while unwinding the stack and if this were an issue any time the stack was unwound on arm64 we would be seeing it in many more services. We felt pretty confident that the stack unwinding was happening correctly but on an invalid stack. </p><p>Our investigation stalled for a while at this point – making guesses, testing guesses, trying to infer if the panic rate went up or down, or if nothing changed. There was <a href="https://github.com/golang/go/issues/73259"><u>a known issue</u></a> on Go’s GitHub issue tracker which matched our symptoms almost exactly, but what they discussed was mostly what we already knew. At some point when looking through the linked stack traces we realized that their crash referenced an old version of a library that we were also using – Go Netlink.</p>
            <pre><code>goroutine 1267 gp=0x4002a8ea80 m=nil [runnable (scan)]:
runtime.asyncPreempt2()
        /usr/local/go/src/runtime/preempt.go:308 +0x3c fp=0x4004cec4c0 sp=0x4004cec4a0 pc=0x46353c
runtime.asyncPreempt()
        /usr/local/go/src/runtime/preempt_arm64.s:47 +0x9c fp=0x4004cec6b0 sp=0x4004cec4c0 pc=0x4a6a8c
github.com/vishvananda/netlink/nl.(*NetlinkSocket).Receive(0x14360300000000?)
        /go/pkg/mod/github.com/!data!dog/netlink@v1.0.1-0.20240223195320-c7a4f832a3d1/nl/nl_linux.go:803 +0x130 fp=0x4004cfc710 sp=0x4004cec6c0 pc=0xf95de0
</code></pre>
            <p></p><p>We spot-checked a few stack traces and confirmed the presence of this Netlink library. Querying our logs showed that not only did we share a library – every single segmentation fault we observed had happened while preempting<a href="https://github.com/vishvananda/netlink/blob/e1e260214862392fb28ff72c9b11adc84df73e2c/nl/nl_linux.go#L880"> <code><u>NetlinkSocket.Receive</u></code></a>.</p>
    <div>
      <h3>What’s (async) preemption?</h3>
      <a href="#whats-async-preemption">
        
      </a>
    </div>
    <p>In the prehistoric era of Go (&lt;=1.13) the runtime was cooperatively scheduled. A goroutine would run until it decided it was ready to yield to the scheduler – usually due to explicit calls to <code>runtime.Gosched()</code> or injected yield points at function calls/IO operations. Since<a href="https://go.dev/doc/go1.14#runtime"> <u>Go 1.14</u></a> the runtime instead does async preemption. The Go runtime has a thread <code>sysmon</code> which tracks the runtime of goroutines and will preempt any that run for longer than 10ms (at time of writing). It does this by sending <code>SIGURG</code> to the OS thread and in the signal handler will modify the program counter and stack to mimic a call to <code>asyncPreempt</code>.</p><p>At this point we had two broad theories:</p><ul><li><p>This is a Go Netlink bug – likely due to <code>unsafe.Pointer</code> usage which invoked undefined behavior but is only actually broken on arm64</p></li><li><p>This is a Go runtime bug and we're only triggering it in <code>NetlinkSocket.Receive</code> for some reason</p></li></ul><p>After finding the same bug publicly reported upstream, we were feeling confident this was caused by a Go runtime bug. However, upon seeing that both issues implicated the same function, we felt more skeptical – notably the Go Netlink library uses unsafe.Pointer so memory corruption was a plausible explanation even if we didn't understand why.</p><p>After an unsuccessful code audit we had hit a wall. The crashes were rare and remote from the root cause. Maybe these crashes were caused by a runtime bug, maybe they were caused by a Go Netlink bug. It seemed clear that there was something wrong with this area of the code, but code auditing wasn’t going anywhere. </p>
    <div>
      <h2>Breakthrough</h2>
      <a href="#breakthrough">
        
      </a>
    </div>
    <p>At this point we had a fairly good understanding of what was crashing but very little understanding of <b>why</b> it was happening. It was clear that the root cause of the stack unwinder crashing was remote from the actual crash, and that it had to do with <code>(*NetlinkSocket).Receive</code>, but why? We were able to capture a <b>coredump</b> of a production crash and view it in a debugger. The backtrace confirmed what we already knew – that there was a segmentation fault when unwinding a stack. The crux of the issue revealed itself when we looked at the goroutine which had been preempted while calling <code>(*NetlinkSocket).Receive</code>.     </p>
            <pre><code>(dlv) bt
0  0x0000555577579dec in runtime.asyncPreempt2
   at /usr/local/go/src/runtime/preempt.go:306
1  0x00005555775bc94c in runtime.asyncPreempt
   at /usr/local/go/src/runtime/preempt_arm64.s:47
2  0x0000555577cb2880 in github.com/vishvananda/netlink/nl.(*NetlinkSocket).Receive
   at
/vendor/github.com/vishvananda/netlink/nl/nl_linux.go:779
3  0x0000555577cb19a8 in github.com/vishvananda/netlink/nl.(*NetlinkRequest).Execute
   at 
/vendor/github.com/vishvananda/netlink/nl/nl_linux.go:532
4  0x0000555577551124 in runtime.heapSetType
   at /usr/local/go/src/runtime/mbitmap.go:714
5  0x0000555577551124 in runtime.heapSetType
   at /usr/local/go/src/runtime/mbitmap.go:714
...
(dlv) disass -a 0x555577cb2878 0x555577cb2888
TEXT github.com/vishvananda/netlink/nl.(*NetlinkSocket).Receive(SB) /vendor/github.com/vishvananda/netlink/nl/nl_linux.go
        nl_linux.go:779 0x555577cb2878  fdfb7fa9        LDP -8(RSP), (R29, R30)
        nl_linux.go:779 0x555577cb287c  ff430191        ADD $80, RSP, RSP
        nl_linux.go:779 0x555577cb2880  ff434091        ADD $(16&lt;&lt;12), RSP, RSP
        nl_linux.go:779 0x555577cb2884  c0035fd6        RET
</code></pre>
            <p></p><p>The goroutine was paused between two opcodes in the function epilogue. Since the process of unwinding a stack relies on the stack frame being in a consistent state, it felt immediately suspicious that we preempted in the middle of adjusting the stack pointer. The goroutine had been paused at 0x555577cb2880, between<code> ADD $80, RSP, RSP and ADD $(16&lt;&lt;12), RSP, RSP</code>. </p><p>We queried the service logs to confirm our theory. This wasn’t isolated – the majority of stack traces showed that this same opcode was preempted. This was no longer a weird production crash we couldn’t reproduce. A crash happened when the Go runtime preempted between these two stack pointer adjustments. We had our smoking gun. </p>
    <div>
      <h2>Building a minimal reproducer</h2>
      <a href="#building-a-minimal-reproducer">
        
      </a>
    </div>
    <p>At this point we felt pretty confident that this was actually just a runtime bug and it should be reproducible in an isolated environment without any dependencies. The theory at this point was:</p><ol><li><p>Stack unwinding is triggered by garbage collection</p></li><li><p>Async preemption between a split stack pointer adjustment causes a crash</p></li><li><p>What if we make a function which splits the adjustment and then call it in a loop?</p></li></ol>
            <pre><code>package main

import (
	"runtime"
)

//go:noinline
func big_stack(val int) int {
	var big_buffer = make([]byte, 1 &lt;&lt; 16)

	sum := 0
	// prevent the compiler from optimizing out the stack
	for i := 0; i &lt; (1&lt;&lt;16); i++ {
		big_buffer[i] = byte(val)
	}
	for i := 0; i &lt; (1&lt;&lt;16); i++ {
		sum ^= int(big_buffer[i])
	}
	return sum
}

func main() {
	go func() {
		for {
			runtime.GC()
		}
	}()
	for {
		_ = big_stack(1000)
	}
}
</code></pre>
            <p></p><p>This function ends up with a stack frame slightly larger than can be represented in 16 bits, and so on arm64 the Go compiler will split the stack pointer adjustment into two opcodes. If the runtime preempts between these opcodes then the stack unwinder will read an invalid stack pointer and crash. </p>
            <pre><code>; epilogue for main.big_stack
ADD $8, RSP, R29
ADD $(16&lt;&lt;12), R29, R29
ADD $16, RSP, RSP
; preemption is problematic between these opcodes
ADD $(16&lt;&lt;12), RSP, RSP
RET
</code></pre>
            <p></p><p>After running this for a few minutes the program panicked as expected!</p>
            <pre><code>SIGSEGV: segmentation violation
PC=0x60598 m=8 sigcode=1 addr=0x118

goroutine 0 gp=0x400019c540 m=8 mp=0x4000198708 [idle]:
runtime.(*unwinder).next(0x400030fd10)
        /home/thea/sdk/go1.23.4/src/runtime/traceback.go:458 +0x188 fp=0x400030fcc0 sp=0x400030fc30 pc=0x60598
runtime.scanstack(0x40000021c0, 0x400002f750)
        /home/thea/sdk/go1.23.4/src/runtime/mgcmark.go:887 +0x290 

[...]

goroutine 1 gp=0x40000021c0 m=nil [runnable (scan)]:
runtime.asyncPreempt2()
        /home/thea/sdk/go1.23.4/src/runtime/preempt.go:308 +0x3c fp=0x40003bfcf0 sp=0x40003bfcd0 pc=0x400cc
runtime.asyncPreempt()
        /home/thea/sdk/go1.23.4/src/runtime/preempt_arm64.s:47 +0x9c fp=0x40003bfee0 sp=0x40003bfcf0 pc=0x75aec
main.big_stack(0x40003cff38?)
        /home/thea/dev/stack_corruption_reproducer/main.go:29 +0x94 fp=0x40003cff00 sp=0x40003bfef0 pc=0x77c04
Segmentation fault (core dumped)

real    1m29.165s
user    4m4.987s
sys     0m43.212s</code></pre>
            <p></p><p>A reproducible crash with standard library only? This felt like conclusive evidence that our problem was a runtime bug.</p><p>This was an extremely particular reproducer! Even now with a good understanding of the bug and its fix, some of the behavior is still puzzling. It's a one-instruction race condition, so it’s unsurprising that small changes could have large impact. For example, this reproducer was originally written and tested on Go 1.23.4, but did not crash when compiled with 1.23.9 (the version in production), even though we could objdump the binary and see the split ADD still present! We don’t have a definite explanation for this behavior – even with the bug present there remain a few unknown variables which affect the likelihood of hitting the race condition. </p>
    <div>
      <h2>A single-instruction race condition window</h2>
      <a href="#a-single-instruction-race-condition-window">
        
      </a>
    </div>
    <p>arm64 is a fixed-length 4-byte instruction set architecture. This has a lot of implications on codegen but most relevant to this bug is the fact that immediate length is limited.<a href="https://developer.arm.com/documentation/ddi0596/2020-12/Base-Instructions/ADD--immediate---Add--immediate--"> <code><u>add</u></code></a> gets a 12-bit immediate,<a href="https://developer.arm.com/documentation/dui0802/a/A64-General-Instructions/MOV--wide-immediate-"> <code><u>mov</u></code></a> gets a 16-bit immediate, etc. How does the architecture handle this when the operands don't fit? It depends – <code>ADD</code> in particular reserves a bit for "shift left by 12" so any 24 bit addition can be decomposed into two opcodes. Other instructions are decomposed similarly, or just require loading an immediate into a register first. </p><p>The very last step of the Go compiler before emitting machine code involves transforming the program into <code>obj.Prog</code> structs. It's a very low level intermediate representation (IR) that mostly serves to be translated into machine code. </p>
            <pre><code>//https://github.com/golang/go/blob/fa2bb342d7b0024440d996c2d6d6778b7a5e0247/src/cmd/internal/obj/arm64/obj7.go#L856

// Pop stack frame.
// ADD $framesize, RSP, RSP
p = obj.Appendp(p, c.newprog)
p.As = AADD
p.From.Type = obj.TYPE_CONST
p.From.Offset = int64(c.autosize)
p.To.Type = obj.TYPE_REG
p.To.Reg = REGSP
p.Spadj = -c.autosize
</code></pre>
            <p></p><p>Notably, this IR is not aware of immediate length limitations. Instead, this happens in<a href="https://github.com/golang/go/blob/2f653a5a9e9112ff64f1392ff6e1d404aaf23e8c/src/cmd/internal/obj/arm64/asm7.go"> <u>asm7.go</u></a> when Go's internal intermediate representation is translated into arm64 machine code. The assembler will classify an immediate in <a href="https://github.com/golang/go/blob/2f653a5a9e9112ff64f1392ff6e1d404aaf23e8c/src/cmd/internal/obj/arm64/asm7.go#L1905"><u>conclass</u></a> based on bit size and then use that when emitting instructions – extra if needed.</p><p>The Go assembler uses a combination of (<code>mov, add</code>) opcodes for some adds that fit in 16-bit immediates, and prefers (<code>add, add + lsl 12</code>) opcodes for 16-bit+ immediates.   </p><p>Compare a stack of (slightly larger than) <code>1&lt;&lt;15</code>:</p>
            <pre><code>; //go:noinline
; func big_stack() byte {
; 	var big_stack = make([]byte, 1&lt;&lt;15)
; 	return big_stack[0]
; }
MOVD $32776, R27
ADD R27, RSP, R29
MOVD $32784, R27
ADD R27, RSP, RSP
RET
</code></pre>
            <p></p><p>With a stack of <code>1&lt;&lt;16</code>:</p>
            <pre><code>; //go:noinline
; func big_stack() byte {
; 	var big_stack = make([]byte, 1&lt;&lt;16)
; 	return big_stack[0]
; } 
ADD $8, RSP, R29
ADD $(16&lt;&lt;12), R29, R29
ADD $16, RSP, RSP
ADD $(16&lt;&lt;12), RSP, RSP
RET
</code></pre>
            <p>In the larger stack case, there is a point between <code>ADD x, RSP, RSP</code> opcodes where the stack pointer is not pointing to the tip of a stack frame. We thought at first that this was a matter of memory corruption – that in handling async preemption the runtime would push a function call on the stack and corrupt the middle of the stack. However, this goroutine is already in the function epilogue – any data we corrupt is actively in the process of being thrown away. What's the issue then?  </p><p>The Go runtime often needs to <b>unwind</b> the stack, which means walking backwards through the chain of function calls. For example: garbage collection uses it to find live references on the stack, panicking relies on it to evaluate <code>defer</code> functions, and generating stack traces needs to print the call stack. For this to work the stack pointer <b>must be accurate during unwinding</b> because of how golang dereferences sp to determine the calling function. If the stack pointer is partially modified, the unwinder will look for the calling function in the middle of the stack. The underlying data is meaningless when interpreted as directions to a parent stack frame and then the runtime will likely crash. </p>
            <pre><code>//https://github.com/golang/go/blob/66536242fce34787230c42078a7bbd373ef8dcb0/src/runtime/traceback.go#L373

if innermost &amp;&amp; frame.sp &lt; frame.fp || frame.lr == 0 {
    lrPtr = frame.sp
    frame.lr = *(*uintptr)(unsafe.Pointer(lrPtr))
}
</code></pre>
            <p></p><p>When async preemption happens it will push a function call onto the stack but the parent stack frame is no longer correct because sp was only partially adjusted when the preemption happened. The crash flow looks something like this:  </p><ol><li><p>Async preemption happens between the two opcodes that <code>add x, rsp</code> expands to</p></li><li><p>Garbage collection triggers stack unwinding (to check for heap object liveness)</p></li><li><p>The unwinder starts traversing the stack of the problematic goroutine and correctly unwinds up to the problematic function</p></li><li><p>The unwinder dereferences <code>sp</code> to determine the parent function</p></li><li><p>Almost certainly the data behind <code>sp</code> is not a function</p></li><li><p>Crash</p></li></ol>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5LKOBC6lQzuKvwy0vyEfk2/054c9aaedc14d155294a682f7de3a610/BLOG-2906_3.png" />
          </figure><p>We saw earlier a faulting stack trace which ended in <code>(*NetlinkSocket).Receive</code> – in this case stack unwinding faulted while it was trying to determine the parent frame.    </p>
            <pre><code>goroutine 90 gp=0x40042cc000 m=nil [preempted (scan)]:
runtime.asyncPreempt2()
/usr/local/go/src/runtime/preempt.go:306 +0x2c fp=0x40060a25d0 sp=0x40060a25b0 pc=0x55557e299dec
runtime.asyncPreempt()
/usr/local/go/src/runtime/preempt_arm64.s:47 +0x9c fp=0x40060a27c0 sp=0x40060a25d0 pc=0x55557e2dc94c
github.com/vishvananda/netlink/nl.(*NetlinkSocket).Receive(0xff48ce6e060b2848?)
/vendor/github.com/vishvananda/netlink/nl/nl_linux.go:779 +0x130 fp=0x40060b2820 sp=0x40060a27d0 pc=0x55557e9d2880
</code></pre>
            <p></p><p>Once we discovered the root cause we reported it with a reproducer and the bug was quickly fixed. This bug is fixed in <a href="https://github.com/golang/go/commit/e8794e650e05fad07a33fb6e3266a9e677d13fa8"><u>go1.23.12</u></a>, <a href="https://github.com/golang/go/commit/6e1c4529e4e00ab58572deceab74cc4057e6f0b6"><u>go1.24.6</u></a>, and <a href="https://github.com/golang/go/commit/f7cc61e7d7f77521e073137c6045ba73f66ef902"><u>go1.25.0</u></a>. Previously, the go compiler emitted a single <code>add x, rsp</code> instruction and relied on the assembler to split immediates into multiple opcodes as necessary. After this change, stacks larger than 1&lt;&lt;12 will build the offset in a temporary register and then add that to <code>rsp</code> in a single, indivisible opcode. A goroutine can be preempted before or after the stack pointer modification, but never during. This means that the stack pointer is always valid and there is no race condition.</p>
            <pre><code>LDP -8(RSP), (R29, R30)
MOVD $32, R27
MOVK $(1&lt;&lt;16), R27
ADD R27, RSP, RSP
RET</code></pre>
            <p></p><p>This was a very fun problem to debug. We don’t often see bugs where you can accurately blame the compiler. Debugging it took weeks and we had to learn about areas of the Go runtime that people don’t usually need to think about. It’s a nice example of a rare race condition, the sort of bug that can only really be quantified at a large scale.</p><p>We’re always looking for people who enjoy this kind of detective work. <a href="https://www.cloudflare.com/careers/jobs/?department=Engineering"><u>Our engineering teams are hiring</u></a>.   </p> ]]></content:encoded>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Programming]]></category>
            <guid isPermaLink="false">12E3V053vhNrZrU5I2AAV1</guid>
            <dc:creator>Thea Heinen</dc:creator>
        </item>
        <item>
            <title><![CDATA[Building Jetflow: a framework for flexible, performant data pipelines at Cloudflare]]></title>
            <link>https://blog.cloudflare.com/building-jetflow-a-framework-for-flexible-performant-data-pipelines-at-cloudflare/</link>
            <pubDate>Wed, 23 Jul 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ Faced with a data-ingestion challenge at a massive scale, Cloudflare's Business Intelligence team built a new framework called Jetflow. ]]></description>
            <content:encoded><![CDATA[ <p>The Cloudflare Business Intelligence team manages a <a href="https://simple.wikipedia.org/wiki/Petabyte"><u>petabyte</u></a>-scale <a href="https://www.cloudflare.com/learning/cloud/what-is-a-data-lake/"><u>data lake</u></a> and ingests thousands of tables every day from many different sources. These include internal databases such as Postgres and ClickHouse, as well as external SaaS applications such as Salesforce. These tasks are often complex and tables may have hundreds of millions or billions of rows of new data each day. They are also business-critical for product decisions, growth plannings, and internal monitoring. In total, about <b>141 billion rows</b> are ingested every day.</p><p>As Cloudflare has grown, the data has become ever larger and more complex. Our existing <a href="https://www.ibm.com/think/topics/elt"><u>Extract Load Transform (ELT)</u></a> solution could no longer meet our technical and business requirements. After evaluating other common ELT solutions, we concluded that their performance generally did not surpass our current system, either.</p><p>It became clear that we needed to build our own framework to cope with our unique requirements — and so <b>Jetflow</b> was born. </p>
    <div>
      <h2>What we achieved</h2>
      <a href="#what-we-achieved">
        
      </a>
    </div>
    <p><b>Over 100x efficiency improvement in GB-s</b>:</p><ul><li><p>Our longest running job with 19 billion rows was taking <b>48 hours</b> using <b>300 GB of memory</b>, and now completes in <b>5.5 hours</b> using <b>4 GB of memory</b></p></li><li><p>We estimate that ingestion of 50 TB from Postgres via <b>Jetflow</b> could cost under $100 based on rates published by commercial cloud providers</p></li></ul><p><b>&gt;10x performance improvement:</b></p><ul><li><p>Our largest dataset was ingesting <b>60-80,000</b> rows per second, this is now <b>2-5 million</b> rows per second per database connection.</p></li><li><p>In addition, these numbers scale well with multiple database connections for some databases.</p></li></ul><p><b>Extensibility: </b></p><ul><li><p>The modular design makes it easy to extend and test<b>. </b>Today<b> Jetflow</b> works with ClickHouse, Postgres, Kafka, many different SaaS APIs, Google BigQuery and many others. It has continued to work well and remain flexible with the addition of new use cases.</p></li></ul>
    <div>
      <h2>How did we do this?</h2>
      <a href="#how-did-we-do-this">
        
      </a>
    </div>
    
    <div>
      <h3>Requirements</h3>
      <a href="#requirements">
        
      </a>
    </div>
    <p>The first step to designing our new framework had to be a clear understanding of the problems we were aiming to solve, with clear requirements to stop us creating new ones.</p>
    <div>
      <h5>Performant &amp; efficient</h5>
      <a href="#performant-efficient">
        
      </a>
    </div>
    <p>We needed to be able to move more data in less time as some ingestion jobs were taking ~24 hours, and our data will only grow. The data should be ingested in a streaming fashion and use less memory and compute resources than our existing solution.</p>
    <div>
      <h5>Backwards compatible </h5>
      <a href="#backwards-compatible">
        
      </a>
    </div>
    <p>Given the daily ingestion of thousands of tables, the chosen solution needed to allow for the migration of individual tables as needed. Due to our usage of <a href="https://spark.apache.org/"><u>Spark</u></a> downstream and Spark's limitations in merging disparate <a href="https://parquet.apache.org/"><u>Parquet</u></a> schemas, the chosen solution had to offer the flexibility to generate the precise schemas needed for each case to match legacy.</p><p>We also required seamless integration with our custom metadata system, used for dependency checks and job status information.</p>
    <div>
      <h5>Ease of use</h5>
      <a href="#ease-of-use">
        
      </a>
    </div>
    <p>We want a configuration file that can be version-controlled, without introducing bottlenecks on repositories with many concurrent changes.</p><p>To increase accessibility for different roles within the team, another requirement was no-code (or configuration as code) in the vast majority of cases. Users should not have to worry about availability or translation of data types between source and target systems, or writing new code for each new ingestion. The configuration needed should also be minimal — for example, data schema should be inferred from the source system and not need to be supplied by the user.</p>
    <div>
      <h5>Customizable</h5>
      <a href="#customizable">
        
      </a>
    </div>
    <p>Striking a balance with the no-code requirement above, although we want a low bar of entry we also want to have the option to tune and override options if desired, with a flexible and optional configuration layer. For example, writing Parquet files is often more expensive than reading from the database, so we want to be able to allocate more resources and concurrency as needed. </p><p>Additionally, we wanted to allow for control over where the work is executed, with the ability to spin up concurrent workers in different threads, different containers, or on different machines. The execution of workers and communication of data was abstracted away with an interface, and different implementations can be written and injected, controlled via the job configuration. </p>
    <div>
      <h5>Testable</h5>
      <a href="#testable">
        
      </a>
    </div>
    <p>We wanted a solution capable of running locally in a containerized environment, which would allow us to write tests for every stage of the pipeline. With “black box” solutions, testing often means validating the output after making a change, which is a slow feedback loop, risks not testing all edge cases as there isn’t good visibility of all code paths internally, and makes debugging issues painful.</p>
    <div>
      <h3>Designing a flexible framework </h3>
      <a href="#designing-a-flexible-framework">
        
      </a>
    </div>
    <p>To build a truly flexible framework, we broke the pipeline down into distinct stages, and then create a config layer to define the composition of the pipeline from these stages, and any configuration overrides. Every pipeline configuration that makes sense logically should execute correctly, and users should not be able to create pipeline configs that do not work. </p>
    <div>
      <h5>Pipeline configuration</h5>
      <a href="#pipeline-configuration">
        
      </a>
    </div>
    <p>This led us to a design where we created stages which were classified according to the meaningfully different categories of:</p><ul><li><p>Consumers</p></li><li><p>Transformers</p></li><li><p>Loaders</p></li></ul>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1ALi9AXyo5v1Y7cIjK619V/3c0735e2d5b36d5660072f92fe551ed3/image3.png" />
          </figure><p>The pipeline was constructed via a <a href="https://yaml.org/"><u>YAML</u></a> file that required a consumer, zero or more transformers, and at least one loader. Consumers create a data stream (via reading from the source system), Transformers (e.g. data transformations, validations) take a data stream input and output a data stream conforming to the same API so that they can be chained, and Loaders have the same data streaming interface, but are the stages with persistent effects — i.e. stages where data is saved to an external system. </p><p>This modular design means that each stage is independently testable, with shared behaviour (such as error handling and concurrency) inherited from shared base stages, significantly decreasing development time for new use cases and increasing confidence in code correctness.</p>
    <div>
      <h5>Data divisions</h5>
      <a href="#data-divisions">
        
      </a>
    </div>
    <p>Next, we designed a breakdown for the data that would allow the pipeline to be idempotent both on whole pipeline re-run and also on internal retry of any data partition due to transient error. We decided on a design that let us parallelize processing, while maintaining meaningful data divisions that allowed the pipeline to perform cleanups of data where required for a retry.</p><ul><li><p><b>RunInstance</b>: the least granular division, corresponding to a business unit for a single run of the pipeline (e.g. one month/day/hour of data). </p></li><li><p><b>Partition</b>: a division of the RunInstance that allows each row to be allocated to a partition in a way that is deterministic and self-evident from the row data without external state, and is therefore idempotent on retry. (e.g. an accountId range, a 10-minute interval)</p></li><li><p><b>Batch</b>: a division of the partition data that is non-deterministic and used only to break the data down into smaller chunks for streaming/parallel processing for faster processing with fewer resources. (e.g. 10k rows, 50 MB)</p></li></ul><p>The options that the user configures in the consumer stage YAML both construct the query that is used to retrieve the data from the source system, and also encode the semantic meaning of this data division in a system agnostic way, so that later stages understand what this data represents — e.g. this partition contains the data for all accounts IDs 0-500. This means that we can do targeted data cleanup and avoid, for example, duplicate data entries if a single data partition is retried due to error.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1NQsitJmwRwSpiLkj2Hoig/81db1750523268bb427d51e1d2746a46/image2.png" />
          </figure>
    <div>
      <h3>Framework implementation</h3>
      <a href="#framework-implementation">
        
      </a>
    </div>
    
    <div>
      <h5>Standard internal state for stage compatibility </h5>
      <a href="#standard-internal-state-for-stage-compatibility">
        
      </a>
    </div>
    <p>Our most common use case is something like read from a database, convert to Parquet format, and then save to <a href="https://www.cloudflare.com/learning/cloud/what-is-object-storage/">object storage,</a> with each of these steps being a separate stage. As more use cases were onboarded to <b>Jetflow,</b> we had to make sure that if someone wrote a new stage it would be compatible with the other stages. We don’t want to create a situation where new code needs to be written for every output format and target system, or you end up with a custom pipeline for every different use case.</p><p>The way we have solved this problem is by having our stage extractor class only allow output data in a single format. This means as long as any downstream stages support this format as in the input and output format they would be compatible with the rest of the pipeline. This seems obvious in retrospect, but internally was a painful learning experience, as we originally created a custom type system and struggled with stage interoperability. </p><p>For this internal format, we chose to use <a href="https://arrow.apache.org/"><u>Arrow</u></a>, an in-memory columnar data format. The key benefits of this format for us are:</p><ul><li><p><b>Arrow ecosystem</b>: Many data projects now support Arrow as an output format. This means when we write extractor stages for new data sources, it is often trivial to produce Arrow output.</p></li><li><p><b>No serialisation overhead</b>: This makes it easy to move Arrow data between machines and even programming languages with minimum overhead. <b>Jetflow</b> was designed from the start to have the flexibility to be able to run in a wide range of systems via a job controller interface, so this efficiency in data transmission means there’s minimal compromise on performance when creating distributed implementations.</p></li><li><p><b>Reserve memory in large fixed-size batches to avoid memory allocations</b>: As Go is a garbage collected (GC) language and GC cycle times are affected mostly by the number of objects rather than the sizes of those objects, fewer heap objects reduces CPU time spent garbage collecting significantly, even if the total size is the same. As the number of objects to scan, and possibly collect, during a GC cycle increases with the number of allocations, if we have 8192 rows with 10 columns each, Arrow would only require us to do 10 allocations versus the 8192 allocations of most drivers that allocate on a row by row basis, meaning fewer objects and lower GC cycle times with Arrow.</p></li></ul>
    <div>
      <h5>Converting rows to columns</h5>
      <a href="#converting-rows-to-columns">
        
      </a>
    </div>
    <p>Another important performance optimization was reducing the number of conversion steps that happen when reading and processing data. Most data ingestion frameworks internally represent data as rows. In our case, we are mostly writing data in Parquet format, which is column based. When reading data from column-based sources (e.g. ClickHouse, where most drivers receive RowBinary format), converting into row-based memory representations for the specific language implementation is inefficient. This is then converted again from rows to columns to write Parquet files. These conversions result in a significant performance impact.</p><p><b>Jetflow</b> instead reads data from column-based sources in columnar formats (e.g. for ClickHouse-native Block format) and then copies this data into Arrow column format. Parquet files are then written directly from Arrow columns. The simplification of this process improves performance.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5HEuO0Cn6Wob7tuR9hjnSP/852cdc44244f107b4289fb3b3553d213/image1.png" />
          </figure>
    <div>
      <h3>Writing each pipelines stage</h3>
      <a href="#writing-each-pipelines-stage">
        
      </a>
    </div>
    
    <div>
      <h5>Case study: ClickHouse</h5>
      <a href="#case-study-clickhouse">
        
      </a>
    </div>
    <p>When testing an initial version of <b>Jetflow</b>, we discovered<b> </b>that due to the architecture of ClickHouse, using additional connections would not be of any benefit, since ClickHouse was reading faster than we were receiving data. It should then be possible, with a more optimized database driver, to take better advantage of that single connection to read a much larger number of rows per second, without needing additional connections.</p><p>Initially, a custom database driver was written for ClickHouse, but we ended up switching to the excellent <a href="https://github.com/ClickHouse/ch-go"><u>ch-go low level library</u></a>, which directly reads <a href="https://clickhouse.com/docs/development/architecture#block"><u>Blocks</u></a> from ClickHouse in a columnar format. This had a dramatic effect on performance in comparison to the standard Go driver. Combined with the framework optimisations above, we now <b>ingest millions of rows per second</b> with a single ClickHouse connection.</p><p>A valuable lesson learned is that as with any software, tradeoffs are often made for the sake of convenience or a common use case that may not match your own. Most database drivers tend not to be optimized for reading large batches of rows, and have high per-row overhead.</p>
    <div>
      <h5>Case study: Postgres</h5>
      <a href="#case-study-postgres">
        
      </a>
    </div>
    <p>For Postgres, we use the excellent <a href="https://github.com/jackc/pgx"><u>jackc/pgx</u></a> driver, but instead of using the database/sql Scan interface, we directly receive the raw bytes for each row and use the jackc/pgx internal scan functions for each Postgres OID (Object Identifier) type.</p><p>The database/sql Scan interface in Go uses reflection to understand the type passed to the function and then also uses reflection to set each field with the column value received from Postgres. In typical scenarios, this is fast enough and easy to use, but falls short for our use cases in terms of performance. The <a href="https://github.com/jackc/pgx"><u>jackc/pgx</u></a> driver reuses the row bytes produced each time the next Postgres row is requested, resulting in zero allocations per row. This allows us to write high-performance, low-allocation code within Jetflow. With this design, we are able to achieve nearly <b>600,000 rows per second</b> per Postgres connection for most tables, with very low memory usage.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>As of early July 2025, the team ingests <b>77 billion</b> records per day via <b>Jetflow</b>. The remaining jobs are in the process of being migrated to <b>Jetflow</b>, which will bring the total daily ingestion to 141 billion records. The framework has allowed us to ingest tables in cases that would not otherwise have been possible, and provided significant cost savings due to ingestions running for less time and with fewer resources. </p><p>In the future, we plan to open source the project, and if you are interested in joining our team to help develop tools like this, then open roles can be found at <a href="https://www.cloudflare.com/en-gb/careers/jobs/"><u>https://www.cloudflare.com/careers/jobs/</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Data]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Performance]]></category>
            <category><![CDATA[Design]]></category>
            <category><![CDATA[Engineering]]></category>
            <guid isPermaLink="false">4wAX6JGDuRNIJwVqwdgrP8</guid>
            <dc:creator>Harry Hough</dc:creator>
            <dc:creator>Rebecca Walton-Jones </dc:creator>
            <dc:creator>Andy Fan</dc:creator>
            <dc:creator>Ricardo Margalhau</dc:creator>
            <dc:creator>Uday Sharma</dc:creator>
        </item>
        <item>
            <title><![CDATA[Over 700 million events/second: How we make sense of too much data]]></title>
            <link>https://blog.cloudflare.com/how-we-make-sense-of-too-much-data/</link>
            <pubDate>Mon, 27 Jan 2025 14:00:00 GMT</pubDate>
            <description><![CDATA[ Here we explain how we made our data pipeline scale to 700 million events per second while becoming more resilient than ever before. We share some math behind our approach and some of the designs of  ]]></description>
            <content:encoded><![CDATA[ <p>Cloudflare's network provides an enormous array of services to our customers. We collect and deliver associated data to customers in the form of event logs and aggregated analytics. As of December 2024, our data pipeline is ingesting up to 706M events per second generated by Cloudflare's services, and that represents 100x growth since our <a href="https://blog.cloudflare.com/http-analytics-for-6m-requests-per-second-using-clickhouse/"><u>2018 data pipeline blog post</u></a>. </p><p>At peak, we are moving 107 <a href="https://simple.wikipedia.org/wiki/Gibibyte"><u>GiB</u></a>/s of compressed data, either pushing it directly to customers or subjecting it to additional queueing and batching.</p><p>All of these data streams power things like <a href="https://developers.cloudflare.com/logs/"><u>Logs</u></a>, <a href="https://developers.cloudflare.com/analytics/"><u>Analytics</u></a>, and billing, as well as other products, such as training machine learning models for bot detection. This blog post is focused on techniques we use to efficiently and accurately deal with the high volume of data we ingest for our Analytics products. A previous <a href="https://blog.cloudflare.com/cloudflare-incident-on-november-14-2024-resulting-in-lost-logs/"><u>blog post</u></a> provides a deeper dive into the data pipeline for Logs. </p><p>The pipeline can be roughly described by the following diagram.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5ihv6JXx19nJiEyfCaCg8V/ad7081720514bafd070cc38a04bc7097/BLOG-2486_2.jpg" />
          </figure><p>The data pipeline has multiple stages, and each can and will naturally break or slow down because of hardware failures or misconfiguration. And when that happens, there is just too much data to be able to buffer it all for very long. Eventually some will get dropped, causing gaps in analytics and a degraded product experience unless proper mitigations are in place.</p>
    <div>
      <h3>Dropping data to retain information</h3>
      <a href="#dropping-data-to-retain-information">
        
      </a>
    </div>
    <p>How does one retain valuable information from more than half a billion events per second, when some must be dropped? Drop it in a controlled way, by downsampling.</p><p>Here is a visual analogy showing the difference between uncontrolled data loss and downsampling. In both cases the same number of pixels were delivered. One is a higher resolution view of just a small portion of a popular painting, while the other shows the full painting, albeit blurry and highly pixelated.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4kUGB4RLQzFb7cphMpHqAg/e7ccf871c73e0e8ca9dcac32fe265f18/Screenshot_2025-01-24_at_10.57.17_AM.png" />
          </figure><p>As we noted above, any point in the pipeline can fail, so we want the ability to downsample at any point as needed. Some services proactively downsample data at the source before it even hits Logfwdr. This makes the information extracted from that data a little bit blurry, but much more useful than what otherwise would be delivered: random chunks of the original with gaps in between, or even nothing at all. The amount of "blur" is outside our control (we make our best effort to deliver full data), but there is a robust way to estimate it, as discussed in the <a href="/how-we-make-sense-of-too-much-data/#extracting-value-from-downsampled-data"><u>next section</u></a>.</p><p>Logfwdr can decide to downsample data sitting in the buffer when it overflows. Logfwdr handles many data streams at once, so we need to prioritize them by assigning each data stream a weight and then applying <a href="https://en.wikipedia.org/wiki/Max-min_fairness"><u>max-min fairness</u></a> to better utilize the buffer. It allows each data stream to store as much as it needs, as long as the whole buffer is not saturated. Once it is saturated, streams divide it fairly according to their weighted size.</p><p>In our implementation (Go), each data stream is driven by a goroutine, and they cooperate via channels. They consult a single tracker object every time they allocate and deallocate memory. The tracker uses a <a href="https://en.wikipedia.org/wiki/Heap_(data_structure)"><u>max-heap</u></a> to always know who the heaviest participant is and what the total usage is. Whenever the total usage goes over the limit, the tracker repeatedly sends the "please shed some load" signal to the heaviest participant, until the usage is again under the limit.</p><p>The effect of this is that healthy streams, which buffer a tiny amount, allocate whatever they need without losses. But any lagging streams split the remaining memory allowance fairly.</p><p>We downsample more or less uniformly, by always taking some of the least downsampled batches from the buffer (using min-heap to find those) and merging them together upon downsampling.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/15VP0VYkrvkQboX9hrOy0q/e3d087fe704bd1b0ee41eb5b7a24b899/BLOG-2486_4.png" />
          </figure><p><sup><i>Merging keeps the batches roughly the same size and their number under control.</i></sup></p><p>Downsampling is cheap, but since data in the buffer is compressed, it causes recompression, which is the single most expensive thing we do to the data. But using extra CPU time is the last thing you want to do when the system is under heavy load! We compensate for the recompression costs by starting to downsample the fresh data as well (before it gets compressed for the first time) whenever the stream is in the "shed the load" state.</p><p>We called this approach "bottomless buffers", because you can squeeze effectively infinite amounts of data in there, and it will just automatically be thinned out. Bottomless buffers resemble <a href="https://en.wikipedia.org/wiki/Reservoir_sampling"><u>reservoir sampling</u></a>, where the buffer is the reservoir and the population comes as the input stream. But there are some differences. First is that in our pipeline the input stream of data never ends, while reservoir sampling assumes it ends to finalize the sample. Secondly, the resulting sample also never ends.</p><p>Let's look at the next stage in the pipeline: Logreceiver. It sits in front of a distributed queue. The purpose of logreceiver is to partition each stream of data by a key that makes it easier for Logpush, Analytics inserters, or some other process to consume.</p><p>Logreceiver proactively performs adaptive sampling of analytics. This improves the accuracy of analytics for small customers (receiving on the order of 10 events per day), while more aggressively downsampling large customers (millions of events per second). Logreceiver then pushes the same data at multiple resolutions (100%, 10%, 1%, etc.) into different topics in the distributed queue. This allows it to keep pushing something rather than nothing when the queue is overloaded, by just skipping writing the high-resolution samples of data.</p><p>The same goes for Inserters: they can skip <i>reading or writing</i> high-resolution data. The Analytics APIs can skip <i>reading</i> high resolution data. The analytical database might be unable to read high resolution data because of overload or degraded cluster state or because there is just too much to read (very wide time range or very large customer). Adaptively dropping to lower resolutions allows the APIs to return <i>some</i> results in all of those cases.</p>
    <div>
      <h3>Extracting value from downsampled data</h3>
      <a href="#extracting-value-from-downsampled-data">
        
      </a>
    </div>
    <p>Okay, we have some downsampled data in the analytical database. It looks like the original data, but with some rows missing. How do we make sense of it? How do we know if the results can be trusted?</p><p>Let's look at the math.</p>Since the amount of sampling can vary over time and between nodes in the distributed system, we need to store this information along with the data. With each event $x_i$ we store its sample interval, which is the reciprocal to its inclusion probability $\pi_i = \frac{1}{\text{sample interval}}$. For example, if we sample 1 in every 1,000 events, each of the events included in the resulting sample will have its $\pi_i = 0.001$, so the sample interval will be 1,000. When we further downsample that batch of data, the inclusion probabilities (and the sample intervals) multiply together: a 1 in 1,000 sample from a 1 in 1,000 sample is a 1 in 1,000,000 sample of the original population. The sample interval of an event can also be interpreted roughly as the number of original events that this event represents, so in the literature it is known as weight $w_i = \frac{1}{\pi_i}$.
<p></p>
We rely on the <a href="https://en.wikipedia.org/wiki/Horvitz%E2%80%93Thompson_estimator">Horvitz-Thompson estimator</a> (HT, <a href="https://www.stat.cmu.edu/~brian/905-2008/papers/Horvitz-Thompson-1952-jasa.pdf">paper</a>) in order to derive analytics about $x_i$. It gives two estimates: the analytical estimate (e.g. the population total or size) and the estimate of the variance of that estimate. The latter enables us to figure out how accurate the results are by building <a href="https://en.wikipedia.org/wiki/Confidence_interval">confidence intervals</a>. They define ranges that cover the true value with a given probability <i>(confidence level)</i>. A typical confidence level is 0.95, at which a confidence interval (a, b) tells that you can be 95% sure the true SUM or COUNT is between a and b.
<p></p><p>So far, we know how to use the HT estimator for doing SUM, COUNT, and AVG.</p>Given a sample of size $n$, consisting of values $x_i$ and their inclusion probabilities $\pi_i$, the HT estimator for the population total (i.e. SUM) would be

$$\widehat{T}=\sum_{i=1}^n{\frac{x_i}{\pi_i}}=\sum_{i=1}^n{x_i w_i}.$$

The variance of $\widehat{T}$ is:

$$\widehat{V}(\widehat{T}) = \sum_{i=1}^n{x_i^2 \frac{1 - \pi_i}{\pi_i^2}} + \sum_{i \neq j}^n{x_i x_j \frac{\pi_{ij} - \pi_i \pi_j}{\pi_{ij} \pi_i \pi_j}},$$

where $\pi_{ij}$ is the probability of both $i$-th and $j$-th events being sampled together.
<p></p>
We use <a href="https://en.wikipedia.org/wiki/Poisson_sampling">Poisson sampling</a>, where each event is subjected to an independent <a href="https://en.wikipedia.org/wiki/Bernoulli_trial">Bernoulli trial</a> ("coin toss") which determines whether the event becomes part of the sample. Since each trial is independent, we can equate $\pi_{ij} = \pi_i \pi_j$, which when plugged in the variance estimator above turns the right-hand sum to zero:

$$\widehat{V}(\widehat{T}) = \sum_{i=1}^n{x_i^2 \frac{1 - \pi_i}{\pi_i^2}} + \sum_{i \neq j}^n{x_i x_j \frac{0}{\pi_{ij} \pi_i \pi_j}},$$

thus

$$\widehat{V}(\widehat{T}) = \sum_{i=1}^n{x_i^2 \frac{1 - \pi_i}{\pi_i^2}} = \sum_{i=1}^n{x_i^2 w_i (w_i-1)}.$$

For COUNT we use the same estimator, but plug in $x_i = 1$. This gives us:

$$\begin{align}
\widehat{C} &amp;= \sum_{i=1}^n{\frac{1}{\pi_i}} = \sum_{i=1}^n{w_i},\\
\widehat{V}(\widehat{C}) &amp;= \sum_{i=1}^n{\frac{1 - \pi_i}{\pi_i^2}} = \sum_{i=1}^n{w_i (w_i-1)}.
\end{align}$$

For AVG we would use

$$\begin{align}
\widehat{\mu} &amp;= \frac{\widehat{T}}{N},\\
\widehat{V}(\widehat{\mu}) &amp;= \frac{\widehat{V}(\widehat{T})}{N^2},
\end{align}$$

if we could, but the original population size $N$ is not known, it is not stored anywhere, and it is not even possible to store because of custom filtering at query time. Plugging $\widehat{C}$ instead of $N$ only partially works. It gives a valid estimator for the mean itself, but not for its variance, so the constructed confidence intervals are unusable.
<p></p>
In all cases the corresponding pair of estimates are used as the $\mu$ and $\sigma^2$ of the normal distribution (because of the <a href="https://en.wikipedia.org/wiki/Central_limit_theorem">central limit theorem</a>), and then the bounds for the confidence interval (of confidence level ) are:

$$\Big( \mu - \Phi^{-1}\big(\frac{1 + \alpha}{2}\big) \cdot \sigma, \quad \mu + \Phi^{-1}\big(\frac{1 + \alpha}{2}\big) \cdot \sigma\Big).$$<p>We do not know the N, but there is a workaround: simultaneous confidence intervals. Construct confidence intervals for SUM and COUNT independently, and then combine them into a confidence interval for AVG. This is known as the <a href="https://www.sciencedirect.com/topics/mathematics/bonferroni-method"><u>Bonferroni method</u></a>. It requires generating wider (half the "inconfidence") intervals for SUM and COUNT. Here is a simplified visual representation, but the actual estimator will have to take into account the possibility of the orange area going below zero.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/69Vvi2CHSW8Gew0TWHSndj/1489cfe1ff57df4e7e1ca3c31a8444a5/BLOG-2486_5.png" />
          </figure><p>In SQL, the estimators and confidence intervals look like this:</p>
            <pre><code>WITH sum(x * _sample_interval)                              AS t,
     sum(x * x * _sample_interval * (_sample_interval - 1)) AS vt,
     sum(_sample_interval)                                  AS c,
     sum(_sample_interval * (_sample_interval - 1))         AS vc,
     -- ClickHouse does not expose the erf⁻¹ function, so we precompute some magic numbers,
     -- (only for 95% confidence, will be different otherwise):
     --   1.959963984540054 = Φ⁻¹((1+0.950)/2) = √2 * erf⁻¹(0.950)
     --   2.241402727604945 = Φ⁻¹((1+0.975)/2) = √2 * erf⁻¹(0.975)
     1.959963984540054 * sqrt(vt) AS err950_t,
     1.959963984540054 * sqrt(vc) AS err950_c,
     2.241402727604945 * sqrt(vt) AS err975_t,
     2.241402727604945 * sqrt(vc) AS err975_c
SELECT t - err950_t AS lo_total,
       t            AS est_total,
       t + err950_t AS hi_total,
       c - err950_c AS lo_count,
       c            AS est_count,
       c + err950_c AS hi_count,
       (t - err975_t) / (c + err975_c) AS lo_average,
       t / c                           AS est_average,
       (t + err975_t) / (c - err975_c) AS hi_average
FROM ...</code></pre>
            <p>Construct a confidence interval for each timeslot on the timeseries, and you get a confidence band, clearly showing the accuracy of the analytics. The figure below shows an example of such a band in shading around the line.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4JEnnC6P4BhM8qB8J5yKqt/3635835967085f9b24f64a5731457ddc/BLOG-2486_6.png" />
          </figure>
    <div>
      <h3>Sampling is easy to screw up</h3>
      <a href="#sampling-is-easy-to-screw-up">
        
      </a>
    </div>
    <p>We started using confidence bands on our internal dashboards, and after a while noticed something scary: a systematic error! For one particular website the "total bytes served" estimate was higher than the true control value obtained from rollups, and the confidence bands were way off. See the figure below, where the true value (blue line) is outside the yellow confidence band at all times.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/CHCyKyXqPMj8DnMpBUf3N/772fb61f02b79c59417f66d9dc0b5d19/BLOG-2486_7.png" />
          </figure><p>We checked the stored data for corruption, it was fine. We checked the math in the queries, it was fine. It was only after reading through the source code for all of the systems responsible for sampling that we found a candidate for the root cause.</p><p>We used simple random sampling everywhere, basically "tossing a coin" for each event, but in Logreceiver sampling was done differently. Instead of sampling <i>randomly</i> it would perform <i>systematic sampling</i> by picking events at equal intervals starting from the first one in the batch.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4xUwjxdylG5ARlFlDtv1OC/76db68677b7ae072b0a065f59d82c6f2/BLOG-2486_8.png" />
          </figure><p>Why would that be a problem?</p>There are two reasons. The first is that we can no longer claim $\pi_{ij} = \pi_i \pi_j$, so the simplified variance estimator stops working and confidence intervals cannot be trusted. But even worse, the estimator for the total becomes biased. To understand why exactly, we wrote a short repro code in Python:
<br /><p></p>
            <pre><code>import itertools

def take_every(src, period):
    for i, x in enumerate(src):
    if i % period == 0:
        yield x

pattern = [10, 1, 1, 1, 1, 1]
sample_interval = 10 # bad if it has common factors with len(pattern)
true_mean = sum(pattern) / len(pattern)

orig = itertools.cycle(pattern)
sample_size = 10000
sample = itertools.islice(take_every(orig, sample_interval), sample_size)

sample_mean = sum(sample) / sample_size

print(f"{true_mean=} {sample_mean=}")</code></pre>
            <p>After playing with different values for <code><b>pattern</b></code> and <code><b>sample_interval</b></code> in the code above, we realized where the bias was coming from.</p><p>Imagine a person opening a huge generated HTML page with many small/cached resources, such as icons. The first response will be big, immediately followed by a burst of small responses. If the website is not visited that much, responses will tend to end up all together at the start of a batch in Logfwdr. Logreceiver does not cut batches, only concatenates them. The first response remains first, so it always gets picked and skews the estimate up.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2WZUzqCwr2A6WgX1T5UE8z/7a2e08b611fb64e64a61e3d5c792fe23/BLOG-2486_9.png" />
          </figure><p>We checked the hypothesis against the raw unsampled data that we happened to have because that particular website was also using one of the <a href="https://developers.cloudflare.com/logs/"><u>Logs</u></a> products. We took all events in a given time range, and grouped them by cutting at gaps of at least one minute. In each group, we ranked all events by time and looked at the variable of interest (response size in bytes), and put it on a scatter plot against the rank inside the group.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2IXtqGkRjV0xs3wvwx609A/81e67736cacbccdd839c2177769ee4fe/BLOG-2486_10.png" />
          </figure><p>A clear pattern! The first response is much more likely to be larger than average.</p><p>We fixed the issue by making Logreceiver shuffle the data before sampling. As we rolled out the fix, the estimation and the true value converged.</p>
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4TL1pKDLw7MA6yGMSCahJN/227cb22054e0e8fe65c7766aa6e4b541/BLOG-2486_11.png" />
          </figure><p>Now, after battle testing it for a while, we are confident the HT estimator is implemented properly and we are using the correct sampling process.</p>
    <div>
      <h3>Using Cloudflare's analytics APIs to query sampled data</h3>
      <a href="#using-cloudflares-analytics-apis-to-query-sampled-data">
        
      </a>
    </div>
    <p>We already power most of our analytics datasets with sampled data. For example, the <a href="https://developers.cloudflare.com/analytics/analytics-engine/"><u>Workers Analytics Engine</u></a> exposes the <a href="https://developers.cloudflare.com/analytics/analytics-engine/sql-api/#sampling"><u>sample interval</u></a> in SQL, allowing our customers to build their own dashboards with confidence bands. In the GraphQL API, all of the data nodes that have "<a href="https://developers.cloudflare.com/analytics/graphql-api/sampling/#adaptive-sampling"><u>Adaptive</u></a>" in their name are based on sampled data, and the sample interval is exposed as a field there as well, though it is not possible to build confidence intervals from that alone. We are working on exposing confidence intervals in the GraphQL API, and as an experiment have added them to the count and edgeResponseBytes (sum) fields on the httpRequestsAdaptiveGroups nodes. This is available under <code><b>confidence(level: X)</b></code>.</p><p>Here is a sample GraphQL query:</p>
            <pre><code>query HTTPRequestsWithConfidence(
  $accountTag: string
  $zoneTag: string
  $datetimeStart: string
  $datetimeEnd: string
) {
  viewer {
    zones(filter: { zoneTag: $zoneTag }) {
      httpRequestsAdaptiveGroups(
        filter: {
          datetime_geq: $datetimeStart
          datetime_leq: $datetimeEnd
      }
      limit: 100
    ) {
      confidence(level: 0.95) {
        level
        count {
          estimate
          lower
          upper
          sampleSize
        }
        sum {
          edgeResponseBytes {
            estimate
            lower
            upper
            sampleSize
          }
        }
      }
    }
  }
}
</code></pre>
            <p>The query above asks for the estimates and the 95% confidence intervals for <code><b>SUM(edgeResponseBytes)</b></code> and <code><b>COUNT</b></code>. The results will also show the sample size, which is good to know, as we rely on the <a href="https://en.wikipedia.org/wiki/Central_limit_theorem"><u>central limit theorem</u></a> to build the confidence intervals, thus small samples don't work very well.</p><p>Here is the response from this query:</p>
            <pre><code>{
  "data": {
    "viewer": {
      "zones": [
        {
          "httpRequestsAdaptiveGroups": [
            {
              "confidence": {
                "level": 0.95,
                "count": {
                  "estimate": 96947,
                  "lower": "96874.24",
                  "upper": "97019.76",
                  "sampleSize": 96294
                },
                "sum": {
                  "edgeResponseBytes": {
                    "estimate": 495797559,
                    "lower": "495262898.54",
                    "upper": "496332219.46",
                    "sampleSize": 96294
                  }
                }
              }
            }
          ]
        }
      ]
    }
  },
  "errors": null
}
</code></pre>
            <p>The response shows the estimated count is 96947, and we are 95% confident that the true count lies in the range 96874.24 to 97019.76. Similarly, the estimate and range for the sum of response bytes are provided.</p><p>The estimates are based on a sample size of 96294 rows, which is plenty of samples to calculate good confidence intervals.</p>
    <div>
      <h3>Conclusion</h3>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>We have discussed what kept our data pipeline scalable and resilient despite doubling in size every 1.5 years, how the math works, and how it is easy to mess up. We are constantly working on better ways to keep the data pipeline, and the products based on it, useful to our customers. If you are interested in doing things like that and want to help us build a better Internet, check out our <a href="http://www.cloudflare.com/careers"><u>careers page</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Bugs]]></category>
            <category><![CDATA[Analytics]]></category>
            <category><![CDATA[Data]]></category>
            <category><![CDATA[GraphQL]]></category>
            <category><![CDATA[SQL]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Deep Dive]]></category>
            <category><![CDATA[Sampling]]></category>
            <guid isPermaLink="false">64DSvKdN853gq5Bx3Cyfij</guid>
            <dc:creator>Constantin Pan</dc:creator>
            <dc:creator>Jim Hawkridge</dc:creator>
        </item>
        <item>
            <title><![CDATA[Improving platform resilience at Cloudflare through automation]]></title>
            <link>https://blog.cloudflare.com/improving-platform-resilience-at-cloudflare/</link>
            <pubDate>Wed, 09 Oct 2024 13:00:00 GMT</pubDate>
            <description><![CDATA[ We realized that we need a way to automatically heal our platform from an operations perspective, and designed and built a workflow orchestration platform to provide these self-healing capabilities   ]]></description>
            <content:encoded><![CDATA[ <p>Failure is an expected state in production systems, and no predictable failure of either software or hardware components should result in a negative experience for users. The exact failure mode may vary, but certain remediation steps must be taken after detection. A common example is when an error occurs on a server, rendering it unfit for production workloads, and requiring action to recover.</p><p>When operating at Cloudflare’s scale, it is important to ensure that our platform is able to recover from faults seamlessly. It can be tempting to rely on the expertise of world-class engineers to remediate these faults, but this would be manual, repetitive, unlikely to produce enduring value, and not scaling. In one word: toil; not a viable solution at our scale and rate of growth.</p><p>In this post we discuss how we built the foundations to enable a more scalable future, and what problems it has immediately allowed us to solve.</p>
    <div>
      <h2>Growing pains</h2>
      <a href="#growing-pains">
        
      </a>
    </div>
    <p>The Cloudflare <a href="https://en.wikipedia.org/wiki/Site_reliability_engineering"><u>Site Reliability Engineering (SRE)</u></a> team builds and manages the platform that helps product teams deliver our extensive suite of offerings to customers. One important component of this platform is the collection of servers that power critical products such as Durable Objects, Workers, and DDoS mitigation. We also build and maintain foundational software services that power our product offerings, such as configuration management, provisioning, and IP address allocation systems.</p><p>As part of tactical operations work, we are often required to respond to failures in any of these components to minimize impact to users. Impact can vary from lack of access to a specific product feature, to total unavailability. The level of response required is determined by the priority, which is usually a reflection of the severity of impact on users. Lower-priority failures are more common — a server may run too hot, or experience an unrecoverable hardware error. Higher-priority failures are rare and are typically resolved via a well-defined incident response process, requiring collaboration with multiple other teams.</p><p>The commonality of lower-priority failures makes it obvious when the response required, as defined in runbooks, is “toilsome”. To reduce this toil, we had previously implemented a plethora of solutions to automate runbook actions such as manually-invoked shell scripts, cron jobs, and ad-hoc software services. These had grown organically over time and provided solutions on a case-by-case basis, which led to duplication of work, tight coupling, and lack of context awareness across the solutions.</p><p>We also care about how long it takes to resolve any potential impact on users. A resolution process which involves the manual invocation of a script relies on human action, increasing the Mean-Time-To-Resolve (MTTR) and leaving room for human error. This risks increasing the amount of errors we serve to users and degrading trust.</p><p>These problems proved that we needed a way to automatically heal these platform components. This especially applies to our servers, for which failure can cause impact across multiple product offerings. While we have <a href="https://blog.cloudflare.com/unimog-cloudflares-edge-load-balancer"><u>mechanisms to automatically steer traffic away</u></a> from these degraded servers, in some rare cases the breakage is sudden enough to be visible.</p>
    <div>
      <h2>Solving the problem</h2>
      <a href="#solving-the-problem">
        
      </a>
    </div>
    <p>To provide a more reliable platform, we needed a new component that provides a common ground for remediation efforts. This would remove duplication of work, provide unified context-awareness and increase development speed, which ultimately saves hours of engineering time and effort.</p><p>A good solution would not allow only the SRE team to auto-remediate, it would empower the entire company. The key to adding self-healing capability was a generic interface for all teams to self-service and quickly remediate failures at various levels: machine, service, network, or dependencies.</p><p>A good way to think about auto-remediation is in terms of workflows. A workflow is a sequence of steps to get to a desired outcome. This is not dissimilar to a manual shell script which executes what a human would otherwise do via runbook instructions. Because of this logical fit with workflows and durable execution, we decided to adopt an open-source platform called <a href="https://github.com/temporalio/temporal"><u>Temporal</u></a>. </p><p>The concept of durable execution is useful to gracefully manage infrastructure failures such as network outages and transient failures in external service endpoints. This capability meant we only needed to build a way to schedule “workflow” tasks and have the code provide reliability guarantees by default, using Temporal. This allowed us to focus on building out the orchestration system to support the control and flow of workflow execution in our data centers. </p><p><a href="https://learn.temporal.io/getting_started/go/first_program_in_go/"><u>Temporal’s documentation</u></a> provides a good introduction to writing Temporal workflows.</p>
    <div>
      <h2>Building an Automatic Remediation System</h2>
      <a href="#building-an-automatic-remediation-system">
        
      </a>
    </div>
    <p>Below, we describe how our automatic remediation system works. It is essentially a way to schedule tasks across our global network with built-in reliability guarantees. With this system, teams can serve their customers more reliably. An unexpected failure mode can be recognized and immediately mitigated, while the root cause can be determined later via a more detailed analysis.</p>
    <div>
      <h3>Step one: we need a coordinator</h3>
      <a href="#step-one-we-need-a-coordinator">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/FOpkEE13QcgwHJ9vhcIZj/5b0c5328ee5326794329a4a07c5db065/Building_on_Temporal_process.png" />
          </figure><p>After our initial testing of Temporal, it was now possible to write workflows. But we needed a way to schedule workflow tasks from other internal services. The coordinator was built to serve this purpose, and became the primary mechanism for the authorisation and scheduling of workflows. </p><p>The most important roles of the coordinator are authorisation, workflow task routing, and safety constraints enforcement. Each consumer is authorized via <a href="https://www.cloudflare.com/learning/access-management/what-is-mutual-tls/"><u>mTLS authentication</u></a>, and the coordinator uses an ACL to determine whether to permit the execution of a workflow. An ACL configuration looks like the following example.</p>
            <pre><code>server_config {
    enable_tls = true
    [...]
    route_rule {
      name  = "global_get"
      method = "GET"
      route_patterns = ["/*"]
      uris = ["spiffe://example.com/worker-admin"]
    }
    route_rule {
      name = "global_post"
      method = "POST"
      route_patterns = ["/*"]
      uris = ["spiffe://example.com/worker-admin"]
      allow_public = true
    }
    route_rule {
      name = "public_access"
      method = "GET"
      route_patterns = ["/metrics"]
      uris = []
      allow_public = true
      skip_log_match = true
    }
}
</code></pre>
            <p>Each workflow specifies two key characteristics: where to run the tasks and the safety constraints, using an <a href="https://github.com/hashicorp/hcl"><u>HCL</u></a> configuration file. Example constraints could be whether to run on only a specific node type (such as a database), or if multiple parallel executions are allowed: if a task has been triggered too many times, that is a sign of a wider problem that might require human intervention. The coordinator uses the Temporal <a href="https://docs.temporal.io/visibility"><u>Visibility API</u></a> to determine the current state of the executions in the Temporal cluster.</p><p>An example of a configuration file is shown below:</p>
            <pre><code>task_queue_target = "&lt;target&gt;"

# The following entries will ensure that
# 1. This workflow is not run at the same time in a 15m window.
# 2. This workflow will not run more than once an hour.
# 3. This workflow will not run more than 3 times in one day.
#
constraint {
    kind = "concurency"
    value = "1"
    period = "15m"
}

constraint {
    kind = "maxExecution"
    value = "1"
    period = "1h"
}

constraint {
    kind = "maxExecution"
    value = "3"
    period = "24h"
    is_global = true
}
</code></pre>
            
    <div>
      <h3>Step two: Task Routing is amazing</h3>
      <a href="#step-two-task-routing-is-amazing">
        
      </a>
    </div>
    
          <figure>
          <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4wOIwKfkKzp7k46Z6tPuhW/f35667a65872cf7a90fc9c03f38a48d5/Task_Routing_is_amazing_process.png" />
          </figure><p>An unforeseen benefit of using a central Temporal cluster was the discovery of Task Routing. This feature allows us to schedule a Workflow/Activity on any server that has a running Temporal Worker, and further segment by the type of server, its location, etc. For this reason, we have three primary task queues — the general queue in which tasks can be executed by any worker in the datacenter, the node type queue in which tasks can only be executed by a specific node type in the datacenter, and the individual node queue where we target a specific node for task execution.</p><p>We rely on this heavily to ensure the speed and efficiency of automated remediation. Certain tasks can be run in datacenters with known low latency to an external resource, or a node type with better performance than others (due to differences in the underlying hardware). This reduces the amount of failure and latency we see overall in task executions. Sometimes we are also constrained by certain types of tasks that can only run on a certain node type, such as a database.</p><p>Task Routing also means that we can configure certain task queues to have a higher priority for execution, although this is not a feature we have needed so far. A drawback of task routing is that every Workflow/Activity needs to be registered to the target task queue, which is a common gotcha. Thankfully, it is possible to catch this failure condition with proper testing.</p>
    <div>
      <h3>Step three: when/how to self-heal?</h3>
      <a href="#step-three-when-how-to-self-heal">
        
      </a>
    </div>
    <p>None of this would be relevant if we didn’t put it to good use. A primary design goal for the platform was to ensure we had easy, quick ways to trigger workflows on the most important failure conditions. The next step was to determine what the best sources to trigger the actions were. The answer to this was simple: we could trigger workflows from anywhere as long as they are properly authorized and detect the failure conditions accurately.</p><p>Example triggers are an alerting system, a log tailer, a health check daemon, or an authorized engineer via a chatbot. Such flexibility allows a high level of reuse, and permits to invest more in workflow quality and reliability.</p><p>As part of the solution, we built a daemon that is able to poll a signal source for any unwanted condition and trigger a configured workflow. We have initially found <a href="https://blog.cloudflare.com/how-cloudflare-runs-prometheus-at-scale"><u>Prometheus</u></a> useful as a source because it contains both service-level and hardware/system-level metrics. We are also exploring more event-based trigger mechanisms, which could eliminate the need to use precious system resources to poll for metrics.</p><p>We already had internal services that are able to detect widespread failure conditions for our customers, but were only able to page a human. With the adoption of auto-remediation, these systems are now able to react automatically. This ability to create an automatic feedback loop with our customers is the cornerstone of these self-healing capabilities, and we continue to work on stronger signals, faster reaction times, and better prevention of future occurrences.</p><p>The most exciting part, however, is the future possibility. Every customer cares about any negative impact from Cloudflare. With this platform we can onboard several services (especially those that are foundational for the critical path) and ensure we react quickly to any failure conditions, even before there is any visible impact.</p>
    <div>
      <h3>Step four: packaging and deployment</h3>
      <a href="#step-four-packaging-and-deployment">
        
      </a>
    </div>
    <p>The whole system is written in <a href="https://go.dev/"><u>golang</u></a>, and a single binary can implement each role. We distribute it as an apt package or a container for maximum ease of deployment.</p><p>We deploy a Temporal-based worker to every server we intend to run tasks on, and a daemon in datacenters where we intend to automatically trigger workflows based on the local conditions. The coordinator is more nuanced since we rely on task routing and can trigger from a central coordinator, but we have also found value in running coordinators locally in the datacenters. This is especially useful in datacenters with less capacity or degraded performance, removing the need for a round-trip to schedule the workflows.</p>
    <div>
      <h3>Step five: test, test, test</h3>
      <a href="#step-five-test-test-test">
        
      </a>
    </div>
    <p>Temporal provides native mechanisms to test an entire workflow, via a <a href="https://docs.temporal.io/develop/go/testing-suite"><u>comprehensive test suite</u></a> that supports end-to-end, integration, and unit testing, which we used extensively to prevent regressions while developing. We also ensured proper test coverage for all the critical platform components, especially the coordinator.</p><p>Despite the ease of written tests, we quickly discovered that they were not enough. After writing workflows, engineers need an environment as close as possible to the target conditions. This is why we configured our staging environments to support quick and efficient testing. These environments receive the latest changes and point to a different (staging) Temporal cluster, which enables experimentation and easy validation of changes.</p><p>After a workflow is validated in the staging environment, we can then do a full release to production. It seems obvious, but catching simple configuration errors before releasing has saved us many hours in development/change-related-task time.</p>
    <div>
      <h2>Deploying to production</h2>
      <a href="#deploying-to-production">
        
      </a>
    </div>
    <p>As you can guess from the title of this post, we put this in production to automatically react to server-specific errors and unrecoverable failures. To this end, we have a set of services that are able to detect single-server failure conditions based on analyzed traffic data. After deployment, we have successfully mitigated potential impact by taking any errant single sources of failure out of production.</p><p>We have also created a set of workflows to reduce internal toil and improve efficiency. These workflows can automatically test pull requests on target machines, wipe and reset servers after experiments are concluded, and take away manual processes that cost many hours in toil.</p><p>Building a system that is maintained by several SRE teams has allowed us to iterate faster, and rapidly tackle long-standing problems. We have set ambitious goals regarding toil elimination and are on course to achieve them, which will allow us to scale faster by eliminating the human bottleneck.</p>
    <div>
      <h2>Looking to the future</h2>
      <a href="#looking-to-the-future">
        
      </a>
    </div>
    <p>Our immediate plans are to leverage this system to provide a more reliable platform for our customers and drastically reduce operational toil, freeing up engineering resources to tackle larger-scale problems. We also intend to leverage more Temporal features such as <a href="https://docs.temporal.io/develop/go/versioning"><u>Workflow Versioning</u></a>, which will simplify the process of making changes to workflows by ensuring that triggered workflows run expected versions. </p><p> We are also interested in how others are solving problems using durable execution platforms such as Temporal, and general strategies to eliminate toil. If you would like to discuss this further, feel free to reach out on the <a href="https://community.cloudflare.com"><u>Cloudflare Community</u></a> and start a conversation!</p><p>If you’re interested in contributing to projects that help build a better Internet, <a href="https://www.cloudflare.com/en-gb/careers/jobs/?department=Engineering&amp;location=default"><u>our engineering teams are hiring</u></a>.</p> ]]></content:encoded>
            <category><![CDATA[Edge]]></category>
            <category><![CDATA[Engineering]]></category>
            <category><![CDATA[Serverless]]></category>
            <category><![CDATA[Developer Platform]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Reliability]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">2i9tHkPAfy7GxYAioGM100</guid>
            <dc:creator>Opeyemi Onikute</dc:creator>
        </item>
        <item>
            <title><![CDATA[Intelligent, automatic restarts for unhealthy Kafka consumers]]></title>
            <link>https://blog.cloudflare.com/intelligent-automatic-restarts-for-unhealthy-kafka-consumers/</link>
            <pubDate>Tue, 24 Jan 2023 14:00:00 GMT</pubDate>
            <description><![CDATA[ At Cloudflare, we take steps to ensure we are resilient against failure at all levels of our infrastructure. This includes Kafka, which we use for critical workflows such as sending time-sensitive emails and alerts. ]]></description>
            <content:encoded><![CDATA[ <p></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7eWbGD5pEX9bKf2p58iqOw/b55ba4bfd305da7ed38cf66fe770585c/image3-8-2.png" />
            
            </figure><p>At Cloudflare, we take steps to ensure we are resilient against failure at all levels of our infrastructure. This includes Kafka, which we use for critical workflows such as sending time-sensitive emails and alerts.</p><p>We learned a lot about keeping our applications that leverage Kafka healthy, so they can always be operational. Application health checks are notoriously hard to implement: What determines an application as healthy? How can we keep services operational at all times?</p><p>These can be implemented in many ways. We’ll talk about an approach that allows us to considerably reduce incidents with unhealthy applications while requiring less manual intervention.</p>
    <div>
      <h3>Kafka at Cloudflare</h3>
      <a href="#kafka-at-cloudflare">
        
      </a>
    </div>
    <p><a href="/using-apache-kafka-to-process-1-trillion-messages/">Cloudflare is a big adopter of Kafka</a>. We use Kafka as a way to decouple services due to its asynchronous nature and reliability. It allows different teams to work effectively without creating dependencies on one another. You can also read more about how other teams at Cloudflare use Kafka in <a href="/http-analytics-for-6m-requests-per-second-using-clickhouse/">this</a> post.</p><p>Kafka is used to send and receive messages. Messages represent some kind of event like a credit card payment or details of a new user created in your platform. These messages can be represented in multiple ways: JSON, Protobuf, Avro and so on.</p><p>Kafka organises messages in topics. A topic is an ordered log of events in which each message is marked with a progressive offset. When an event is written by an external system, that is appended to the end of that topic. These events are not deleted from the topic by default (retention can be applied).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2KUYbqCCL74YZVU8NXOThl/4ec5024168993a2300add7221016af0d/1-4.png" />
            
            </figure><p>Topics are stored as log files on disk, which are finite in size. Partitions are a systematic way of breaking the one topic log file into many logs, each of which can be hosted on separate servers–enabling to scale topics.</p><p>Topics are managed by brokers–nodes in a Kafka cluster. These are responsible for writing new events to partitions, serving reads and replicating partitions among themselves.</p><p>Messages can be consumed by individual consumers or co-ordinated groups of consumers, known as consumer groups.</p><p>Consumers use a unique id (consumer id) that allows them to be identified by the broker as an application which is consuming from a specific topic.</p><p>Each topic can be read by an infinite number of different consumers, as long as they use a different id. Each consumer can replay the same messages as many times as they want.</p><p>When a consumer starts consuming from a topic, it will process all messages, starting from a selected offset, from each partition. With a consumer group, the partitions are divided amongst each consumer in the group. This division is determined by the consumer group leader. This leader will receive information about the other consumers in the group and will decide which consumers will receive messages from which partitions (partition strategy).</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6Qe2Qe5nQ5gcHyhV0zpTWw/5182eea9de66164a36a28e92270fdb3f/2-3.png" />
            
            </figure><p>The offset of a consumer’s commit can demonstrate whether the consumer is working as expected. Committing a processed offset is the way a consumer and its consumer group report to the broker that they have processed a particular message.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/29Y9mQiHkvGKUzc3RGF1sk/09d2987f53eef026c164e6c49cacc95c/unnamed-6.png" />
            
            </figure><p>A standard measurement of whether a consumer is processing fast enough is lag. We use this to measure how far behind the newest message we are. This tracks time elapsed between messages being written to and read from a topic. When a service is lagging behind, it means that the consumption is at a slower rate than new messages being produced.</p><p>Due to Cloudflare’s scale, message rates typically end up being very large and a lot of requests are time-sensitive so monitoring this is vital.</p><p>At Cloudflare, our applications using Kafka are deployed as microservices on Kubernetes.</p>
    <div>
      <h3>Health checks for Kubernetes apps</h3>
      <a href="#health-checks-for-kubernetes-apps">
        
      </a>
    </div>
    <p>Kubernetes uses <a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/">probes</a> to understand if a service is healthy and is ready to receive traffic or to run. When a liveness probe fails and the bounds for retrying are exceeded, Kubernetes restarts the services.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4FagbTygES9L7dmEQ6ratD/0a6f0d4c5ac117b723ad726a12d3936a/4-3.png" />
            
            </figure><p>When a readiness probe fails and the bounds for retrying are exceeded, it stops sending HTTP traffic to the targeted pods. In the case of Kafka applications this is not relevant as they don’t run an http server. For this reason, we’ll cover only liveness checks.</p><p>A classic Kafka liveness check done on a consumer checks the status of the connection with the broker. It’s often best practice to keep these checks simple and perform some basic operations - in this case, something like listing topics. If, for any reason, this check fails consistently, for instance the broker returns a TLS error, Kubernetes terminates the service and starts a new pod of the same service, therefore forcing a new connection. Simple Kafka liveness checks do a good job of understanding when the connection with the broker is unhealthy.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6gNWb3Rit0MmTutsurm7sf/70355c422fab7ebce7d59d8c2c682d6d/5-2.png" />
            
            </figure>
    <div>
      <h3>Problems with Kafka health checks</h3>
      <a href="#problems-with-kafka-health-checks">
        
      </a>
    </div>
    <p>Due to Cloudflare’s scale, a lot of our Kafka topics are divided into multiple partitions (in some cases this can be hundreds!) and in many cases the replica count of our consuming service doesn’t necessarily match the number of partitions on the Kafka topic. This can mean that in a lot of scenarios this simple approach to health checking is not quite enough!</p><p>Microservices that consume from Kafka topics are healthy if they are consuming and committing offsets at regular intervals when messages are being published to a topic. When such services are not committing offsets as expected, it means that the consumer is in a bad state, and it will start accumulating lag. An approach we often take is to manually terminate and restart the service in Kubernetes, this will cause a reconnection and rebalance.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/N4YalYdgNRxYJK7PVAlzY/26b55fc38c53855a6c28c71b25cdac02/lag.png" />
            
            </figure><p>When a consumer joins or leaves a consumer group, a rebalance is triggered and the consumer group leader must re-assign which consumers will read from which partitions.</p><p>When a rebalance happens, each consumer is notified to stop consuming. Some consumers might get their assigned partitions taken away and re-assigned to another consumer. We noticed when this happened within our library implementation; if the consumer doesn’t acknowledge this command, it will wait indefinitely for new messages to be consumed from a partition that it’s no longer assigned to, ultimately leading to a deadlock. Usually a manual restart of the faulty client-side app is needed to resume processing.</p>
    <div>
      <h3>Intelligent health checks</h3>
      <a href="#intelligent-health-checks">
        
      </a>
    </div>
    <p>As we were seeing consumers reporting as “healthy” but sitting idle, it occurred to us that maybe we were focusing on the wrong thing in our health checks. Just because the service is connected to the Kafka broker and can read from the topic, it does not mean the consumer is actively processing messages.</p><p>Therefore, we realised we should be focused on message ingestion, using the offset values to ensure that forward progress was being made.</p>
    <div>
      <h4>The PagerDuty approach</h4>
      <a href="#the-pagerduty-approach">
        
      </a>
    </div>
    <p>PagerDuty wrote an excellent <a href="https://www.pagerduty.com/eng/kafka-health-checks/">blog</a> on this topic which we used as inspiration when coming up with our approach.</p><p>Their approach used the current (latest) offset and the committed offset values. The current offset signifies the last message that was sent to the topic, while the committed offset is the last message that was processed by the consumer.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2fwem7NtBnO6M1RMhrezr8/af4cbbd7a63d3145f5c7fe9f405bd04d/pasted-image-0-4.png" />
            
            </figure><p>Checking the consumer is moving forwards, by ensuring that the latest offset was changing (receiving new messages) and the committed offsets were changing as well (processing the new messages).</p><p>Therefore, the solution we came up with:</p><ul><li><p>If we cannot read the current offset, fail liveness probe.</p></li><li><p>If we cannot read the committed offset, fail liveness probe.</p></li><li><p>If the committed offset == the current offset, pass liveness probe.</p></li><li><p>If the value for the committed offset has not changed since the last run of the health check, fail liveness probe.</p></li></ul>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5r76n2Iew7pSqA8vYNZzIy/c9e0f6a113a34d0c36a216c054e4d840/pasted-image-0--1--3.png" />
            
            </figure><p>To measure if the committed offset is changing, we need to store the value of the previous run, we do this using an in-memory map where partition number is the key. This means each instance of our service only has a view of the partitions it is currently consuming from and will run the health check for each.</p>
    <div>
      <h4>Problems</h4>
      <a href="#problems">
        
      </a>
    </div>
    <p>When we first rolled out our smart health checks we started to notice cascading failures some time after release. After initial investigations we realised this was happening when a rebalance happens. It would initially affect one replica then quickly result in the others reporting as unhealthy.</p><p>What we observed was due to us storing the previous value of the committed offset in-memory, when a rebalance happens the service may get re-assigned a different partition. When this happened it meant our service was incorrectly assuming that the committed offset for that partition had not changed (as this specific replica was no longer updating the latest value), therefore it would start to report the service as unhealthy. The failing liveness probe would then cause it to restart which would in-turn trigger another rebalancing in Kafka causing other replicas to face the same issue.</p>
    <div>
      <h4>Solution</h4>
      <a href="#solution">
        
      </a>
    </div>
    <p>To fix this issue we needed to ensure that each replica only kept track of the offsets for the partitions it was consuming from at that moment. Luckily, the Shopify Sarama library, which we use internally, has functionality to observe when a rebalancing happens. This meant we could use it to rebuild the in-memory map of offsets so that it would only include the relevant partition values.</p><p>This is handled by receiving the signal from the session context channel:</p>
            <pre><code>for {
  select {
  case message, ok := &lt;-claim.Messages(): // &lt;-- Message received

     // Store latest received offset in-memory
     offsetMap[message.Partition] = message.Offset


     // Handle message
     handleMessage(ctx, message)


     // Commit message offset
     session.MarkMessage(message, "")


  case &lt;-session.Context().Done(): // &lt;-- Rebalance happened

     // Remove rebalanced partition from in-memory map
     delete(offsetMap, claim.Partition())
  }
}</code></pre>
            <p>Verifying this solution was straightforward, we just needed to trigger a rebalance. To test this worked in all possible scenarios we spun up a single replica of a service consuming from multiple partitions, then proceeded to scale up the number of replicas until it matched the partition count, then scaled back down to a single replica. By doing this we verified that the health checks could safely handle new partitions being assigned as well as partitions being taken away.</p>
    <div>
      <h3>Takeaways</h3>
      <a href="#takeaways">
        
      </a>
    </div>
    <p>Probes in Kubernetes are very easy to set up and can be a powerful tool to ensure your application is running as expected. Well implemented probes can often be the difference between engineers being called out to fix trivial issues (sometimes outside of working hours) and a service which is self-healing.</p><p>However, without proper thought, “dumb” health checks can also lead to a false sense of security that a service is running as expected even when it’s not. One thing we have learnt from this was to think more about the specific behaviour of the service and decide what being unhealthy means in each instance, instead of just ensuring that dependent services are connected.</p> ]]></content:encoded>
            <category><![CDATA[Kafka]]></category>
            <category><![CDATA[Observability]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Kubernetes]]></category>
            <guid isPermaLink="false">7s1ijlG7zMlxJPI6Hcs3zl</guid>
            <dc:creator>Chris Shepherd</dc:creator>
            <dc:creator>Andrea Medda</dc:creator>
        </item>
        <item>
            <title><![CDATA[Production ready eBPF, or how we fixed the BSD socket API]]></title>
            <link>https://blog.cloudflare.com/tubular-fixing-the-socket-api-with-ebpf/</link>
            <pubDate>Thu, 17 Feb 2022 17:02:54 GMT</pubDate>
            <description><![CDATA[ We are open sourcing the production tooling we’ve built for the sk_lookup hook we contributed to the Linux kernel, called tubular ]]></description>
            <content:encoded><![CDATA[ 
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3qt80mUTCxJp6nLkenADAL/29eb329be3097752997f3ac4b9a00f25/tubular-1.png" />
            
            </figure><p>As we develop new products, we often push our operating system - Linux - beyond what is commonly possible. A common theme has been relying on <a href="https://ebpf.io/what-is-ebpf/">eBPF</a> to build technology that would otherwise have required modifying the kernel. For example, we’ve built <a href="/l4drop-xdp-ebpf-based-ddos-mitigations/">DDoS mitigation</a> and a <a href="/unimog-cloudflares-edge-load-balancer/">load balancer</a> and use it to <a href="/introducing-ebpf_exporter/">monitor our fleet of servers</a>.</p><p>This software usually consists of a small-ish eBPF program written in C, executed in the context of the kernel, and a larger user space component that loads the eBPF into the kernel and manages its lifecycle. We’ve found that the ratio of eBPF code to userspace code differs by an order of magnitude or more. We want to shed some light on the issues that a developer has to tackle when dealing with eBPF and present our solutions for building rock-solid production ready applications which contain eBPF.</p><p>For this purpose we are open sourcing the production tooling we’ve built for the <a href="https://www.kernel.org/doc/html/latest/bpf/prog_sk_lookup.html">sk_lookup hook</a> we contributed to the Linux kernel, called <b>tubular</b>. It exists because <a href="/its-crowded-in-here/">we’ve outgrown the BSD sockets API</a>. To deliver some products we need features that are just not possible using the standard API.</p><ul><li><p>Our services are available on millions of IPs.</p></li><li><p>Multiple services using the same port on different addresses have to coexist, e.g. <a href="https://1.1.1.1/">1.1.1.1</a> resolver and our authoritative DNS.</p></li><li><p>Our Spectrum product <a href="/how-we-built-spectrum/">needs to listen on all 2^16 ports</a>.</p></li></ul><p>The source code for tubular is at <a href="https://github.com/cloudflare/tubular">https://github.com/cloudflare/tubular</a>, and it allows you to do all the things mentioned above. Maybe the most interesting feature is that you can change the addresses of a service on the fly:</p><div></div>
<p></p>
    <div>
      <h2>How tubular works</h2>
      <a href="#how-tubular-works">
        
      </a>
    </div>
    <p><code>tubular</code> sits at a critical point in the Cloudflare stack, since it has to inspect every connection terminated by a server and decide which application should receive it.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6ZFfhU9ui5dR4KpbOcofqr/c61fde7a87d189167a3b72ca90b61e20/unnamed.png" />
            
            </figure><p>Failure to do so will drop or misdirect connections hundreds of times per second. So it has to be incredibly robust during day to day operations. We had the following goals for tubular:</p><ul><li><p><b>Releases must be unattended and happen online.</b> tubular runs on thousands of machines, so we can’t babysit the process or take servers out of production.</p></li><li><p><b>Releases must fail safely.</b> A failure in the process must leave the previous version of tubular running, otherwise we may drop connections.</p></li><li><p><b>Reduce the impact of (userspace) crashes.</b> When the inevitable bug comes along we want to minimise the blast radius.</p></li></ul><p>In the past we had built a proof-of-concept control plane for sk_lookup called <a href="https://github.com/majek/inet-tool">inet-tool</a>, which proved that we could get away without a persistent service managing the eBPF. Similarly, tubular has <code>tubectl</code>: short-lived invocations make the necessary changes and persisting state is handled by the kernel in the form of <a href="https://www.kernel.org/doc/html/latest/bpf/maps.html">eBPF maps</a>. Following this design gave us crash resiliency by default, but left us with the task of mapping the user interface we wanted to the tools available in the eBPF ecosystem.</p>
    <div>
      <h2>The tubular user interface</h2>
      <a href="#the-tubular-user-interface">
        
      </a>
    </div>
    <p>tubular consists of a BPF program that attaches to the sk_lookup hook in the kernel and userspace Go code which manages the BPF program. The <code>tubectl</code> command wraps both in a way that is easy to distribute.</p><p><code>tubectl</code> manages two kinds of objects: bindings and sockets. A binding encodes a rule against which an incoming packet is matched. A socket is a reference to a TCP or UDP socket that can accept new connections or packets.</p><p>Bindings and sockets are "glued" together via arbitrary strings called labels. Conceptually, a binding assigns a label to some traffic. The label is then used to find the correct socket.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3G1ZM7iKvkGurKMBYqonW5/f6612068b8fb404a8cc0af1d02108c43/unnamed--2-.png" />
            
            </figure>
    <div>
      <h3>Adding bindings</h3>
      <a href="#adding-bindings">
        
      </a>
    </div>
    <p>To create a binding that steers port 80 (aka HTTP) traffic destined for 127.0.0.1 to the label “foo” we use <code>tubectl bind</code>:</p>
            <pre><code>$ sudo tubectl bind "foo" tcp 127.0.0.1 80</code></pre>
            <p>Due to the power of sk_lookup we can have much more powerful constructs than the BSD API. For example, we can redirect connections to all IPs in 127.0.0.0/24 to a single socket:</p>
            <pre><code>$ sudo tubectl bind "bar" tcp 127.0.0.0/24 80</code></pre>
            <p>A side effect of this power is that it's possible to create bindings that "overlap":</p>
            <pre><code>1: tcp 127.0.0.1/32 80 -&gt; "foo"
2: tcp 127.0.0.0/24 80 -&gt; "bar"</code></pre>
            <p>The first binding says that HTTP traffic to localhost should go to “foo”, while the second asserts that HTTP traffic in the localhost subnet should go to “bar”. This creates a contradiction, which binding should we choose? tubular resolves this by defining precedence rules for bindings:</p><ol><li><p>A prefix with a longer mask is more specific, e.g. 127.0.0.1/32 wins over 127.0.0.0/24.</p></li><li><p>A port is more specific than the port wildcard, e.g. port 80 wins over "all ports" (0).</p></li></ol><p>Applying this to our example, HTTP traffic to all IPs in 127.0.0.0/24 will be directed to bar, except for 127.0.0.1 which goes to foo.</p>
    <div>
      <h3>Getting ahold of sockets</h3>
      <a href="#getting-ahold-of-sockets">
        
      </a>
    </div>
    <p><code>sk_lookup</code> needs a reference to a TCP or a UDP socket to redirect traffic to it. However, a socket is usually accessible only by the process which created it with the socket syscall. For example, an HTTP server creates a TCP listening socket bound to port 80. How can we gain access to the listening socket?</p><p>A fairly well known solution is to make processes cooperate by passing socket file descriptors via <a href="/know-your-scm_rights/">SCM_RIGHTS</a> messages to a tubular daemon. That daemon can then take the necessary steps to hook up the socket with <code>sk_lookup</code>. This approach has several drawbacks:</p><ol><li><p>Requires modifying processes to send SCM_RIGHTS</p></li><li><p>Requires a tubular daemon, which may crash</p></li></ol><p>There is another way of getting at sockets by using systemd, provided <a href="https://www.freedesktop.org/software/systemd/man/systemd.socket.html">socket activation</a> is used. It works by creating an additional service unit with the correct <a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html#Sockets=">Sockets</a> setting. In other words: we can leverage systemd oneshot action executed on creation of a systemd socket service, registering the socket into tubular. For example:</p>
            <pre><code>[Unit]
Requisite=foo.socket

[Service]
Type=oneshot
Sockets=foo.socket
ExecStart=tubectl register "foo"</code></pre>
            <p>Since we can rely on systemd to execute <code>tubectl</code> at the correct times we don't need a daemon of any kind. However, the reality is that a lot of popular software doesn't use systemd socket activation. Dealing with systemd sockets is complicated and doesn't invite experimentation. Which brings us to the final trick: <a href="https://www.man7.org/linux/man-pages/man2/pidfd_getfd.2.html">pidfd_getfd</a>:</p><blockquote><p>The <code>pidfd_getfd()</code> system call allocates a new file descriptor in the calling process. This new file descriptor is a duplicate of an existing file descriptor, targetfd, in the process referred to by the PID file descriptor pidfd.</p></blockquote><p>We can use it to iterate all file descriptors of a foreign process, and pick the socket we are interested in. To return to our example, we can use the following command to find the TCP socket bound to 127.0.0.1 port 8080 in the httpd process and register it under the "foo" label:</p>
            <pre><code>$ sudo tubectl register-pid "foo" $(pidof httpd) tcp 127.0.0.1 8080</code></pre>
            <p>It's easy to wire this up using systemd's <a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html#ExecStartPre=">ExecStartPost</a> if the need arises.</p>
            <pre><code>[Service]
Type=forking # or notify
ExecStart=/path/to/some/command
ExecStartPost=tubectl register-pid $MAINPID foo tcp 127.0.0.1 8080</code></pre>
            
    <div>
      <h2>Storing state in eBPF maps</h2>
      <a href="#storing-state-in-ebpf-maps">
        
      </a>
    </div>
    <p>As mentioned previously, tubular relies on the kernel to store state, using <a href="https://prototype-kernel.readthedocs.io/en/latest/bpf/ebpf_maps.html">BPF key / value data structures also known as maps</a>. Using the <a href="https://www.kernel.org/doc/html/latest/userspace-api/ebpf/syscall.html">BPF_OBJ_PIN syscall</a> we can persist them in /sys/fs/bpf:</p>
            <pre><code>/sys/fs/bpf/4026532024_dispatcher
├── bindings
├── destination_metrics
├── destinations
├── sockets
└── ...</code></pre>
            <p>The way the state is structured differs from how the command line interface presents it to users. Labels like “foo” are convenient for humans, but they are of variable length. Dealing with variable length data in BPF is cumbersome and slow, so the BPF program never references labels at all. Instead, the user space code allocates numeric IDs, which are then used in the BPF. Each ID represents a (<code>label</code>, <code>domain</code>, <code>protocol</code>) tuple, internally called <code>destination</code>.</p><p>For example, adding a binding for "foo" <code>tcp 127.0.0.1</code> ... allocates an ID for ("<code>foo</code>", <code>AF_INET</code>, <code>TCP</code>). Including domain and protocol in the destination allows simpler data structures in the BPF. Each allocation also tracks how many bindings reference a destination so that we can recycle unused IDs. This data is persisted into the destinations hash table, which is keyed by (Label, Domain, Protocol) and contains (ID, Count). Metrics for each destination are tracked in destination_metrics in the form of per-CPU counters.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5JI7BzZmFdOS5DO6n2cpjh/3bf1a320954e9de2e4b60e64e0a3b375/unnamed--1--5.png" />
            
            </figure><p><code>bindings</code> is a <a href="https://en.wikipedia.org/wiki/Trie">longest prefix match (LPM) trie</a> which stores a mapping from (<code>protocol</code>, <code>port</code>, <code>prefix</code>) to (<code>ID</code>, <code>prefix length</code>). The ID is used as a key to the sockets map which contains pointers to kernel socket structures. IDs are allocated in a way that makes them suitable as an array index, which allows using the simpler BPF sockmap (an array) instead of a socket hash table. The prefix length is duplicated in the value to work around shortcomings in the BPF API.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4FJXwiooeaLRbRriCrETia/656cc5c0f78ca393627335cec1064755/unnamed--3-.png" />
            
            </figure>
    <div>
      <h2>Encoding the precedence of bindings</h2>
      <a href="#encoding-the-precedence-of-bindings">
        
      </a>
    </div>
    <p>As discussed, bindings have a precedence associated with them. To repeat the earlier example:</p>
            <pre><code>1: tcp 127.0.0.1/32 80 -&gt; "foo"
2: tcp 127.0.0.0/24 80 -&gt; "bar"</code></pre>
            <p>The first binding should be matched before the second one. We need to encode this in the BPF somehow. One idea is to generate some code that executes the bindings in order of specificity, a technique we’ve used to great effect in <a href="/l4drop-xdp-ebpf-based-ddos-mitigations/">l4drop</a>:</p>
            <pre><code>1: if (mask(ip, 32) == 127.0.0.1) return "foo"
2: if (mask(ip, 24) == 127.0.0.0) return "bar"
...</code></pre>
            <p>This has the downside that the program gets longer the more bindings are added, which slows down execution. It's also difficult to introspect and debug such long programs. Instead, we use a specialised BPF longest prefix match (LPM) map to do the hard work. This allows inspecting the contents from user space to figure out which bindings are active, which is very difficult if we had compiled bindings into BPF. The LPM map uses a trie behind the scenes, so <a href="https://en.wikipedia.org/wiki/Trie#Searching">lookup has complexity proportional to the length of the key</a> instead of linear complexity for the “naive” solution.</p><p>However, using a map requires a trick for encoding the precedence of bindings into a key that we can look up. Here is a simplified version of this encoding, which ignores IPv6 and uses labels instead of IDs. To insert the binding <code>tcp 127.0.0.0/24 80</code> into a trie we first convert the IP address into a number.</p>
            <pre><code>127.0.0.0    = 0x7f 00 00 00</code></pre>
            <p>Since we're only interested in the first 24 bits of the address we, can write the whole prefix as</p>
            <pre><code>127.0.0.0/24 = 0x7f 00 00 ??</code></pre>
            <p>where “?” means that the value is not specified. We choose the number 0x01 to represent TCP and prepend it and the port number (80 decimal is 0x50 hex) to create the full key:</p>
            <pre><code>tcp 127.0.0.0/24 80 = 0x01 50 7f 00 00 ??</code></pre>
            <p>Converting <code>tcp 127.0.0.1/32 80</code> happens in exactly the same way. Once the converted values are inserted into the trie, the LPM trie conceptually contains the following keys and values.</p>
            <pre><code>LPM trie:
        0x01 50 7f 00 00 ?? = "bar"
        0x01 50 7f 00 00 01 = "foo"</code></pre>
            <p>To find the binding for a TCP packet destined for 127.0.0.1:80, we again encode a key and perform a lookup.</p>
            <pre><code>input:  0x01 50 7f 00 00 01   TCP packet to 127.0.0.1:80
---------------------------
LPM trie:
        0x01 50 7f 00 00 ?? = "bar"
           y  y  y  y  y
        0x01 50 7f 00 00 01 = "foo"
           y  y  y  y  y  y
---------------------------
result: "foo"

y = byte matches</code></pre>
            <p>The trie returns “foo” since its key shares the longest prefix with the input. Note that we stop comparing keys once we reach unspecified “?” bytes, but conceptually “bar” is still a valid result. The distinction becomes clear when looking up the binding for a TCP packet to 127.0.0.255:80.</p>
            <pre><code>input:  0x01 50 7f 00 00 ff   TCP packet to 127.0.0.255:80
---------------------------
LPM trie:
        0x01 50 7f 00 00 ?? = "bar"
           y  y  y  y  y
        0x01 50 7f 00 00 01 = "foo"
           y  y  y  y  y  n
---------------------------
result: "bar"

n = byte doesn't match</code></pre>
            <p>In this case "foo" is discarded since the last byte doesn't match the input. However, "bar" is returned since its last byte is unspecified and therefore considered to be a valid match.</p>
    <div>
      <h2>Observability with minimal privileges</h2>
      <a href="#observability-with-minimal-privileges">
        
      </a>
    </div>
    <p>Linux has the powerful ss tool (part of iproute2) available to inspect socket state:</p>
            <pre><code>$ ss -tl src 127.0.0.1
State      Recv-Q      Send-Q           Local Address:Port           Peer Address:Port
LISTEN     0           128                  127.0.0.1:ipp                 0.0.0.0:*</code></pre>
            <p>With tubular in the picture this output is not accurate anymore. <code>tubectl</code> bindings makes up for this shortcoming:</p>
            <pre><code>$ sudo tubectl bindings tcp 127.0.0.1
Bindings:
 protocol       prefix port label
      tcp 127.0.0.1/32   80   foo</code></pre>
            <p>Running this command requires super-user privileges, despite in theory being safe for any user to run. While this is acceptable for casual inspection by a human operator, it's a dealbreaker for observability via pull-based monitoring systems like Prometheus. The usual approach is to expose metrics via an HTTP server, which would have to run with elevated privileges and be accessible to the Prometheus server somehow. Instead, BPF gives us the tools to enable read-only access to tubular state with minimal privileges.</p><p>The key is to carefully set file ownership and mode for state in /sys/fs/bpf. Creating and opening files in /sys/fs/bpf uses <a href="https://www.kernel.org/doc/html/latest/userspace-api/ebpf/syscall.html#bpf-subcommand-reference">BPF_OBJ_PIN and BPF_OBJ_GET</a>. Calling BPF_OBJ_GET with BPF_F_RDONLY is roughly equivalent to open(O_RDONLY) and allows accessing state in a read-only fashion, provided the file permissions are correct. tubular gives the owner full access but restricts read-only access to the group:</p>
            <pre><code>$ sudo ls -l /sys/fs/bpf/4026532024_dispatcher | head -n 3
total 0
-rw-r----- 1 root root 0 Feb  2 13:19 bindings
-rw-r----- 1 root root 0 Feb  2 13:19 destination_metrics</code></pre>
            <p>It's easy to choose which user and group should own state when loading tubular:</p>
            <pre><code>$ sudo -u root -g tubular tubectl load
created dispatcher in /sys/fs/bpf/4026532024_dispatcher
loaded dispatcher into /proc/self/ns/net
$ sudo ls -l /sys/fs/bpf/4026532024_dispatcher | head -n 3
total 0
-rw-r----- 1 root tubular 0 Feb  2 13:42 bindings
-rw-r----- 1 root tubular 0 Feb  2 13:42 destination_metrics</code></pre>
            <p>There is one more obstacle, <a href="https://github.com/systemd/systemd/blob/b049b48c4b6e60c3cbec9d2884f90fd4e7013219/src/shared/mount-setup.c#L111-L112">systemd mounts /sys/fs/bpf</a> in a way that makes it inaccessible to anyone but root. Adding the executable bit to the directory fixes this.</p>
            <pre><code>$ sudo chmod -v o+x /sys/fs/bpf
mode of '/sys/fs/bpf' changed from 0700 (rwx------) to 0701 (rwx-----x)</code></pre>
            <p>Finally, we can export metrics without privileges:</p>
            <pre><code>$ sudo -u nobody -g tubular tubectl metrics 127.0.0.1 8080
Listening on 127.0.0.1:8080
^C</code></pre>
            <p>There is a caveat, unfortunately: truly unprivileged access requires unprivileged BPF to be enabled. Many distros have taken to disabling it via the unprivileged_bpf_disabled sysctl, in which case scraping metrics does require CAP_BPF.</p>
    <div>
      <h2>Safe releases</h2>
      <a href="#safe-releases">
        
      </a>
    </div>
    <p>tubular is distributed as a single binary, but really consists of two pieces of code with widely differing lifetimes. The BPF program is loaded into the kernel once and then may be active for weeks or months, until it is explicitly replaced. In fact, a reference to the program (and link, see below) is persisted into /sys/fs/bpf:</p>
            <pre><code>/sys/fs/bpf/4026532024_dispatcher
├── link
├── program
└── ...</code></pre>
            <p>The user space code is executed for seconds at a time and is replaced whenever the binary on disk changes. This means that user space has to be able to deal with an "old" BPF program in the kernel somehow. The simplest way to achieve this is to compare what is loaded into the kernel with the BPF shipped as part of tubectl. If the two don't match we return an error:</p>
            <pre><code>$ sudo tubectl bind foo tcp 127.0.0.1 80
Error: bind: can't open dispatcher: loaded program #158 has differing tag: "938c70b5a8956ff2" doesn't match "e007bfbbf37171f0"</code></pre>
            <p><code>tag</code> is the truncated hash of the instructions making up a BPF program, which the kernel makes available for every loaded program:</p>
            <pre><code>$ sudo bpftool prog list id 158
158: sk_lookup  name dispatcher  tag 938c70b5a8956ff2
...</code></pre>
            <p>By comparing the tag tubular asserts that it is dealing with a supported version of the BPF program. Of course, just returning an error isn't enough. There needs to be a way to update the kernel program so that it's once again safe to make changes. This is where the persisted link in /sys/fs/bpf comes into play. <code>bpf_links</code> are used to attach programs to various BPF hooks. "Enabling" a BPF program is a two-step process: first, load the BPF program, next attach it to a hook using a bpf_link. Afterwards the program will execute the next time the hook is executed. By updating the link we can change the program on the fly, in an atomic manner.</p>
            <pre><code>$ sudo tubectl upgrade
Upgraded dispatcher to 2022.1.0-dev, program ID #159
$ sudo bpftool prog list id 159
159: sk_lookup  name dispatcher  tag e007bfbbf37171f0
…
$ sudo tubectl bind foo tcp 127.0.0.1 80
bound foo#tcp:[127.0.0.1/32]:80</code></pre>
            <p>Behind the scenes the upgrade procedure is slightly more complicated, since we have to update the pinned program reference in addition to the link. We pin the new program into /sys/fs/bpf:</p>
            <pre><code>/sys/fs/bpf/4026532024_dispatcher
├── link
├── program
├── program-upgrade
└── ...</code></pre>
            <p>Once the link is updated we <a href="https://www.man7.org/linux/man-pages/man2/rename.2.html">atomically rename</a> program-upgrade to replace program. In the future we may be able to <a href="https://lkml.kernel.org/netdev/20211028094724.59043-5-lmb@cloudflare.com/t/">use RENAME_EXCHANGE</a> to make upgrades even safer.</p>
    <div>
      <h2>Preventing state corruption</h2>
      <a href="#preventing-state-corruption">
        
      </a>
    </div>
    <p>So far we’ve completely neglected the fact that multiple invocations of <code>tubectl</code> could modify the state in /sys/fs/bpf at the same time. It’s very hard to reason about what would happen in this case, so in general it’s best to prevent this from ever occurring. A common solution to this is <a href="https://gavv.github.io/articles/file-locks/#differing-features">advisory file locks</a>. Unfortunately it seems like BPF maps don't support locking.</p>
            <pre><code>$ sudo flock /sys/fs/bpf/4026532024_dispatcher/bindings echo works!
flock: cannot open lock file /sys/fs/bpf/4026532024_dispatcher/bindings: Input/output error</code></pre>
            <p>This led to a bit of head scratching on our part. Luckily it is possible to flock the directory instead of individual maps:</p>
            <pre><code>$ sudo flock --exclusive /sys/fs/bpf/foo echo works!
works!</code></pre>
            <p>Each <code>tubectl</code> invocation likewise invokes <a href="https://www.man7.org/linux/man-pages//man2/flock.2.html"><code>flock()</code></a>, thereby guaranteeing that only ever a single process is making changes.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>tubular is in production at Cloudflare today and has simplified the deployment of <a href="https://www.cloudflare.com/products/cloudflare-spectrum/">Spectrum</a> and our <a href="https://www.cloudflare.com/dns/">authoritative DNS</a>. It allowed us to leave behind limitations of the BSD socket API. However, its most powerful feature is that <a href="https://research.cloudflare.com/publications/Fayed2021/">the addresses a service is available on can be changed on the fly</a>. In fact, we have built tooling that automates this process across our global network. Need to listen on another million IPs on thousands of machines? No problem, it’s just an HTTP POST away.</p><p><i>Interested in working on tubular and our L4 load balancer</i> <a href="/unimog-cloudflares-edge-load-balancer/"><i>unimog</i></a><i>? We are</i> <a href="https://boards.greenhouse.io/cloudflare/jobs/3232234?gh_jid=3232234"><i>hiring in our European offices</i></a><i>.</i></p> ]]></content:encoded>
            <category><![CDATA[eBPF]]></category>
            <category><![CDATA[Linux]]></category>
            <category><![CDATA[Go]]></category>
            <guid isPermaLink="false">7ofIShaWHxqlp4ZmHyNRs</guid>
            <dc:creator>Lorenz Bauer</dc:creator>
        </item>
        <item>
            <title><![CDATA[Pairings in CIRCL]]></title>
            <link>https://blog.cloudflare.com/circl-pairings-update/</link>
            <pubDate>Wed, 13 Oct 2021 12:59:30 GMT</pubDate>
            <description><![CDATA[ Our Go cryptographic library CIRCL announces support for pairing-based cryptography. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>In 2019, we announced the release of <a href="https://github.com/cloudflare/circl/">CIRCL</a>, an open-source cryptographic library written in Go that provides optimized implementations of several primitives for key exchange and digital signatures. We are pleased to announce a major update of our library: we have included more packages for elliptic curve-based cryptography (ECC), pairing-based cryptography, and quantum-resistant algorithms.</p><p>All of these packages are the foundation of work we’re doing on bringing the benefits of cutting edge research to Cloudflare. In the past we’ve <a href="/the-tls-post-quantum-experiment/">experimented with post-quantum algorithms</a>, used pairings to keep <a href="/geo-key-manager-how-it-works/">keys safe around the world</a>, and implemented <a href="/introducing-circl/">advanced elliptic curves</a>. Now we’re continuing that work, and sharing the foundation with everyone.</p><p>In this blog post we’re going to focus on pairing-based cryptography and give you a brief overview of some properties that make this topic so pleasant. If you are not so familiar with elliptic curves, we recommend this <a href="/a-relatively-easy-to-understand-primer-on-elliptic-curve-cryptography/">primer on ECC</a>.</p><p>Otherwise, let’s get ready, pairings have arrived!</p><p>What are pairings?</p><hr /><p>Elliptic curve cryptography enables an efficient instantiation of several cryptographic applications: public-key encryption, signatures, zero-knowledge proofs, and many other more exotic applications like <a href="https://en.wikipedia.org/wiki/Oblivious_transfer">oblivious transfer</a> and <a href="https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/">OPRF</a>s. With all of those applications you might wonder what is the additional value that pairings offer? To see that, we need first to understand the basic properties of an elliptic curve system, and from that we can highlight the big gap that pairings have.</p><p>Conventional elliptic curve systems work with a single group \( \mathbb{G} \): the points of an elliptic curve \(E\). In this group, usually denoted additively, we can add the points \(P\) and \(Q\) and get another point on the curve \(R=P+Q\); also, we can multiply a point \(P\) by an integer scalar \(k\) and by repeatedly doing$$ kP = \underbrace{P+P+\dots+P}_{k \text{ terms}} $$This operation is known as scalar multiplication, which resembles exponentiation, and there are efficient algorithms for this operation. But given the point \(Q=kP\), and \(P\), it is very hard for an adversary that doesn’t know \(k\) to find it. This is the Elliptic Curve Discrete Logarithm problem (ECDLP).</p><p>Now we show a property of scalar multiplication that can help us to understand the properties of pairings.</p><p><b><i>Scalar Multiplication is a Linear Map</i></b></p><p>Note the following equivalences:</p><p>\( (a+b)P = aP + bP \)</p><p>\( b (aP) = a (bP) \).</p><p>These are very useful properties for many protocols: for example, the last identity allows Alice and Bob to arrive at the same value when following the Diffie-Hellman key-agreement protocol.</p><p>But while point addition and scalar multiplication are nice, it’s also useful to be able to multiply points: if we had a point \(P\) and \(aP\) and \(bP\), getting \(abP\) out would be very cool and let us do all sorts of things. Unfortunately Diffie-Hellman would immediately be insecure, so we can’t get what we want.</p><p>Guess what? Pairings provide an efficient, useful <i>sort of intermediary</i> point multiplication.</p><p>It’s intermediate multiplication because although the operation takes two points as operands, the result of a pairing is not a point, but an element of a different group; thus, in a pairing there are more groups involved and all of them must contain the same number of elements.</p><p>Pairing is defined as  $$ e \colon\; \mathbb{G}_1 \times \mathbb{G}_2 \rightarrow \mathbb{G}_T $$Groups \(\mathbb{G}_1\) and \(\mathbb{G}_2\) contain points of an elliptic curve \(E\). More specifically, they are the \(r\)-torsion points, for a fixed prime \(r\). Some pairing instances fix \(\mathbb{G}_1=\mathbb{G}_2\), but it is common to use disjoint sets for efficiency reasons. The third group \(\mathbb{G}_T\) has notable differences. First, it is written multiplicatively, unlike the other two groups. \(\mathbb{G}_T\) is not the set of points on an elliptic curve. It’s instead a subgroup of the multiplicative group over some larger finite field. It contains the elements that satisfy \(x^r=1\), better known as the \(r\)-roots of unity.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/nmjAHa9jrnE1lnmilM8rR/f0c5e06aaadf4fbd276a970e5426eaef/2ai5WUAviNg3iAxw9x-IMAv3mVWnrMrDOgvJEIHsKqqNNn3OzQdeDJd6kMo578rqUTqoCPdQcFz6rcrTiXlyfdxL_iDLQ9v6zvswJiz5ini3lLgSMfHbFIpIEwS7.png" />
            
            </figure><p>Source: “<i>Pairings are not dead, just resting</i>” by Diego Aranha <a href="https://ecc2017.cs.ru.nl/slides/ecc2017-aranha.pdf">ECC-2017</a> (inspired by Avanzi’s talk at <a href="https://www.hyperelliptic.org/SPEED/slides09/avanzi.pdf">SPEED-2009</a>).</p><p>While every elliptic curve has a pairing, very few have ones that are efficiently computable. Those that do, we call them <i>pairing-friendly curves</i>.</p><p><b>The Pairing Operation is a Bilinear Map</b></p><p>What makes pairings special is that \(e\) is a <i>bilinear map</i>. Yes, the linear property of the scalar multiplication is present twice, one per group. Let’s see the first linear map.</p><p>For points \(P, Q, R\) and scalars \(a\) and \(b\) we have:</p><p>\( e(P+Q, R) = e(P, R) * e(Q, R) \)</p><p>\( e(aP, Q) = e(P, Q)^a \).</p><p>So, a scalar \(a\) acting in the first operand as \(aP\), finds its way out and escapes from the input of the pairing and appears in the output of the pairing as an exponent in \(\mathbb{G}_T\). The same linear map is observed for the second group:</p><p>\( e(P, Q+R) = e(P, Q) * e(P, R) \)</p><p>\( e(P, bQ) = e(P, Q)^b \).</p><p>Hence, the pairing is bilinear. We will see below how this property becomes useful.</p><p><b>Can bilinear pairings help solving ECDLP?</b></p><p>The <a href="https://www.dima.unige.it/~morafe/MaterialeCTC/p80-menezes.pdf">MOV</a> (by Menezes, Okamoto, and Vanstone) attack reduces the discrete logarithm problem on elliptic curves to finite fields. An attacker with knowledge of \(kP\) and public points \(P\) and \(Q\) can recover \(k\) by computing:</p><p>\( g = e(P, Q) \),</p><p>\( g_k = e(kP, Q) = e(P, Q)^k \),</p><p>\( k = \log_g(g_k) = \log_g(g^k) \).</p><p>Note that the discrete logarithm to be solved was moved from \(\mathbb{G}_1\) to \(\mathbb{G}_T\). So an attacker must ensure that the discrete logarithm is easier to solve in \(\mathbb{G}_T\), and surprisingly, for some curves this is the case.</p><p>Fortunately, pairings do not present a threat for standard curves (such as the NIST curves or Curve25519) because these curves are constructed in such a way that \(\mathbb{G}_T\) gets very large, which makes the pairing operation not efficient anymore.</p><p>This attacking strategy was one of the first applications of pairings in cryptanalysis as a tool to solve the discrete logarithm. Later, more people noticed that the properties of pairings are so useful, and can be used constructively to do cryptography. One of the fascinating truisms of cryptography is that one person's sledgehammer is another person's brick: while pairings yield a generic attack strategy for the ECDLP problem, it can also be used as a building block in a ton of useful applications.</p>
    <div>
      <h3>Applications of Pairings</h3>
      <a href="#applications-of-pairings">
        
      </a>
    </div>
    <p>In the 2000s decade, a large wave of research works were developed aimed at applying pairings to many practical problems. An iconic pairing-based system was created by Antoine Joux, who constructed a <a href="https://link.springer.com/chapter/10.1007/10722028_23">one-round Diffie-Hellman</a> key exchange for three parties.</p><p>Let’s see first how a three-party Diffie-Hellman is done without pairings. Alice, Bob and Charlie want to agree on a shared key, so they compute, respectively, \(aP\), \(bP\) and \(cP\) for a public point P. Then, they send to each other the points they computed. So Alice receives \(cP\) from Charlie and sends \(aP\) to Bob, who can then send \(baP\) to Charlie and get \(acP\) from Alice and so on. After all this is done, they can all compute \(k=abcP\). Can this be performed in a single round trip?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1pGrpJQPbIktFdaxQz81fd/a0bcccab1b5efa958bb221de5a220f43/vnfAPEoM5vefRaP6wysBktjTyxvh4sxXzYY3HUz3ErengPo01exd3LDLZ38SQi_lYTKoJZQEPuvGYaLBE7Kg7ExNErj8Yu5k06klm8cQoXdwgtOZkDR3umqZWa6o.png" />
            
            </figure><p>Two round Diffie-Hellman without pairings.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/hIYImdhvrm8dbikA9HnOv/9b5970d153b0c0146f844b310330609e/n8lyvbn43kHVis2z6mlUO5Msq5jVy2OixIA1xoZ9H3S0XZIczsdmnipD71gvvRDF6hZG10EWY0V803za-sihFWFMf32EF_0rRAlaA_zVXivOv0zYH1KOeMW4qZun.png" />
            
            </figure><p>One round Diffie-Hellman with pairings.</p><p>The 3-party Diffie-Hellman protocol needs two communication rounds (on the top), but with the use of pairings a one-round trip protocol is possible.</p><p>Affirmative! Antoine Joux <a href="https://doi.org/10.1007/s00145-004-0312-y">showed how</a> to agree on a shared secret in a single round of communication. Alice announces \(aP\), gets \(bP\) and \(cP\) from Bob and Charlie respectively, and then computes \(k= (bP, cP)^a\). Likewise Bob computes \(e(aP,cP)^b\) and Charlie does \(e(aP,bP)^c\). It’s not difficult to convince yourself that all these values are equivalent, just by looking at the bilinear property.</p><p>\( e(bP,cP)^a  = e(aP,cP)^b  = e(aP,bP)^c = e(P,P)^{abc}\)</p><p>With pairings we’ve done in one round what would otherwise take two.</p><p>Another application in cryptography addresses a problem posed by Shamir in 1984: does there exist an encryption scheme in which the public key is an arbitrary string? Imagine if your public key was your email address. It would be easy to remember and certificate authorities and certificate management would be unnecessary.</p><p>A solution to this problem came some years later, in 2001, and is the Identity-based Encryption (IBE) scheme proposed by <a href="https://crypto.stanford.edu/~dabo/papers/bfibe.pdf">Boneh and Franklin</a>, which uses bilinear pairings as the main tool.</p><p>Nowadays, pairings are used for the <a href="https://eprint.iacr.org/2012/215">zk-SNARKS</a> that make Zcash an anonymous currency, and are also used in <a href="https://developers.cloudflare.com/randomness-beacon/about">drand</a> to generate public-verifiable randomness. Pairings and the compact, aggregatable BLS signatures are used in Ethereum. We have used pairings to build Geo Key Manager: pairings let us implement a compact broadcast and negative broadcast scheme that together make <a href="/geo-key-manager-how-it-works/">Geo Key Manager</a> work.</p><p>In order to make these schemes, we have to implement pairings, and to do that we need to understand the mathematics behind them.</p>
    <div>
      <h3>Where do pairings come from?</h3>
      <a href="#where-do-pairings-come-from">
        
      </a>
    </div>
    <p>In order to deeply understand pairings we must understand the interplay of geometry and arithmetic, and the origins of the group’s law. The starting point is the concept of a <i>divisor</i>, a formal combination of points on the curve.</p><p>\( D = \sum n_i P_i \)</p><p>The sum of all the coefficients \(n_i\) is the degree of the divisor. If we have a function on the curve that has poles and zeros, we can count them with multiplicity to get a <i>principal divisor</i>. Poles are counted as negative, while zeros as positive. For example if we take the projective line, the function \(x\) has the divisor \((0)-(\infty)\).</p><p>The degree of a divisor is the sum of its coefficients. All principal divisors have degree equal to \(0\).  The group of degree zero divisors modulo the principal divisors is the Jacobian. This means that we take all the degree zero divisors, and freely add or subtract principle divisors, constructing an abelian variety called the Jacobian.</p><p>Until now our constructions have worked for any curve.  Elliptic curves have a special property: since a line intersects the curve in three points, it’s always possible to turn an element of the Jacobian into one of the form \((P)-(O)\) for a point \(P\). This is where the addition law of elliptic curves comes from.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4eisQYqRXhDNLTdMbiFZRO/0db5b48f5cd06ea377cd944c5120036a/DZUPeC6dl9fx4W7ggusFvWzN6-zjcQAroZZAcu2BsDWuhOd1j9_YjfjyCpCI2jOwLi9IoCDgKSNEyb4Zc3q7cp5wVM6_gyNMBDHfttqQ_cTxedlMzBLS8EOb2miG.png" />
            
            </figure><p>The relation between addition on an elliptic curve and the geometry of the curve. Source file <a href="https://commons.wikimedia.org/wiki/File:ECClines.svg">ECClines.svg</a></p><p>Given a function \(f\) we can evaluate it on a divisor \(D=\sum n_i P_i\) by taking the product \(\prod f(P_i)^{n_i}\). And if two functions \(f\) and \(g\) have disjoint divisors, we have the <i>Weil duality</i>:</p><p>\( f(\text{div}(g)) = g(\text{div}(f)) \),</p><p>The existence of Weil duality is what gives us the bilinear map we seek. Given an \(r\)-torsion point \(T\) we have a function \(f\) whose divisor is \(r(T)-r(O)\). We can write down an auxiliary function \(g\) such that \(f(rP)=g^r(P)\) for any \(P\). We then get a pairing by taking:</p><p>\(e_r(S,T)=\frac{g(X+S)}{g(X)}\).</p><p>The auxiliary point \(X\) is any point that makes the numerator and denominator defined.</p><p>In practice, the pairing we have defined above, the Weil pairing, is little used. It was historically the first pairing and is extremely important in the mathematics of elliptic curves, but faster alternatives based on more complicated underlying mathematics are used today. These faster pairings have different \(\mathbb{G}_1\) and \(\mathbb{G}_2\), while the Weil pairing made them the same.</p>
    <div>
      <h3>Shift in parameters</h3>
      <a href="#shift-in-parameters">
        
      </a>
    </div>
    <p>As we saw earlier, the discrete logarithm problem can be attacked either on the group of elliptic curve points or on the third group (an extension of a prime field) whichever is weaker. This is why the parameters that define a pairing must balance the security of the three groups.</p><p>Before 2015 a good balance between the extension degree, the size of the prime field, and the security of the scheme was achieved by the family of <a href="https://eprint.iacr.org/2005/133.pdf">Barreto-Naehrig</a> (BN) curves. For 128 bits of security, BN curves use an extension of degree 12, and have a prime of size 256 bits; as a result they are an efficient choice for implementation.</p><p>A breakthrough for pairings occurred in 2015 when Kim and Barbescu <a href="https://ia.cr/2015/1027">published a result</a> that accelerated the attacks in finite fields. This resulted in increasing the size of fields to comply with standard security levels. Just as short hashes like MD5 got depreciated as they became insecure and \(2^{64}\) was no longer enough, and RSA-1024 was replaced with RSA-2048, we regularly change parameters to deal with improved attacks.</p><p>For pairings this implied the use of larger primes for all the groups. Roughly speaking, the previous 192-bit security level becomes the new 128-bit level after this attack. Also, this shift in parameters brings the family of <a href="https://eprint.iacr.org/2002/088.pdf">Barreto-Lynn-Scott</a> (BLS) curves to the stage because pairings on BLS curves are faster than BN in this new setting. Hence, currently BLS curves using an extension of degree 12, and primes of around 384 bits provide the equivalent to 128 bit security.</p><p>The IETF draft (currently in preparation) <a href="https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/">draft-irtf-cfrg-pairing-friendly-curves</a> specifies secure pairing-friendly elliptic curves. It includes parameters for BN and BLS families of curves. It also targets different security levels to provide crypto agility for some applications relying on pairing-based cryptography.</p>
    <div>
      <h2>Implementing Pairings in Go</h2>
      <a href="#implementing-pairings-in-go">
        
      </a>
    </div>
    <p>Historically, notable examples of software libraries implementing pairings include <a href="https://crypto.stanford.edu/pbc/">PBC</a> by Ben Lynn, <a href="https://github.com/miracl/core">Miracl</a> by Michael Scott, and <a href="https://github.com/relic-toolkit/relic">Relic</a> by Diego Aranha. All of them are written in C/C++ and some ports and wrappers to other languages exist.</p><p>In the Go standard library we can find the <a href="https://pkg.go.dev/golang.org/x/crypto/bn256">golang.org/x/crypto/bn256</a> package by Adam Langley, an implementation of a pairing using a BN curve with 256-bit prime. Our colleague Brendan McMillion built <a href="https://github.com/cloudflare/bn256">github.com/cloudflare/bn256</a> that dramatically improves the speed of pairing operations for that curve. See the <a href="https://youtu.be/eHqIq1kFJJo?t=791">RWC-2018</a> talk to see our use case of pairing-based cryptography. This time we want to go one step further, and we started looking for alternative pairing implementations.</p><p>Although one can find many libraries that implement pairings, our goal is to rely on one that is efficient, includes protection against side channels, and exposes a flexible API oriented towards applications that permit generality, while avoiding common security pitfalls. This motivated us to include pairings in <a href="https://github.com/cloudflare/circl/tree/master/ecc/bls12381">CIRCL</a>. We followed best practices on secure code development and we want to share with you some details about the implementation.</p><p>We started by choosing a pairing-friendly curve. Due to the attack previously mentioned, the BN256 curve does not meet the 128-bit security level. Thus there is a need for using stronger curves. Such a stronger curve is the <a href="https://electriccoin.co/blog/new-snark-curve/">BLS12-381</a> curve that is widely used in the zk-SNARK protocols and short signature schemes. Using this curve allows us to make our Go pairing implementation interoperable with other implementations available in other programming languages, so other projects can benefit from using CIRCL too.</p><p>This code snippet tests the linearity property of pairings and shows how easy it is to use our library.</p><div><pre><span>import</span> (
    <span>"crypto/rand"</span>
    <span>"fmt"</span>
    e <span>"github.com/cloudflare/circl/ecc/bls12381"</span>
)

<span>func</span> ExamplePairing() {
    P,  Q <span>:=</span> e.G1Generator(), e.G2Generator()
    a,  b <span>:=</span> <span>new</span>(e.Scalar), <span>new</span>(e.Scalar)
    aP, bQ <span>:=</span> <span>new</span>(e.G1), <span>new</span>(e.G2)
    ea, eb <span>:=</span> <span>new</span>(e.Gt), <span>new</span>(e.Gt)

    a.Random(rand.Reader)
    b.Random(rand.Reader)

    aP.ScalarMult(a, P)
    bQ.ScalarMult(b, Q)

    g  <span>:=</span> e.Pair( P, Q)
    ga <span>:=</span> e.Pair(aP, Q)
    gb <span>:=</span> e.Pair( P,bQ)

    ea.Exp(g, a)
    eb.Exp(g, b)
    linearLeft <span>:=</span> ea.IsEqual(ga) <span>// e(P,Q)^a == e(aP,Q)</span>
    linearRight<span>:=</span> eb.IsEqual(gb) <span>// e(P,Q)^b == e(P,bQ)</span>

    fmt.Print(linearLeft <span>&amp;&amp;</span> linearRight)
    <span>// Output: true</span>
}
</pre></div>
<p>We applied several optimizations that allowed us to improve on performance and security of the implementation. In fact, as the parameters of the curve are fixed, some other optimizations become easier to apply; for example, the code for prime field arithmetic and the towering construction for extension fields as we detail next.</p>
    <div>
      <h3>Formally-verified arithmetic using fiat-crypto</h3>
      <a href="#formally-verified-arithmetic-using-fiat-crypto">
        
      </a>
    </div>
    <p>One of the more difficult parts of a cryptography library to implement correctly is the prime field arithmetic. Typically people specialize it for speed, but there are many tedious constraints on what the inputs to operations can be to ensure correctness. Vulnerabilities have happened when people get it wrong, across many libraries. However, this code is perfect for machines to write and check. One such tool is <a href="https://github.com/mit-plv/fiat-crypto">fiat-crypto</a>.</p><p>Using fiat-crypto to generate the prime field arithmetic means that we have a formal verification that the code does what we need. The fiat-crypto tool is <a href="https://github.com/cloudflare/circl/blob/5115a7384c00c16f684872cd8019e82a7b385f30/ecc/bls12381/ff/gen.go">invoked in this script</a>, and produces Go code for addition, subtraction, multiplication, and squaring over the 381-bit prime field used in the BLS12-381 curve. Other operations are not covered, but those are much easier to check and analyze by hand.</p><p>Another advantage is that it avoids relying on the generic <a href="https://golang.org/pkg/math/big/#Int">big.Int</a> package, which is slow, frequently spills variables to the heap causing dynamic memory allocations, and most importantly, does not run in constant-time. Instead, the code produced is straight-line code, no branches at all, and relies on the <a href="https://golang.org/pkg/math/bits">math/bits</a> package for accessing machine-level instructions. Automated code generation also means that it’s easier to apply new techniques to all primitives.</p>
    <div>
      <h3>Tower Field Arithmetic</h3>
      <a href="#tower-field-arithmetic">
        
      </a>
    </div>
    <p>In addition to prime field arithmetic, say integers modulo a prime number p, a pairing also requires high-level arithmetic operations over extension fields.</p><p>To better understand what an extension field is, think of the analogous case of going from the reals to the complex numbers: the operations are referred as usual, there exist addition, multiplication and division \((+, -, \times, /)\), however they are computed quite differently.</p><p>The complex numbers are a quadratic extension over the reals, so imagine a two-level house. The first floor is where the real numbers live, however, they cannot access the second floor by themselves. On the other hand, the complex numbers can access the entire house through the use of a staircase. The equation \(f(x)=x^2+1\) was not solvable over the reals, but is solvable over the complex numbers, since they have the number \(i^2=1\). And because they have the number \(i\), they also have to have numbers like \(3i\) and \(5+i\) that solve other equations that weren’t solvable over the reals either. This second story has given the roots of the polynomials a place to live.</p><p>Algebraically we can view the complex numbers as \(\mathbb{R}[x]/(x^2+1)\), the space of polynomials where we consider \(x^2=-1\). Given a polynomial like \(x^3+5x+1\), we can turn it into \(4x+1\), which is another way of writing \(1+4i\). In this new field \(x^2+1=0\) holds automatically, and we have added both \(x\) as a root of the polynomial we picked. This process of writing down a field extension by adding a root of a polynomial works over any field, including finite fields.</p><p>Following this analogy, one can construct not a house but a tower, say a \(k=12\) floor building where the ground floor is the prime field \(\mathbb{F}_p\). The reason to build such a large tower is because we want to host VIP guests: namely a group called \(\mu_r\), <i>the</i> \(r\)<i>-roots of unity</i>. There are exactly \(r\) members and they behave as an (algebraic) group, i.e. for all \(x,y \in \mu_r\), it follows \(x*y \in \mu_r\) and \(x^r = 1\).</p><p>One particularity is that making operations on the top-floor can be costly. Assume that whenever an operation is needed in the top-floor, members who live on the main floor are required to provide their assistance. Hence an operation on the top-floor needs to go all the way down to the ground floor. For this reason, our tower needs more than a staircase, it needs an efficient way to move between the levels, something even better than an elevator.</p><p>What if we use portals? Imagine anyone on the twelfth floor using a portal to go down immediately to the sixth floor, and then use another one connecting the sixth to the second floor, and finally another portal connecting to the ground floor. Thus, one can get faster to the first floor rather than descending through a long staircase.</p><p>The building analogy can be used to understand and construct a tower of finite fields. We use only some extensions to build a twelfth extension from the (ground) prime field \(\mathbb{F}_p\).</p><p>\(\mathbb{F}_{p}\) ⇒  \(\mathbb{F}_{p^2}\) ⇒  \(\mathbb{F}_{p^6}\) ⇒  \(\mathbb{F}_{p^{12}}\)</p><p>In fact, the extension of finite fields is as follows:</p><ul><li><p>\(\mathbb{F}_{p^2}\) is built as polynomials in \(\mathbb{F}_p[u]\) reduced modulo \(u^2+1=0\).</p></li><li><p>\(\mathbb{F}_{p^6}\) is built as polynomials in \(\mathbb{F}_{p^2}[v]\) reduced modulo \(v^3+u+1=0\).</p></li><li><p>\(\mathbb{F}_{p^{12}}\) is built as polynomials in \(\mathbb{F}_{p^6}[w]\) reduced modulo \(w^2+v=0\), or as polynomials in \(\mathbb{F}_{p^4}[w]\) reduced modulo \(w^3+v=0\).</p></li></ul><p>The portals here are the polynomials used as modulus, as they allow us to move from one extension to the other.</p><p>Different constructions for higher extensions have an impact on the number of operations performed. Thus, we implemented the latter tower field for \(\mathbb{F}_{p^{12}}\) as it results in a lower number of operations. The arithmetic operations are quite easy to implement and manually verify, so at this level formal verification is not as effective as in the case of prime field arithmetic. However, having an automated tool that generates code for this arithmetic would be useful for developers not familiar with the internals of field towering. The fiat-crypto tool keeps track of this idea [<a href="https://github.com/mit-plv/fiat-crypto/issues/904">Issue 904</a>, <a href="https://github.com/mit-plv/fiat-crypto/issues/851">Issue 851</a>].</p><p>Now, we describe more details about the main core operations of a bilinear pairing.</p>
    <div>
      <h3>The Miller loop and the final exponentiation</h3>
      <a href="#the-miller-loop-and-the-final-exponentiation">
        
      </a>
    </div>
    <p>The pairing function we implemented is the <a href="https://eprint.iacr.org/2008/096">optimal r-ate</a> pairing, which is defined as:</p><p>\( e(P,Q) = f_Q(P)^{\text{exp}} \)</p><p>That is the construction of a function \(f\) based on \(Q\), then evaluated on a point \(P\), and the result of that is raised to a specific power. The efficient function evaluation is performed using “the Miller loop”, which is an algorithm devised by <a href="https://crypto.stanford.edu/miller/miller.pdf">Victor Miller</a> and has a similar structure to a double-and-add algorithm for scalar multiplication.</p><p>After having computed \(f_Q(P)\) this value is an element of \(\mathbb{F}_{p^{12}}\), however it is not yet an \(r\)-root of unity; in order to do so, the final exponentiation accomplishes this task. Since the exponent is constant for each curve, special algorithms can be tuned for it.</p><p>One interesting acceleration opportunity presents itself: in the Miller loop the elements of \(\mathbb{F}_{p^{12}}\) that we have to multiply by are special — as polynomials, they have no linear term and their constant term lives in \(\mathbb{F}_{p^{2}}\). We created a specialized multiplication that avoids multiplications where the input has to be zero. This specialization accelerated the pairing computation by 12%.</p><p>So far, we have described how the internal operations of a pairing are performed. There are still some other functions floating around regarding the use of pairings in cryptographic protocols. It is also important to optimize these functions and now we will discuss some of them.</p>
    <div>
      <h3>Product of Pairings</h3>
      <a href="#product-of-pairings">
        
      </a>
    </div>
    <p>Often protocols will want to evaluate a product of pairings, rather than a single pairing. This is the case if we’re evaluating multiple signatures, or if the protocol uses cancellation between different equations to ensure security, as in the <i>dual system encoding</i> approach to designing protocols. If each pairing was evaluated individually, this would require multiple evaluations of the final exponentiation. However, we can evaluate the product first, and then evaluate the final exponentiation once. This requires a different interface that can take vectors of points.</p><p>Occasionally, there is a sign or an exponent in the factors of the product. It’s very easy to deal with a sign explicitly by negating one of the input points, almost for free. General exponents are more complicated, especially when considering the need for side channel protection. But since we expose the interface, later work on the library will accelerate it without changing applications.</p><p>Regarding API exposure, one of the trickiest and most error prone aspects of software engineering is input validation. So we must check that raw binary inputs decode correctly as the points used for a pairing. Part of this verification includes subgroup membership testing which is the topic we discuss next.</p>
    <div>
      <h3>Subgroup Membership Testing</h3>
      <a href="#subgroup-membership-testing">
        
      </a>
    </div>
    <p>Checking that a point is on the curve is easy, but checking that it has the right order is not: the classical way to do this is an entire expensive scalar multiplication. But implementing pairings involves the use of many clever tricks that help to make things run faster.</p><p>One example is <i>twisting</i>: the \(\mathbb{G}_2\) group are points with coordinates in \(\mathbb{F}_{p^{12}}\), however, one can use a smaller field to reduce the number of operations. The trick here is using an associated curve \(E’\), which is a twist of the original curve \(E\). This allows us to work on the subfield \(\mathbb{F}_{p^{2}}\) that has cheaper operations.</p><p>Additionally, twisting the curve over \(\mathbb{G}_2\) carries some efficiently computable endomorphisms coming from the field structure. For the cost of two field multiplications, we can compute an additional endomorphism, dramatically decreasing the cost of scalar multiplication.</p><p>By searching for the smallest combination of scalars that could zero out the \(r\)-torsion points, <a href="https://eprint.iacr.org/2019/814">Sean Bowe</a> came up with a much more efficient way to do subgroup checks. We implement his trick, with a big reduction in the complexity of some applications.</p><p>As can be seen, implementing a pairing is full of subtleties. We just saw that point validation in the pairing setting is a bit more challenging than in the conventional case of elliptic curve cryptography. This kind of reformulation also applies to other operations that require special care on their implementation. One another example is how to encode binary strings as elements of the group \(\mathbb{G}_1\) (or \(\mathbb{G}_2\)). Although this operation might sound simple, implementing it securely needs to take into consideration several aspects; thus we expand more on this topic.</p>
    <div>
      <h3>Hash to Curve</h3>
      <a href="#hash-to-curve">
        
      </a>
    </div>
    <p>An important piece on the <a href="https://crypto.stanford.edu/~dabo/papers/bfibe.pdf">Boneh-Franklin</a> Identity-based Encryption scheme is a special hash function that maps an arbitrary string — the identity, e.g., an email address — to a point on an elliptic curve, and that still behaves as a conventional cryptographic hash function (such as SHA-256) that is hard to invert and collision-resistant. This operation is commonly known as <i>hashing to curve</i>.</p><p>Boneh and Franklin found a particular way to perform hashing to curve: apply a conventional hash function to the input bitstring, and interpret the result as the \(y\)-coordinate of a point, then from the curve equation \(y^2=x^3+b\), find the \(x\)-coordinate as \(x=\sqrt[3]{y^2-b}\). The cubic root always exists on fields of characteristic \(p\equiv 2 \bmod{3}\). But this algorithm does not apply to other fields in general restricting the parameters to be used.</p><p>Another popular algorithm, but since now we need to remark it is an insecure way for performing hash to curve is the following. Let the hash of the input be the \(x\)-coordinate, and from it find the \(y\)-coordinate by computing a square root \(y= \sqrt{x^3+b}\). Note that not all \(x\)-coordinates lead that the square root exists, which means the algorithm may fail; thus, it’s a probabilistic algorithm. To make sure it works always, a counter can be added to \(x\) and increased each time the square root is not found. Although this algorithm always finds a point on the curve, this also makes the algorithm run in variable time i.e., it's a non-constant time algorithm. The lack of this property on implementations of cryptographic algorithms makes them susceptible to timing attacks. The <a href="https://wpa3.mathyvanhoef.com/">DragonBlood</a> attack is an example of how a non-constant time hashing algorithm resulted in a full key recovery of WPA3 Wi-Fi passwords.</p><p>Secure hash to curve algorithms must guarantee several properties. It must be ensured that any input passed to the hash produces a point on the targeted group. That is no special inputs must trigger exceptional cases, and the output point must belong to the <i>correct</i> group. We make emphasis on the correct group since in certain applications the target group is the entire set of points of an elliptic curve, but in other cases, such as in the pairing setting, the target group is a subgroup of the entire curve, recall that \(\mathbb{G}_1\) and \(\mathbb{G}_2\) are \(r\)-torsion points. Finally, some cryptographic protocols are proven secure provided that the hash to curve function behaves as a random oracle of points. This requirement adds another level of complexity to the hash to curve function.</p><p>Fortunately, several researchers have addressed most of these problems and some other researchers have been involved in efforts to define a concrete specification for secure algorithms for hashing to curves, by extending the sort of geometric trick that worked for the Boneh-Franklin curve. We have participated in the Crypto Forum Research Group (CFRG) at IETF on the work-in-progress Internet <a href="https://datatracker.ietf.org/doc/draft-irtf-cfrg-hash-to-curve/">draft-irtf-cfrg-hash-to-curve</a>. This document specifies secure algorithms for hashing targeting several elliptic curves including the BLS12-381 curve. At Cloudflare, we are actively collaborating in several working groups of IETF, see Jonathan Hoyland’s <a href="/cloudflare-and-the-ietf">post</a> to know more about it.</p><p>Our implementation complies with the recommendations given in the hash to curve draft and also includes many implementation techniques and tricks derived from a vast number of academic research articles in pairing-based cryptography. A good compilation of most of these tricks is delightfully explained by <a href="https://www.craigcostello.com.au/s/PairingsForBeginners.pdf">Craig Costello</a>.</p><p>We hope this post helps you to shed some light and guidance on the development of pairing-based cryptography, as it has become much more relevant these days. We will share with you soon an interesting use case in which the application of pairing-based cryptography helps us to harden the security of our infrastructure.</p>
    <div>
      <h2>What’s next?</h2>
      <a href="#whats-next">
        
      </a>
    </div>
    <p>We invite you to use our <a href="https://github.com/cloudflare/circl/">CIRCL</a> library, now equipped with bilinear pairings. But there is more: look at other primitives already available such as <a href="https://github.com/cloudflare/circl/tree/master/hpke">HPKE</a>, <a href="https://github.com/cloudflare/circl/tree/master/oprf">VOPRF</a>, and <a href="https://github.com/cloudflare/circl/tree/master/kem">Post-Quantum</a> algorithms. On our side, we will continue improving the performance and security of our library, and let us know if any of your projects uses CIRCL, we would like to know your use case. Reach us at <a href="https://research.cloudflare.com">research.cloudflare.com</a>.</p><p>You’ll soon hear more about how we’re using CIRCL across Cloudflare.</p> ]]></content:encoded>
            <category><![CDATA[Research]]></category>
            <category><![CDATA[Cryptography]]></category>
            <category><![CDATA[Go]]></category>
            <guid isPermaLink="false">78HsUIApwC8CnQLeWxAi07</guid>
            <dc:creator>Armando Faz-Hernández</dc:creator>
            <dc:creator>Watson Ladd</dc:creator>
        </item>
        <item>
            <title><![CDATA[Know your SCM_RIGHTS]]></title>
            <link>https://blog.cloudflare.com/know-your-scm_rights/</link>
            <pubDate>Thu, 29 Nov 2018 09:54:22 GMT</pubDate>
            <description><![CDATA[ As TLS 1.3 was ratified earlier this year, I was recollecting how we got started with it here at Cloudflare. We made the decision to be early adopters of TLS 1.3 a little over two years ago. It was a very important decision, and we took it very seriously. ]]></description>
            <content:encoded><![CDATA[ <p>As TLS 1.3 was ratified earlier <a href="/rfc-8446-aka-tls-1-3/">this year</a>, I was recollecting how we got started with it here at Cloudflare. We made the decision to be early adopters of <a href="/introducing-tls-1-3/">TLS 1.3</a> a little over two years ago. It was a very important decision, and we took it very seriously.</p><p>It is no secret that Cloudflare uses <a href="/end-of-the-road-for-cloudflare-nginx/">nginx</a> to handle user traffic. A little less known fact, is that we have several instances of nginx running. I won’t go into detail, but there is one instance whose job is to accept connections on port 443, and proxy them to another instance of nginx that actually handles the requests. It has pretty limited functionality otherwise. We fondly call it nginx-ssl.</p><p>Back then we were using OpenSSL for TLS and Crypto in nginx, but OpenSSL (and BoringSSL) had yet to announce a timeline for TLS 1.3 support, therefore we had to implement our own TLS 1.3 stack. Obviously we wanted an implementation that would not affect any customer or client that would not enable TLS 1.3. We also needed something that we could iterate on quickly, because the spec was very fluid back then, and also something that we can release frequently without worrying about the rest of the Cloudflare stack.</p><p>The obvious solution was to implement it on top of OpenSSL. The OpenSSL version we were using was 1.0.2, but not only were we looking ahead to replace it with version 1.1.0 or with <a href="/make-ssl-boring-again/">BoringSSL</a> (which we eventually did), it was so ingrained in our stack and so fragile that we wouldn’t be able to achieve our stated goals, without risking serious bugs.</p><p>Instead, Filippo Valsorda and Brendan McMillion suggested that the easier path would be to implement TLS 1.3 on top of the Go TLS library and make a Go replica of nginx-ssl (go-ssl). Go is very easy to iterate and prototype, with a powerful standard library, and we had a great pool of Go talent to use, so it made a lot of sense. Thus <a href="https://github.com/cloudflare/tls-tris">tls-tris</a> was born.</p><p>The question remained how would we have Go handle only TLS 1.3 while letting nginx handling all prior versions of TLS?</p><p>And herein lies the problem. Both TLS 1.3 and older versions of TLS communicate on port 443, and it is common knowledge that only one application can listen on a given TCP port, and that application is nginx, that would still handle the bulk of the TLS traffic. We could pipe all the TCP data into another connection in Go, effectively creating an additional proxy layer, but where is the fun in that? Also it seemed a little inefficient.</p>
    <div>
      <h2>Meet SCM_RIGHTS</h2>
      <a href="#meet-scm_rights">
        
      </a>
    </div>
    <p>So how do you make two different processes, written in two different programming languages, share the same TCP socket?</p><p>Fortunately, Linux (or rather UNIX) provides us with just the tool that we need. You can use UNIX-domain sockets to pass file descriptors between applications, and like everything else in UNIX connections are files.Looking at <code>man 7 unix</code> we see the following:</p>
            <pre><code>   Ancillary messages
       Ancillary  data  is  sent and received using sendmsg(2) and recvmsg(2).
       For historical reasons the ancillary message  types  listed  below  are
       specified with a SOL_SOCKET type even though they are AF_UNIX specific.
       To send them  set  the  cmsg_level  field  of  the  struct  cmsghdr  to
       SOL_SOCKET  and  the cmsg_type field to the type.  For more information
       see cmsg(3).

       SCM_RIGHTS
              Send or receive a set of  open  file  descriptors  from  another
              process.  The data portion contains an integer array of the file
              descriptors.  The passed file descriptors behave as though  they
              have been created with dup(2).</code></pre>
            <blockquote><p>Technically you do not send “file descriptors”. The “file descriptors” you handle in the code are simply indices into the processes' local file descriptor table, which in turn points into the OS' open file table, that finally points to the vnode representing the file. Thus the “file descriptor” observed by the other process will most likely have a different numeric value, despite pointing to the same file.</p></blockquote><p>We can also check <code>man 3 cmsg</code> as suggested, to find a handy example on how to use SCM_RIGHTS:</p>
            <pre><code>   struct msghdr msg = { 0 };
   struct cmsghdr *cmsg;
   int myfds[NUM_FD];  /* Contains the file descriptors to pass */
   int *fdptr;
   union {         /* Ancillary data buffer, wrapped in a union
                      in order to ensure it is suitably aligned */
       char buf[CMSG_SPACE(sizeof(myfds))];
       struct cmsghdr align;
   } u;

   msg.msg_control = u.buf;
   msg.msg_controllen = sizeof(u.buf);
   cmsg = CMSG_FIRSTHDR(&amp;msg);
   cmsg-&gt;cmsg_level = SOL_SOCKET;
   cmsg-&gt;cmsg_type = SCM_RIGHTS;
   cmsg-&gt;cmsg_len = CMSG_LEN(sizeof(int) * NUM_FD);
   fdptr = (int *) CMSG_DATA(cmsg);    /* Initialize the payload */
   memcpy(fdptr, myfds, NUM_FD * sizeof(int));</code></pre>
            <p>And that is what we decided to use. We let OpenSSL read the “Client Hello” message from an established TCP connection. If the “Client Hello” indicated TLS version 1.3, we would use SCM_RIGHTS to send it to the Go process. The Go process would in turn try to parse the rest of the “Client Hello”, if it were successful it would proceed with TLS 1.3 connection, and upon failure it would give the file descriptor back to OpenSSL, to handle regularly.</p><p>So how exactly do you implement something like that?</p><p>Since in our case we established that the C process will listen for TCP connections, our other process will have to listen on a UNIX socket, for connections C will want to forward.</p><p>For example in Go:</p>
            <pre><code>type scmListener struct {
	*net.UnixListener
}

type scmConn struct {
	*net.UnixConn
}

var path = "/tmp/scm_example.sock"

func listenSCM() (*scmListener, error) {
	syscall.Unlink(path)

	addr, err := net.ResolveUnixAddr("unix", path)
	if err != nil {
		return nil, err
	}

	ul, err := net.ListenUnix("unix", addr)
	if err != nil {
		return nil, err
	}

	err = os.Chmod(path, 0777)
	if err != nil {
		return nil, err
	}

	return &amp;scmListener{ul}, nil
}

func (l *scmListener) Accept() (*scmConn, error) {
	uc, err := l.AcceptUnix()
	if err != nil {
		return nil, err
	}
	return &amp;scmConn{uc}, nil
}</code></pre>
            <p>Then in the C process, for each connection we want to pass, we will connect to that socket first:</p>
            <pre><code>int connect_unix()
{
    struct sockaddr_un addr = {.sun_family = AF_UNIX,
                               .sun_path = "/tmp/scm_example.sock"};

    int unix_sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (unix_sock == -1)
        return -1;

    if (connect(unix_sock, (struct sockaddr *)&amp;addr, sizeof(addr)) == -1)
    {
        close(unix_sock);
        return -1;
    }

    return unix_sock;
}</code></pre>
            <p>To actually pass a file descriptor we utilize the example from <code>man 3 cmsg</code>:</p>
            <pre><code>int send_fd(int unix_sock, int fd)
{
    struct iovec iov = {.iov_base = ":)", // Must send at least one byte
                        .iov_len = 2};

    union {
        char buf[CMSG_SPACE(sizeof(fd))];
        struct cmsghdr align;
    } u;

    struct msghdr msg = {.msg_iov = &amp;iov,
                         .msg_iovlen = 1,
                         .msg_control = u.buf,
                         .msg_controllen = sizeof(u.buf)};

    struct cmsghdr *cmsg = CMSG_FIRSTHDR(&amp;msg);
    *cmsg = (struct cmsghdr){.cmsg_level = SOL_SOCKET,
                             .cmsg_type = SCM_RIGHTS,
                             .cmsg_len = CMSG_LEN(sizeof(fd))};

    memcpy(CMSG_DATA(cmsg), &amp;fd, sizeof(fd));

    return sendmsg(unix_sock, &amp;msg, 0);
}</code></pre>
            <p>Then to receive the file descriptor in Go:</p>
            <pre><code>func (c *scmConn) ReadFD() (*os.File, error) {
	msg, oob := make([]byte, 2), make([]byte, 128)

	_, oobn, _, _, err := c.ReadMsgUnix(msg, oob)
	if err != nil {
		return nil, err
	}

	cmsgs, err := syscall.ParseSocketControlMessage(oob[0:oobn])
	if err != nil {
		return nil, err
	} else if len(cmsgs) != 1 {
		return nil, errors.New("invalid number of cmsgs received")
	}

	fds, err := syscall.ParseUnixRights(&amp;cmsgs[0])
	if err != nil {
		return nil, err
	} else if len(fds) != 1 {
		return nil, errors.New("invalid number of fds received")
	}

	fd := os.NewFile(uintptr(fds[0]), "")
	if fd == nil {
		return nil, errors.New("could not open fd")
	}

	return fd, nil
}</code></pre>
            
    <div>
      <h2>Rust</h2>
      <a href="#rust">
        
      </a>
    </div>
    <p>We can also do this in Rust, although the standard library in Rust does not yet support UNIX sockets, but it does let you address the C library via the <a href="https://rust-lang.github.io/libc/x86_64-unknown-linux-gnu/libc/">libc</a> crate. Warning, unsafe code ahead!</p><p>First we want to implement some UNIX socket functionality in Rust:</p>
            <pre><code>use libc::*;
use std::io::prelude::*;
use std::net::TcpStream;
use std::os::unix::io::FromRawFd;
use std::os::unix::io::RawFd;

fn errno_str() -&gt; String {
    let strerr = unsafe { strerror(*__error()) };
    let c_str = unsafe { std::ffi::CStr::from_ptr(strerr) };
    c_str.to_string_lossy().into_owned()
}

pub struct UNIXSocket {
    fd: RawFd,
}

pub struct UNIXConn {
    fd: RawFd,
}

impl Drop for UNIXSocket {
    fn drop(&amp;mut self) {
        unsafe { close(self.fd) };
    }
}

impl Drop for UNIXConn {
    fn drop(&amp;mut self) {
        unsafe { close(self.fd) };
    }
}

impl UNIXSocket {
    pub fn new() -&gt; Result&lt;UNIXSocket, String&gt; {
        match unsafe { socket(AF_UNIX, SOCK_STREAM, 0) } {
            -1 =&gt; Err(errno_str()),
            fd @ _ =&gt; Ok(UNIXSocket { fd }),
        }
    }

    pub fn bind(self, address: &amp;str) -&gt; Result&lt;UNIXSocket, String&gt; {
        assert!(address.len() &lt; 104);

        let mut addr = sockaddr_un {
            sun_len: std::mem::size_of::&lt;sockaddr_un&gt;() as u8,
            sun_family: AF_UNIX as u8,
            sun_path: [0; 104],
        };

        for (i, c) in address.chars().enumerate() {
            addr.sun_path[i] = c as i8;
        }

        match unsafe {
            unlink(&amp;addr.sun_path as *const i8);
            bind(
                self.fd,
                &amp;addr as *const sockaddr_un as *const sockaddr,
                std::mem::size_of::&lt;sockaddr_un&gt;() as u32,
            )
        } {
            -1 =&gt; Err(errno_str()),
            _ =&gt; Ok(self),
        }
    }

    pub fn listen(self) -&gt; Result&lt;UNIXSocket, String&gt; {
        match unsafe { listen(self.fd, 50) } {
            -1 =&gt; Err(errno_str()),
            _ =&gt; Ok(self),
        }
    }

    pub fn accept(&amp;self) -&gt; Result&lt;UNIXConn, String&gt; {
        match unsafe { accept(self.fd, std::ptr::null_mut(), std::ptr::null_mut()) } {
            -1 =&gt; Err(errno_str()),
            fd @ _ =&gt; Ok(UNIXConn { fd }),
        }
    }
}</code></pre>
            <p>And the code to extract the file desciptor:</p>
            <pre><code>#[repr(C)]
pub struct ScmCmsgHeader {
    cmsg_len: c_uint,
    cmsg_level: c_int,
    cmsg_type: c_int,
    fd: c_int,
}

impl UNIXConn {
    pub fn recv_fd(&amp;self) -&gt; Result&lt;RawFd, String&gt; {
        let mut iov = iovec {
            iov_base: std::ptr::null_mut(),
            iov_len: 0,
        };

        let mut scm = ScmCmsgHeader {
            cmsg_len: 0,
            cmsg_level: 0,
            cmsg_type: 0,
            fd: 0,
        };

        let mut mhdr = msghdr {
            msg_name: std::ptr::null_mut(),
            msg_namelen: 0,
            msg_iov: &amp;mut iov as *mut iovec,
            msg_iovlen: 1,
            msg_control: &amp;mut scm as *mut ScmCmsgHeader as *mut c_void,
            msg_controllen: std::mem::size_of::&lt;ScmCmsgHeader&gt;() as u32,
            msg_flags: 0,
        };

        let n = unsafe { recvmsg(self.fd, &amp;mut mhdr, 0) };

        if n == -1
            || scm.cmsg_len as usize != std::mem::size_of::&lt;ScmCmsgHeader&gt;()
            || scm.cmsg_level != SOL_SOCKET
            || scm.cmsg_type != SCM_RIGHTS
        {
            Err("Invalid SCM message".to_string())
        } else {
            Ok(scm.fd)
        }
    }
}</code></pre>
            
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>SCM_RIGHTS is a very powerful tool that can be used for many purposes. In our case we used to to introduce a new service in a non-obtrusive fashion. Other uses may be:</p><ul><li><p>A/B testing</p></li><li><p>Phasing out of an old C based service in favor of new Go or Rust one</p></li><li><p>Passing connections from a privileged process to an unprivileged one</p></li></ul><p>And more</p><p>You can find the full example <a href="https://github.com/vkrasnov/scm_sample">here</a>.</p> ]]></content:encoded>
            <category><![CDATA[TLS 1.3]]></category>
            <category><![CDATA[TLS]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Linux]]></category>
            <category><![CDATA[TCP]]></category>
            <category><![CDATA[OpenSSL]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[NGINX]]></category>
            <guid isPermaLink="false">6FPYG7UeMVoKyzz6mA3tpB</guid>
            <dc:creator>Vlad Krasnov</dc:creator>
        </item>
        <item>
            <title><![CDATA[Graceful upgrades in Go]]></title>
            <link>https://blog.cloudflare.com/graceful-upgrades-in-go/</link>
            <pubDate>Thu, 11 Oct 2018 14:30:20 GMT</pubDate>
            <description><![CDATA[ The idea behind graceful upgrades is to swap out the configuration and code of a process while it is running, without anyone noticing it. If this sounds error-prone, dangerous, undesirable and in general a bad idea – I’m with you. ]]></description>
            <content:encoded><![CDATA[ <p><sup><i>Dingle Dangle! by </i></sup><a href="https://www.flickr.com/photos/grant_subaru/14175646490"><sup><i>Grant C.</i></sup></a><sup><i> (CC-BY 2.0)</i></sup></p><p>The idea behind graceful upgrades is to swap out the configuration and code of a process while it is running, without anyone noticing it. If this sounds error-prone, dangerous, undesirable and in general a bad idea – I’m with you. However, sometimes you really need them. Usually this happens in an environment where there is no load balancing layer. We have these at Cloudflare, which led to us investigating and implementing various solutions to this problem.</p><p>Coincidentally, implementing graceful upgrades involves some fun low-level systems programming, which is probably why there are already a bajillion options out there. Read on to learn what trade-offs there are, and why you should really use the Go library we are about to open source. For the impatient, the code is on <a href="https://github.com/cloudflare/tableflip">GitHub</a> and you can read the <a href="https://godoc.org/github.com/cloudflare/tableflip">documentation on godoc</a>.</p>
    <div>
      <h3>The basics</h3>
      <a href="#the-basics">
        
      </a>
    </div>
    <p>So what does it mean for a process to perform a graceful upgrade? Let’s use a web server as an example: we want to be able to fire HTTP requests at it, and never see an error because a graceful upgrade is happening.</p><p>We know that HTTP uses TCP under the hood, and that we interface with TCP using the BSD socket API. We have told the OS that we’d like to receive connections on port 80, and the OS has given us a listening socket, on which we call <code>Accept()</code> to wait for new clients.</p><p>A new client will be refused if the OS doesn’t know of a listening socket for port 80, or nothing is calling <code>Accept()</code> on it. The trick of a graceful upgrade is to make sure that neither of these two things occur while we somehow restart our service. Let’s look at the all the ways we could achieve this, from simple to complex.</p>
    <div>
      <h3>Just <code>Exec()</code></h3>
      <a href="#just-exec">
        
      </a>
    </div>
    <p>Ok, how hard can it be. Let’s just <code>Exec()</code> the new binary (without doing a fork first). This does exactly what we want, by replacing the currently running code with the new code from disk.</p>
            <pre><code>// The following is pseudo-Go.

func main() {
	var ln net.Listener
	if isUpgrade {
		ln = net.FileListener(os.NewFile(uintptr(fdNumber), "listener"))
	} else {
		ln = net.Listen(network, address)
	}
	
	go handleRequests(ln)

	&lt;-waitForUpgradeRequest

	syscall.Exec(os.Argv[0], os.Argv[1:], os.Environ())
}</code></pre>
            <p>Unfortunately this has a fatal flaw since we can’t “undo” the exec. Imagine a configuration file with too much white space in it or an extra semicolon. The new process would try to read that file, get an error and exit.</p><p>Even if the exec call works, this solution assumes that initialisation of the new process is practically instantaneous. We can get into a situation where the kernel refuses new connections because the <a href="https://veithen.github.io/2014/01/01/how-tcp-backlog-works-in-linux.html">listen queue is overflowing</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/46DpPmhtCjeHZmXVkySQTP/e644645ace6a5b37c1e0c4c09fc86814/Example1-1.png" />
            
            </figure><p><i>New connections may be dropped if </i><code><i>Accept()</i></code><i> is not called regularly enough</i></p><p>Specifically, the new binary is going to spend some time after <code>Exec()</code> to initialise, which delays calls to  <code>Accept()</code>. This means the backlog of new connections grows until some are dropped. Plain exec is out of the game.</p>
    <div>
      <h3><code>Listen()</code> all the things</h3>
      <a href="#listen-all-the-things">
        
      </a>
    </div>
    <p>Since just using exec is out of the question, we can try the next best thing. Lets fork and exec a new process which then goes through its usual start up routine. At some point it will create a few sockets by listening on some addresses, except that won’t work out-of-the-box due to errno 48, otherwise known as Address Already In Use. The kernel is preventing us from listening on the address and port combination used by the old process.</p><p>Of course, there is a flag to fix that: <code>SO_REUSEPORT</code>. This tells the kernel to ignore the fact that there is already a listening socket for a given address and port, and just allocate a new one.</p>
            <pre><code>func main() {
	ln := net.ListenWithReusePort(network, address)

	go handleRequests(ln)

	&lt;-waitForUpgradeRequest

	cmd := exec.Command(os.Argv[0], os.Argv[1:])
	cmd.Start()

	&lt;-waitForNewProcess
}</code></pre>
            <p>Now both processes have working listening sockets and the upgrade works. Right?</p><p><code>SO_REUSEPORT</code> is a little bit peculiar in what it does inside the kernel. As systems programmers, we tend to think of a socket as the file descriptor that is returned by the socket call. The kernel however makes a distinction between the data structure of a socket, and one or more file descriptors pointing at it. It creates a separate socket structure if you bind using <code>SO_REUSEPORT</code>, not just another file descriptor. The old and the new process are thus referring to two separate sockets, which happen to share the same address. This leads to an unavoidable race condition: new-but-not-yet-accepted connections on the socket used by the old process will be orphaned and terminated by the kernel. GitHub wrote <a href="https://githubengineering.com/glb-part-2-haproxy-zero-downtime-zero-delay-reloads-with-multibinder/#haproxy-almost-safe-reloads">an excellent blog post about this problem</a>.</p><p>The engineers at GitHub solved the problems with <code>SO_REUSEPORT</code> by using an obscure feature of the sendmsg syscall <a href="http://man7.org/linux/man-pages/man0/sys_socket.h.0p.html">called ancilliary data</a>. It turns out that ancillary data can include file descriptors. Using this API made sense for GitHub, since it allowed them to integrate elegantly with HAProxy. Since we have the luxury of changing the program we can use simpler alternatives.</p>
    <div>
      <h3>NGINX: share sockets via fork and exec</h3>
      <a href="#nginx-share-sockets-via-fork-and-exec">
        
      </a>
    </div>
    <p>NGINX is the tried and trusted workhorse of the Internet, and happens to support graceful upgrades. As a bonus we also use it at Cloudflare, so we were confident in its implementation.</p><p>It is written in a process-per-core model, which means that instead of spawning a bunch of threads NGINX runs a process per logical CPU core. Additionally, there is a primary process which orchestrates graceful upgrades.</p><p>The primary is responsible for creating all listen sockets used by NGINX and sharing them with the workers. This is fairly straightforward: first, the <code>FD_CLOEXEC</code> bit is cleared on all listen sockets. This means that they are not closed when the <code>exec()</code> syscall is made. The primary then does the customary <code>fork()</code> / <code>exec()</code> dance to spawn the workers, passing the file descriptor numbers as an environment variable.</p><p>Graceful upgrades make use of the same mechanism. We can spawn a new primary process (PID 1176) by <a href="http://nginx.org/en/docs/control.html#upgrade">following the NGINX documentation</a>. This inherits the existing listeners from the old primary process (PID 1017) just like workers do. The new primary then spawns its own workers:</p>
            <pre><code> CGroup: /system.slice/nginx.service
       	├─1017 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
       	├─1019 nginx: worker process
       	├─1021 nginx: worker process
       	├─1024 nginx: worker process
       	├─1026 nginx: worker process
       	├─1027 nginx: worker process
       	├─1028 nginx: worker process
       	├─1029 nginx: worker process
       	├─1030 nginx: worker process
       	├─1176 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
       	├─1187 nginx: worker process
       	├─1188 nginx: worker process
       	├─1190 nginx: worker process
       	├─1191 nginx: worker process
       	├─1192 nginx: worker process
       	├─1193 nginx: worker process
       	├─1194 nginx: worker process
       	└─1195 nginx: worker process</code></pre>
            <p>At this point there are two completely independent NGINX processes running. PID 1176 might be a new version of NGINX, or could use an updated config file. When a new connection arrives for port 80, one of the 16 worker processes is chosen by the kernel.</p><p>After executing the remaining steps, we end up with a fully replaced NGINX:</p>
            <pre><code>   CGroup: /system.slice/nginx.service
       	├─1176 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
       	├─1187 nginx: worker process
       	├─1188 nginx: worker process
       	├─1190 nginx: worker process
       	├─1191 nginx: worker process
       	├─1192 nginx: worker process
       	├─1193 nginx: worker process
       	├─1194 nginx: worker process
       	└─1195 nginx: worker process</code></pre>
            <p>Now, when a request arrives the kernel chooses between one of the eight remaining processes.</p><p>This process is rather fickle, so NGINX has a safeguard in place. Try requesting a second upgrade while the first hasn’t finished, and you’ll find the following message in the error log:</p>
            <pre><code>[crit] 1176#1176: the changing binary signal is ignored: you should shutdown or terminate before either old or new binary's process</code></pre>
            <p>This is very sensible, there is no good reason why there should be more than two processes at any given point in time. In the best case, we also want this behaviour from our Go solution.</p>
    <div>
      <h3>Graceful upgrade wishlist</h3>
      <a href="#graceful-upgrade-wishlist">
        
      </a>
    </div>
    <p>The way NGINX has implemented graceful upgrades is very nice. There is a clear life cycle which determines valid actions at any point in time:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/71WT8Hg8Bi4AAgf3yGdN8I/e30876bbf1c15d1e68143278b52f4bba/upgrade-lifecycle.svg" />
            
            </figure><p>It also solves the problems we’ve identified with the other approaches. Really, we’d like NGINX-style graceful upgrades as a Go library.</p><ul><li><p>No old code keeps running after a successful upgrade</p></li><li><p>The new process can crash during initialisation, without bad effects</p></li><li><p>Only a single upgrade is active at any point in time</p></li></ul><p>Of course, the Go community has produced some fine libraries just for this occasion. We looked at</p><ul><li><p><a href="https://github.com/alext/tablecloth">github.com/alext/tablecloth</a> (hat tip for the great name)</p></li><li><p><a href="https://godoc.org/github.com/astaxie/beego/grace">github.com/astaxie/beego/grace</a></p></li><li><p><a href="https://github.com/facebookgo/grace">github.com/facebookgo/grace</a></p></li><li><p><a href="https://github.com/crawshaw/littleboss">github.com/crawshaw/littleboss</a></p></li></ul><p>just to name a few. Each of them is different in its implementation and trade-offs, but none of them ticked all of our boxes. The most common problem is that they are designed to gracefully upgrade an http server. This makes their API much nicer, but removes flexibility that we need to support other socket based protocols. So really, there was absolutely no choice but to write our own library, called tableflip. Having fun was not part of the equation.</p>
    <div>
      <h3>tableflip</h3>
      <a href="#tableflip">
        
      </a>
    </div>
    <p>tableflip is a Go library for NGINX-style graceful upgrades. Here is what using it looks like:</p>
            <pre><code>upg, _ := tableflip.New(tableflip.Options{})
defer upg.Stop()

// Do an upgrade on SIGHUP
go func() {
    sig := make(chan os.Signal, 1)
    signal.Notify(sig, syscall.SIGHUP)
    for range sig {
   	    _ = upg.Upgrade()
    }
}()

// Start a HTTP server
ln, _ := upg.Fds.Listen("tcp", "localhost:8080")
server := http.Server{}
go server.Serve(ln)

// Tell the parent we are ready
_ = upg.Ready()

// Wait to be replaced with a new process
&lt;-upg.Exit()

// Wait for connections to drain.
server.Shutdown(context.TODO())</code></pre>
            <p>Calling <code>Upgrader.Upgrade</code> spawns a new process with the necessary net.Listeners, and waits for the new process to signal that it has finished initialisation, to die or to time out. Calling it when an upgrade is ongoing returns an error.</p><p><code>Upgrader.Fds.Listen</code> is inspired by <code>facebookgo/grace</code> and allows inheriting net.Listener easily. Behind the scenes, <code>Fds</code> makes sure that unused inherited sockets are cleaned up. This includes UNIX sockets, which are tricky due to <a href="https://golang.org/pkg/net/#UnixListener.SetUnlinkOnClose">UnlinkOnClose</a>. You can also pass straight up <code>*os.File</code> to the new process if you desire.</p><p>Finally, <code>Upgrader.Ready</code> cleans up unused fds and signals the parent process that initialisation is done. The parent can then exit, which completes the graceful upgrade cycle.</p> ]]></content:encoded>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Programming]]></category>
            <guid isPermaLink="false">7qaSxnaXNYj34tyA0WUanS</guid>
            <dc:creator>Lorenz Bauer</dc:creator>
        </item>
        <item>
            <title><![CDATA[Porting Our Software to ARM64]]></title>
            <link>https://blog.cloudflare.com/porting-our-software-to-arm64/</link>
            <pubDate>Sun, 02 Sep 2018 07:35:00 GMT</pubDate>
            <description><![CDATA[ As we enable more ARM64[1] machines in our network, I want to give some technical insight into the process we went through to reach software parity in our multi-architecture environment. ]]></description>
            <content:encoded><![CDATA[ <p>As we enable more ARM64<a href="#fn1">[1]</a> machines in our network, I want to give some technical insight into the process we went through to reach software parity in our multi-architecture environment.</p><p>To give some idea of the scale of this task, it’s necessary to describe the software stack we run on our servers. The foundation is the Linux kernel. Then, we use the Debian distribution as our base operating system. Finally, we install hundreds of packages that we build ourselves. Some packages are based on open-source software, often tailored to better meet our needs. Other packages were written from scratch within Cloudflare.</p><p>Industry support for ARM64 is very active, so a lot of open-source software has already been ported. This includes the Linux kernel. Additionally, Debian made ARM64 a <a href="https://wiki.debian.org/Arm64Port#Status">first-class release architecture starting with Stretch</a> in 2017. This meant that upon obtaining our ARM64 hardware, a few engineers were able to bring Debian up quickly and smoothly. Our attention then turned to getting all our in-house packages to build and run for ARM64.</p><p>Our stack uses a diverse range of programming languages, including C, C++, Go, Lua, Python, and Rust. Different languages have different porting requirements, with some being easier than others.</p>
    <div>
      <h3>Porting Go Code</h3>
      <a href="#porting-go-code">
        
      </a>
    </div>
    <p>Cross-compiling Go code is relatively simple, since <a href="https://github.com/golang/go/wiki/GoArm">ARM64 is a first-class citizen</a>. Go compiles and links static binaries using the system’s crossbuild toolchain, meaning the only additional Debian package we had to install on top of <code>build-essential</code> is <code>crossbuild-essential-arm64</code>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/35Jkf2QztHDpwjzR2x6hw3/3cee03287c46dca64e8ad270c54839d2/photo-1509815963-90cab26a868f" />
            
            </figure><p>Photo by <a href="https://unsplash.com/@tomcoe?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">tom coe</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></p><p>After installing the crossbuild toolchain, we then replaced every <code>go build</code> invocation with a loop of <code>GOARCH=&lt;arch&gt; CGO_ENABLED=1 go build</code>, where <code>&lt;arch&gt;</code> iterates through <code>amd64</code> and <code>arm64</code>. Forcing <code>CGO_ENABLED=1</code> is required, as <code>cgo</code> is <a href="https://github.com/golang/go/blob/8fbbf63cc61ffbb953a6d44649b644e4211c5d83/src/cmd/cgo/doc.go#L115-L124">disabled by default for cross-compilation</a>. The generated binaries are then run through our testing framework.</p>
    <div>
      <h3>Porting Rust Code</h3>
      <a href="#porting-rust-code">
        
      </a>
    </div>
    <p>Rust also has mature support for ARM64. The steps for porting start at installing <code>crossbuild-essential-arm64</code>, and defining the <code>--target</code> triple in either <code>rustc</code> or <code>cargo</code>. Different targets are bucketed into <a href="https://forge.rust-lang.org/platform-support.html">different tiers of completeness</a>. Full instructions are well-documented at <a href="https://github.com/japaric/rust-cross">rust-cross</a>.</p><p>One thing to note, however, is that any crates pulled in by a package must also be cross-compiled. The more crates used, the higher of a chance of running into one that does not cross-compile well.</p>
    <div>
      <h3>Testing, Plus Porting Other Code</h3>
      <a href="#testing-plus-porting-other-code">
        
      </a>
    </div>
    <p>Other languages are less cooperative when it comes to cross-compilation. Fiddling with <code>CC</code> and <code>LD</code> values didn’t seem to be best use of engineering resources. What we really wanted was an emulation layer. An emulation layer would leverage all of our <code>x86_64</code> machines, from our distributed compute behemoths to developers’ laptops, for the purposes of both building and testing code.</p><p>Enter QEMU.</p><p>QEMU is an emulator with multiple modes, including both full system emulation and user-space emulation. Our compute nodes are beefy enough to handle system-level emulation, but for developers’ laptops, user-space emulation provides most of the benefits, with less overhead.</p><p>For user-space emulation, our porting team did not want to intrude too much into our developers’ normal workflow. Our internal build system already uses Docker as a backend, so it would be ideal to be able to <code>docker run</code> into an ARM environment, like so:</p>
            <pre><code>host$ uname -m
x86_64
host$ docker run --rm -it stretch-arm64/master:latest
guest# uname -m
aarch64</code></pre>
            <p>Fortunately, we were not the first ones to come up with this idea: folks over at resin.io have <a href="https://resin.io/blog/building-arm-containers-on-any-x86-machine-even-dockerhub/">solved this problem already</a>! They’ve also submitted a <a href="https://patchwork.ozlabs.org/patch/582756/">patch to <code>qemu-user</code></a> that prepends the emulator into every <code>execve</code> call, similar to how <a href="https://www.kernel.org/doc/html/v4.14/admin-guide/binfmt-misc.html"><code>binfmt_misc</code> is implemented</a><a href="#fn2">[2]</a>. By prepending the emulator, you’re essentially forcing every new process to also be emulated, resulting in a nice self-contained environment.</p><p>With the <code>execve</code> patch in built into <code>qemu-user</code>, all we had to do was copy the emulator into an ARM64 container, and set the appropriate entrypoint:</p>
            <pre><code># internal build of qemu with patch
FROM qemu-aarch64/master:latest as qemu

# arm64v8/debian:stretch-slim at 2018-02-12T13:02:00Z
FROM arm64v8/debian@sha256:841bbe6f4132526be95c91bec6757831c76e603309a47992e6444de6a0b6521a

COPY --from=qemu /qemu-aarch64 /qemu-aarch64
SHELL ["/qemu-aarch64", "/bin/sh", "-c"]

# setcap is required for `sudo` to work, but breaks environment variable passing
# run `setcap -r /qemu-aarch64` to break sudo, but allow environment variable passing
# maybe one day we’ll have our cake and eat it too
RUN apt-get update &amp;&amp; apt-get install -y --no-install-recommends libcap2-bin &amp;&amp; \
    setcap cap_setuid,cap_setgid+ep /qemu-aarch64 &amp;&amp; \
    apt-get remove --purge -y libcap2-bin &amp;&amp; apt-get autoremove -y &amp;&amp; \
    rm -rf /var/lib/apt/lists/*

ENTRYPOINT ["/qemu-aarch64", "--execve", "/qemu-aarch64"]
CMD ["/bin/bash"]</code></pre>
            <p>This Dockerfile resulted in the cross-architecture output we were looking for earlier.</p><p>Now that we had a self-contained ARM64 environment, we could build and test most of our code relatively smoothly.</p>
    <div>
      <h3>Technical Gotchas</h3>
      <a href="#technical-gotchas">
        
      </a>
    </div>
    <p>Of course, there are always a few blockers on the road to perfection. Upon releasing this modified Debian image to our developers, they returned with a few interesting problems:</p><ul><li><p>tests were failing due to <code>LD_LIBRARY_PATH</code> not working</p></li><li><p>Go programs segfaulting at indeterminate intervals</p></li><li><p>system-installed libraries were taking precedence over user-installed libraries</p></li><li><p>slow builds and sporadic test case failures, speeding up our plan for native builds and CI</p></li></ul>
    <div>
      <h4>LD_LIBRARY_PATH and Friends</h4>
      <a href="#ld_library_path-and-friends">
        
      </a>
    </div>
    <p>It turns out that <code>LD_LIBRARY_PATH</code> was not the only environment variable that failed to work correctly. <i>All</i> environment variables, either set on the command line or via other means (e.g. <code>export</code>), would fail to propagate into the <code>qemu-user</code> process.</p><p>Through bisection of known good code, we found that it was the <code>setcap</code> in our Dockerfile which prevented the environment variable passthrough. Unfortunately, this <code>setcap</code> is the same one that allows us to call <code>sudo</code>, so we have a caveat for our developers that they can either run <code>sudo</code> inside their containers, or have environment variable passing, but not both.</p>
    <div>
      <h4>Intermittent Go Failures</h4>
      <a href="#intermittent-go-failures">
        
      </a>
    </div>
    <p>With a decent amount of Go code running through our CI system, it was easy to spot a trend of intermittent segfaults.</p><p>Going on a hunch, we confirmed a hypothesis that non-deterministic failures are generally due to threading issues. Unfortunately, opinion on <a href="https://github.com/golang/go/issues/20763">the issue tracker</a> showed that Go / QEMU incompatibilities aren’t a priority, so we were left without an upstream fix.</p><p>The workaround we came up with is simple: if the problem is threading-related, limit where the threads can run! When we package our internal <code>go</code> binaries, we add a <a href="https://gist.github.com/ahrex/9a84f32a33aadc197a688d2158d7e2ea"><code>.deb</code> post-install script</a> to detect if we’re running under ARM64 emulation, and if so, reduce the number of CPUs the <code>go</code> binary can run under to one. We lose performance by pinning to one CPU, but this slowdown is negligible when we’re already running under emulation, and slow code is better than non-working code.</p><p>With the workaround in place, reports of intermittent crashes dropped to zero. Onto the next problem!</p>
    <div>
      <h4>Shared Library Mixups</h4>
      <a href="#shared-library-mixups">
        
      </a>
    </div>
    <p>We like to be at the forefront of technology. From suggesting improvements to what would become TLS 1.3, to partnering with Mozilla to <a href="https://blog.nightly.mozilla.org/2018/08/28/firefox-nightly-secure-dns-experimental-results/">make DNS queries more secure</a>, and everything in between. To be able to support these new technologies, our software has to be at the cutting edge.</p><p>On the other hand, we also need a reliable platform to build on. One of the reasons we chose Debian is due to its long-term support lifecycle, versus other rolling release operating systems.</p><p>With these two ideas counterposed, we opted not to overwrite system libraries in <code>/usr/lib</code> with our cutting edge version, but instead supplement the defaults by installing into <code>/usr/local/lib</code>.</p><p>The same development team that reported the <code>LD_LIBRARY_PATH</code> issue also came to us saying the ARM64 version of their software would fail to load shared object symbols. A debugging session was launched and we eventually isolated it to the <a href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=685706">ordering of <code>/etc/ld.so.conf.d/</code> in Debian</a>.</p><p>Compare an <code>x86_64</code> machine:</p>
            <pre><code>$ uname -m
x86_64
$ ls /etc/ld.so.conf.d/
libc.conf  x86_64-linux-gnu.conf
$ cat /etc/ld.so.conf.d/libc.conf
# libc default configuration
/usr/local/lib
$ cat /etc/ld.so.conf.d/x86_64-linux-gnu.conf
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu</code></pre>
            <p>With an <code>arm64</code> machine:</p>
            <pre><code>$ uname -m
aarch64
$ ls /etc/ld.so.conf.d/
aarch64-linux-gnu.conf  libc.conf
$ cat /etc/ld.so.conf.d/aarch64-linux-gnu.conf
# Multiarch support
/lib/aarch64-linux-gnu
/usr/lib/aarch64-linux-gnu
$ cat /etc/ld.so.conf.d/libc.conf
# libc default configuration
/usr/local/lib</code></pre>
            <p>By traversing <code>/etc/ld.so.conf.d/</code> in alphabetical order, shared libraries in <code>/usr/local/lib</code> would be loaded before <code>/usr/lib/$(uname -m)-linux-gnu</code> on <code>x86_64</code>, while the opposite is true for <code>arm64</code>!</p><p>Internal discussion resulted in us not changing the system default search order, but instead use the <a href="https://en.wikipedia.org/wiki/Rpath">linker flag <code>--rpath</code></a> to request the runtime loader to explicitly search our <code>/usr/local/lib</code> location first.</p><p>This issue applies to both the emulated and physical ARM64 environments, which is a boon for the emulation framework we’ve just put together.</p>
    <div>
      <h4>Native Builds and CI</h4>
      <a href="#native-builds-and-ci">
        
      </a>
    </div>
    <p>Cross- and emulated compilation brought over 99% of our edge codebase, but there were still a handful of packages that did not fit the models we defined. Some packages, e.g. <code>llvm</code>, parallelize their build so well that the cost of userspace emulation slowed the build time to over 6 hours. Other packages called more esoteric functions which QEMU was not prepared to handle.</p><p>Rather than devote resources to emulating the long tail, we allocated a few ARM64 machines for developer access, and one machine for a native CI agent. Maintainers of the long tail could iterate in peace, knowing their failing test cases were never due to the emulation layer. When ready, CI would pick up their changes and build an official package, post-review.</p><p>While native compilation is the least error-prone build method, limited supply of machines made this option unattractive; the more machines we allocate for development and CI mean the more machines we take away from our proving grounds.</p><p>Ideally, we should follow the <a href="https://github.com/golang/go/issues/13024#issuecomment-164894790">Go team’s recommendation of running code natively</a>, but as long as our developers iterate on their <code>x86_64</code> laptops, supporting emulation is necessary for us.</p>
    <div>
      <h3>Other Challenges</h3>
      <a href="#other-challenges">
        
      </a>
    </div>
    <p>With the most glaring blockers out of the way, we have now given our developers an even footing to easily build for multiple architectures.</p><p>The rest of the time was spent coordinating over a hundred packages, split between dozens of tech teams. At the beginning, responsibility of building ARM64 packages laid on the porting team. Working on a changing codebase required close collaboration between maintainer and porter.</p><p>Once we deemed our ARM64 platform production-ready, a self-guided procedure was created to use the build methods listed above, and a request was sent out to all of engineering to support ARM64 as a first-class citizen.</p><p>The end result of our stack is currently being tested, profiled, and optimized, with results coming soon!</p><hr /><h6>Many more opportunities exist for systems integration, debugging deep dives, cross-team collaboration, and internal tools development. <a href="https://www.cloudflare.com/careers/">Come join us</a> if you’re interested!</h6><hr /><ol><li><p>ARM64 is sometimes used interchangeably with aarch64 and ARMv8 <a href="#fnref1">↩︎</a></p></li><li><p><code>binfmt_misc</code> is also what <a href="https://docs.docker.com/docker-for-mac/multi-arch/">Docker for Mac uses to leverage multi-architecture support</a>; we’re supporting something very similar, albeit from Linux to Linux, versus macOS to Linux. <a href="#fnref2">↩︎</a></p></li></ol> ]]></content:encoded>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Rust]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <guid isPermaLink="false">28OIXFL38zGjyvlunsoGOY</guid>
            <dc:creator>Alexander Huynh</dc:creator>
        </item>
        <item>
            <title><![CDATA[Copenhagen & London developers, join us for five events this May]]></title>
            <link>https://blog.cloudflare.com/copenhagen-london-developers/</link>
            <pubDate>Thu, 26 Apr 2018 05:32:00 GMT</pubDate>
            <description><![CDATA[ Are you based in Copenhagen or London? Drop by some talks we're hosting about the use of Go, Kubernetes, and Cloudflare’s Mobile SDK. ]]></description>
            <content:encoded><![CDATA[ <p></p><p>Photo by <a href="https://unsplash.com/@nickkarvounis?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Nick Karvounis</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></p><p>Are you based in Copenhagen or London? Drop by one or all of these five events.</p><p><a href="https://twitter.com/0xRLG">Ross Guarino</a> and <a href="https://twitter.com/terinjokes">Terin Stock</a>, both Systems Engineers at Cloudflare are traveling to Europe to lead Go and Kubernetes talks in Copenhagen. They'll then join <a href="https://twitter.com/IcyApril">Junade Ali</a> and lead talks on their use of Go, Kubernetes, and Cloudflare’s Mobile SDK at Cloudflare's London office.</p><p>My Developer Relations teammates and I are visiting these cities over the next two weeks to produce these events with Ross, Terin, and Junade. We’d love to meet you and invite you along.</p><p>Our trip will begin with two meetups and a conference talk in Copenhagen.</p>
    <div>
      <h3>Event #1 (Copenhagen): 6 Cloud Native Talks, 1 Evening: Special KubeCon + CloudNativeCon EU Meetup</h3>
      <a href="#event-1-copenhagen-6-cloud-native-talks-1-evening-special-kubecon-cloudnativecon-eu-meetup">
        
      </a>
    </div>
    
            <figure>
            <a href="https://www.meetup.com/GOTO-Nights-CPH/events/249895973/">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3PkIfrgFfKT97ZlXTCkM8N/b29595b25228a344e0c1b66c880d004f/GOTO.jpeg.jpeg" />
            </a>
            </figure><p><b>Tuesday, 1 May</b>: 17:00-21:00</p><p><b>Location</b>: <a href="https://trifork.com/">Trifork Copenhagen</a> - <a href="https://www.google.com/maps/place/Borgergade+24b,+1300+K%C3%B8benhavn,+Denmark/@55.684785,12.5840548,17z/data=!3m1!4b1!4m5!3m4!1s0x46525318dfb3b89d:0x855a7fb57181604f!8m2!3d55.684785!4d12.5862435">Borgergade 24B, 1300 København K</a></p><p>How to extend your Kubernetes cluster</p><p>A brief introduction to controllers, webhooks and CRDs. Ross and Terin will talk about how Cloudflare’s internal platform builds on Kubernetes.</p><p><b>Speakers</b>: Ross Guarino and Terin Stock</p><p><a href="https://www.meetup.com/GOTO-Nights-CPH/events/249895973/">View Event Details &amp; Register Here »</a></p>
    <div>
      <h3>Event #2 (Copenhagen): Gopher Meetup At Falcon.io: Building Go With Bazel &amp; Internationalization in Go</h3>
      <a href="#event-2-copenhagen-gopher-meetup-at-falcon-io-building-go-with-bazel-internationalization-in-go">
        
      </a>
    </div>
    
            <figure>
            <a href="https://www.meetup.com/Go-Cph/events/249830850/">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1YCo27Er0ncIR677a3eKFL/ae8b09422245f7c111d27f23607e16ff/Viking-Gopher.png" />
            </a>
            </figure><p><b>Wednesday, 2 May</b>: 18:00-21:00</p><p><b>Location</b>: <a href="https://www.falcon.io/">Falcon.io</a> - <a href="https://www.google.com/maps/place/H.+C.+Andersens+Blvd.+27,+1553+K%C3%B8benhavn,+Denmark/@55.674143,12.5629923,15z/data=!4m5!3m4!1s0x4652531251d1c86d:0xd1f236f0ffef562e!8m2!3d55.674143!4d12.571747">H.C. Andersen Blvd. 27, København</a></p><p>Talk 1: Building Go with Bazel</p><p>Fast and Reproducible go builds with Bazel. Learn how to remove Makefiles from your repositories.</p><p><b>Speaker</b>: Ross Guarino</p><p>Talk 2: Internationalization in Go</p><p>Explore making effective use of Go’s internationalization and localization packages and easily making your applications world-friendly.</p><p><b>Speaker</b>: Terin Stock</p><p><a href="https://www.meetup.com/Go-Cph/events/249830850/">View Event Details &amp; Register Here »</a></p>
    <div>
      <h3>Event #3 (Copenhagen): Controllers: Lambda Functions for Extending your Infrastructure at KubeCon + CloudNativeCon 2018</h3>
      <a href="#event-3-copenhagen-controllers-lambda-functions-for-extending-your-infrastructure-at-kubecon-cloudnativecon-2018">
        
      </a>
    </div>
    
            <figure>
            <a href="http://sched.co/DqwM">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6DfqqwLIbsg89kEglVpmNr/5ee34593d6192c6cdb9bb3bac21da2e9/Screen-Shot-2018-04-25-at-2.41.41-PM.png" />
            </a>
            </figure><p><b>Friday, 4 May</b>: 14:45-15:20</p><p><b>Location</b>: <a href="https://events.linuxfoundation.org/events/kubecon-cloudnativecon-europe-2018/">KubeCon + CloudNativeCon 2018</a> - <a href="https://www.google.com/maps/place/Bella+Center/@55.6385357,12.5433961,13z/data=!3m1!5s0x465254a4eeec0777:0x55f95a7fe9ed3f83!4m13!1m5!2m4!1sBella+Center,+Center+Blvd.+5,+2300+K%C3%B8benhavn!5m2!5m1!1s2018-04-27!3m6!1s0x465254a363269c3d:0x61db300fc92fb898!5m1!1s2018-04-27!8m2!3d55.6375044!4d12.5785932">Bella Center, Center Blvd. 5, 2300 København</a></p><p>If you happen to be attending <a href="https://events.linuxfoundation.org/events/kubecon-cloudnativecon-europe-2018/">KubeCon + CloudNativeCon 2018</a>, check out Terin and Ross’s conference talk as well.</p><p>This session demonstrates how to leverage Kubernetes Controllers and Initializers as a framework for building transparent extensions of your Kubernetes cluster. Using a live coding exercise and demo, this presentation will showcase the possibilities of the basic programming paradigms the Kubernetes API server makes easy.</p><p><b>Speakers</b>: Ross Guarino and Terin Stock</p><p><a href="http://sched.co/DqwM">View Event Details &amp; Register Here »</a></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5NWrQuZUZgMIy7uJZv0OWr/4fe475faee0e83937f10542f86e6bb4c/photo-1508808402998-ec38e4bf0fd0" />
            
            </figure><p>Photo by <a href="https://unsplash.com/@photobuffs?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Paul Buffington</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></p><p>When <a href="https://events.linuxfoundation.org/events/kubecon-cloudnativecon-europe-2018/">KubeCon + CloudNativeCon 2018</a> concludes, we're all heading to the Cloudflare London office where we are hosting two more meetups.</p>
    <div>
      <h3>Event #4 (London): Kubernetes Controllers: Lambda Functions for Extending your Infrastructure</h3>
      <a href="#event-4-london-kubernetes-controllers-lambda-functions-for-extending-your-infrastructure">
        
      </a>
    </div>
    
            <figure>
            <a href="https://kubernetes-controlers.eventbrite.com">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4RvxFZQ2Thh4N7J4zBOcSu/4c02fcfd43a2fd108b19fac3c0e5aab8/Cloudflare-London.jpg" />
            </a>
            </figure><p><b>Wednesday, 9 May</b>: 18:00-20:00</p><p><b>Location</b>: Cloudflare London - <a href="https://www.google.com/maps/place/25+Lavington+St,+London+SE1+0NZ,+UK/@51.5047963,-0.1024043,17z/data=!3m1!4b1!4m5!3m4!1s0x487604a8a2b9c4f1:0x1126c5560c56cc41!8m2!3d51.5047963!4d-0.1002156">25 Lavington St, Second floor | SE1 0NZ London</a></p><p>This session demonstrates how to leverage Kubernetes Controllers and Initializers as a framework for building transparent extensions of your Kubernetes cluster. Using a live coding exercise and demo, this presentation will showcase the possibilities of the basic programming paradigms the Kubernetes API server makes easy. As an SRE, learn to build custom integrations directly into the Kubernetes API that transparently enhance the developer experience.</p><p><b>Speakers</b>: Ross Guarino and Terin Stock</p><p><a href="https://kubernetes-controlers.eventbrite.com">View Event Details &amp; Register Here »</a></p>
    <div>
      <h3>Event #5 (London): Architecture for Network Failure, Developing for Mobile Performance</h3>
      <a href="#event-5-london-architecture-for-network-failure-developing-for-mobile-performance">
        
      </a>
    </div>
    
            <figure>
            <a href="https://mobilearchitectureandperformance.eventbrite.com">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/atA3RsFZPPZbbHcZKMhZW/1c5d56415e2513375ef5e6db50344910/Screen-Shot-2018-04-25-at-8.59.10-AM.png" />
            </a>
            </figure><p><b>Thursday, 10 May</b>: 18:00-20:00</p><p><b>Location</b>: Cloudflare London - <a href="https://www.google.com/maps/place/25+Lavington+St,+London+SE1+0NZ,+UK/@51.5047963,-0.1024043,17z/data=!3m1!4b1!4m5!3m4!1s0x487604a8a2b9c4f1:0x1126c5560c56cc41!8m2!3d51.5047963!4d-0.1002156">25 Lavington St, Second floor | SE1 0NZ London</a></p><p>Whether you're building an <a href="https://www.cloudflare.com/ecommerce/">e-commerce app</a> or a new mobile game, chances are you'll be needing some network functionality at some point when building a mobile app. Network performance can vary dramatically between carriers, networks, and APIs, but far too often mobile apps are tested inconsistent conditions with the same decent network performance. Fortunately we can iterate on our apps by collecting real-life performance measurements from your users; however, unfortunately existing mobile app analytics platforms only provide visibility into in-app performance but have no knowledge about outgoing network call.</p><p>This talk will cover how you can easily collect vital performance data from your users at no cost and then use this data to improve your apps' reliability and experience, discussing the tips and tricks needed to <a href="https://www.cloudflare.com/solutions/ecommerce/optimization/">boost app performance</a>.</p><p><b>Speaker</b>: Junade Ali</p><p><a href="https://mobilearchitectureandperformance.eventbrite.com">View Event Details &amp; Register Here »</a></p>
    <div>
      <h3>More About the Speakers</h3>
      <a href="#more-about-the-speakers">
        
      </a>
    </div>
    <p><a href="https://twitter.com/0xRLG">Ross Guarino</a> is a Systems Engineer at Cloudflare in charge of the technical direction of the internal platform. He’s determined to improve the lives of developers building and maintaining everything from a simple function to complex globally distributed systems.</p><p><a href="https://twitter.com/terinjokes">Terin Stock</a> is a long-time engineer at Cloudflare, currently working on building an internal Kubernetes cluster. By night, he hacks on building new hardware projects. Terin is also a member of <a href="https://gulpjs.com/">gulp.js</a> core team and the author of the <a href="https://github.com/terinjokes/StickersStandard">Sticker Standard</a>.</p><p><a href="https://twitter.com/IcyApril">Junade Ali</a> is a software engineer who is specialised in computer security and software architecture. Currently, Junade works at Cloudflare as a polymath, and helps make the Internet more secure and faster; prior to this, he was a technical lead at some of the UK's leading digital agencies before moving into architecting software for mission-critical road-safety systems.</p><p>We'll hope to meet you soon!</p> ]]></content:encoded>
            <category><![CDATA[Events]]></category>
            <category><![CDATA[Community]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[United Kingdom]]></category>
            <category><![CDATA[Kubernetes]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Mobile SDK]]></category>
            <category><![CDATA[Cloudflare Meetups]]></category>
            <category><![CDATA[MeetUp]]></category>
            <guid isPermaLink="false">4KmQqQHsaL4hmb1fHLo2VX</guid>
            <dc:creator>Andrew Fitch</dc:creator>
        </item>
        <item>
            <title><![CDATA[Using Go as a scripting language in Linux]]></title>
            <link>https://blog.cloudflare.com/using-go-as-a-scripting-language-in-linux/</link>
            <pubDate>Tue, 20 Feb 2018 19:49:17 GMT</pubDate>
            <description><![CDATA[ At Cloudflare we like Go. We use it in many in-house software projects as well as parts of bigger pipeline systems. But can we take Go to the next level and use it as a scripting language for our favourite operating system, Linux? ]]></description>
            <content:encoded><![CDATA[ <p>At Cloudflare we like Go. We use it in many <a href="/what-weve-been-doing-with-go/">in-house software projects</a> as well as parts of <a href="/meet-gatebot-a-bot-that-allows-us-to-sleep/">bigger pipeline systems</a>. But can we take Go to the next level and use it as a scripting language for our favourite operating system, Linux?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4xPPT6bpUh23aWgb47ugak/64a8b0f1ad6d51a000034829b8d26fd4/gopher-tux-1.png" />
            
            </figure><p><a href="https://golang.org/doc/gopher/gophercolor.png">gopher image</a> <a href="https://creativecommons.org/licenses/by/3.0/">CC BY 3.0</a> <a href="http://reneefrench.blogspot.com/">Renee French</a><a href="https://pixabay.com/en/linux-penguin-tux-2025536/">Tux image</a> <a href="https://creativecommons.org/publicdomain/zero/1.0/deed.en">CC0 BY</a> <a href="https://pixabay.com/en/users/OpenClipart-Vectors-30363/">OpenClipart-Vectors</a></p>
    <div>
      <h3>Why consider Go as a scripting language</h3>
      <a href="#why-consider-go-as-a-scripting-language">
        
      </a>
    </div>
    <p>Short answer: why not? Go is relatively easy to learn, not too verbose and there is a huge ecosystem of libraries which can be reused to avoid writing all the code from scratch. Some other potential advantages it might bring:</p><ul><li><p>Go-based build system for your Go project: <code>go build</code> command is mostly suitable for small, self-contained projects. More complex projects usually adopt some build system/set of scripts. Why not have these scripts written in Go then as well?</p></li><li><p>Easy non-privileged package management out of the box: if you want to use a third-party library in your script, you can simply <code>go get</code> it. And because the code will be installed in your <code>GOPATH</code>, getting a third-party library does not require administrative privileges on the system (unlike some other scripting languages). This is especially useful in large corporate environments.</p></li><li><p>Quick code prototyping on early project stages: when you're writing the first iteration of the code, it usually takes a lot of edits even to make it compile and you have to waste a lot of keystrokes on <i>"edit-&gt;build-&gt;check"</i> cycle. Instead you can skip the "build" part and just immediately execute your source file.</p></li><li><p>Strongly-typed scripting language: if you make a small typo somewhere in the middle of the script, most scripts will execute everything up to that point and fail on the typo itself. This might leave your system in an inconsistent state. With strongly-typed languages many typos can be caught at compile time, so the buggy script will not run in the first place.</p></li></ul>
    <div>
      <h3>Current state of Go scripting</h3>
      <a href="#current-state-of-go-scripting">
        
      </a>
    </div>
    <p>At first glance Go scripts seem easy to implement with Unix support of <a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">shebang lines</a> for scripts. A shebang line is the first line of the script, which starts with <code>#!</code> and specifies the script interpreter to be used to execute the script (for example, <code>#!/bin/bash</code> or <code>#!/usr/bin/env python</code>), so the system knows exactly how to execute the script regardless of the programming language used. And Go already supports interpreter-like invocation for <code>.go</code> files with <code>go run</code> command, so it should be just a matter of adding a proper shebang line, something like <code>#!/usr/bin/env go run</code>, to any <code>.go</code> file, setting the executable bit and we're good to go.</p><p>However, there are problems around using <code>go run</code> directly. <a href="https://gist.github.com/posener/73ffd326d88483df6b1cb66e8ed1e0bd">This great post</a> describes in detail all the issues around <code>go run</code> and potential workarounds, but the gist is:</p><ul><li><p><code>go run</code> does not properly return the script error code back to the operating system and this is important for scripts, because error codes are one of the most common ways multiple scripts interact with each other and the operating system environment.</p></li><li><p>you can't have a shebang line in a valid <code>.go</code> file, because Go does not know how to process lines starting with <code>#</code>. Other scripting languages do not have this problem, because for most of them <code>#</code> is a way to specify comments, so the final interpreter just ignores the shebang line, but Go comments start with <code>//</code> and <code>go run</code> on invocation will just produce an error like:</p></li></ul>
            <pre><code>package main:
helloscript.go:1:1: illegal character U+0023 '#'</code></pre>
            <p><a href="https://gist.github.com/posener/73ffd326d88483df6b1cb66e8ed1e0bd">The post</a> describes several workarounds for above issues including using a custom wrapper program <a href="https://github.com/erning/gorun">gorun</a> as an interpreter, but all of them do not provide an ideal solution. You either:</p><ul><li><p>have to use non-standard shebang line, which starts with <code>//</code>. This is technically not even a shebang line, but the way how <code>bash</code> shell processes executable text files, so this solution is <code>bash</code> specific. Also, because of the specific behaviour of <code>go run</code>, this line is rather complex and not obvious (see <a href="https://gist.github.com/posener/73ffd326d88483df6b1cb66e8ed1e0bd">original post</a> for examples).</p></li><li><p>have to use a custom wrapper program <a href="https://github.com/erning/gorun">gorun</a> in the shebang line, which works well, however, you end up with <code>.go</code> files, which are not compilable with standard <code>go build</code> command because of the illegal <code>#</code> character.</p></li></ul>
    <div>
      <h3>How Linux executes files</h3>
      <a href="#how-linux-executes-files">
        
      </a>
    </div>
    <p>OK, it seems the shebang approach does not provide us with an all-rounder solution. Is there anything else we could use? Let's take a closer look how Linux kernel executes binaries in the first place. When you try to execute a binary/script (or any file for that matter which has executable bit set), your shell in the end will just use Linux <code>execve</code> <a href="https://en.wikipedia.org/wiki/System_call">system call</a> passing it the filesystem path of the binary in question, command line parameters and currently defined environment variables. Then the kernel is responsible for correct parsing of the file and creating a new process with the code from the file. Most of us know that Linux (and many other Unix-like operating systems) use <a href="https://en.wikipedia.org/wiki/Executable_and_Linkable_Format">ELF binary format</a> for its executables.</p><p>However, one of the core principles of Linux kernel development is to avoid "vendor/format lock-in" for any subsystem, which is part of the kernel. Therefore, Linux implements a "pluggable" system, which allows any binary format to be supported by the kernel - all you have to do is to write a correct module, which can parse the format of your choosing. And if you take a closer look at the kernel source code, you'll see that Linux supports more binary formats out of the box. For example, for the recent <code>4.14</code> Linux kernel <a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs?h=linux-4.14.y">we can see</a> that it supports at least 7 binary formats (in-tree modules for various binary formats usually have <code>binfmt_</code> prefix in their names). It is worth to note the <a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/binfmt_script.c?h=linux-4.14.y">binfmt_script</a> module, which is responsible for parsing above mentioned shebang lines and executing scripts on the target system (not everyone knows that the shebang support is actually implemented in the kernel itself and not in the shell or other daemon/process).</p>
    <div>
      <h3>Extending supported binary formats from userspace</h3>
      <a href="#extending-supported-binary-formats-from-userspace">
        
      </a>
    </div>
    <p>But since we concluded that shebang is not the best option for our Go scripting, seems we need something else. Surprisingly Linux kernel already has a <a href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/fs/binfmt_misc.c?h=linux-4.14.y">"something else" binary support module</a>, which has an appropriate name <code>binfmt_misc</code>. The module allows an administrator to dynamically add support for various executable formats directly from userspace through a well-defined <code>procfs</code> interface and is <a href="https://www.kernel.org/doc/html/v4.14/admin-guide/binfmt-misc.html">well-documented</a>.</p><p>Let's follow <a href="https://www.kernel.org/doc/html/v4.14/admin-guide/binfmt-misc.html">the documentation</a> and try to setup a binary format description for <code>.go</code> files. First of all the guide tells you to mount special <code>binfmt_misc</code> filesystem to <code>/proc/sys/fs/binfmt_misc</code>. If you're using relatively recent systemd-based Linux distribution, it is highly likely the filesystem is already mounted for you, because systemd by default installs special <a href="https://github.com/systemd/systemd/blob/master/units/proc-sys-fs-binfmt_misc.mount">mount</a> and <a href="https://github.com/systemd/systemd/blob/master/units/proc-sys-fs-binfmt_misc.automount">automount</a> units for this purpose. To double-check just run:</p>
            <pre><code>$ mount | grep binfmt_misc
systemd-1 on /proc/sys/fs/binfmt_misc type autofs (rw,relatime,fd=27,pgrp=1,timeout=0,minproto=5,maxproto=5,direct)</code></pre>
            <p>Another way is to check if you have any files in <code>/proc/sys/fs/binfmt_misc</code>: properly mounted <code>binfmt_misc</code> filesystem will create at least two special files with names <code>register</code> and <code>status</code> in that directory.</p><p>Next, since we do want our <code>.go</code> scripts to be able to properly pass the exit code to the operating system, we need the custom <a href="https://github.com/erning/gorun">gorun</a> wrapper as our "interpreter":</p>
            <pre><code>$ go get github.com/erning/gorun
$ sudo mv ~/go/bin/gorun /usr/local/bin/</code></pre>
            <p>Technically we don't need to move <code>gorun</code> to <code>/usr/local/bin</code> or any other system path as <code>binfmt_misc</code> requires full path to the interpreter anyway, but the system may run this executable with arbitrary privileges, so it is a good idea to limit access to the file from security perspective.</p><p>At this point let's create a simple toy Go script <code>helloscript.go</code> and verify we can successfully "interpret" it. The script:</p>
            <pre><code>package main

import (
	"fmt"
	"os"
)

func main() {
	s := "world"

	if len(os.Args) &gt; 1 {
		s = os.Args[1]
	}

	fmt.Printf("Hello, %v!", s)
	fmt.Println("")

	if s == "fail" {
		os.Exit(30)
	}
}</code></pre>
            <p>Checking if parameter passing and error handling works as intended:</p>
            <pre><code>$ gorun helloscript.go
Hello, world!
$ echo $?
0
$ gorun helloscript.go gopher
Hello, gopher!
$ echo $?
0
$ gorun helloscript.go fail
Hello, fail!
$ echo $?
30</code></pre>
            <p>Now we need to tell <code>binfmt_misc</code> module how to execute our <code>.go</code> files with <code>gorun</code>. Following <a href="https://www.kernel.org/doc/html/v4.14/admin-guide/binfmt-misc.html">the documentation</a> we need this configuration string: <code>:golang:E::go::/usr/local/bin/gorun:OC</code>, which basically tells the system: "if you encounter an executable file with <code>.go</code> extension, please, execute it with <code>/usr/local/bin/gorun</code> interpreter". The <code>OC</code> flags at the end of the string make sure, that the script will be executed according to the owner information and permission bits set on the script itself, and not the ones set on the interpreter binary. This makes Go script execution behaviour same as the rest of the executables and scripts in Linux.</p><p>Let's register our new Go script binary format:</p>
            <pre><code>$ echo ':golang:E::go::/usr/local/bin/gorun:OC' | sudo tee /proc/sys/fs/binfmt_misc/register
:golang:E::go::/usr/local/bin/gorun:OC</code></pre>
            <p>If the system successfully registered the format, a new file <code>golang</code> should appear under <code>/proc/sys/fs/binfmt_misc</code> directory. Finally, we can natively execute our <code>.go</code> files:</p>
            <pre><code>$ chmod u+x helloscript.go
$ ./helloscript.go
Hello, world!
$ ./helloscript.go gopher
Hello, gopher!
$ ./helloscript.go fail
Hello, fail!
$ echo $?
30</code></pre>
            <p>That's it! Now we can edit <code>helloscript.go</code> to our liking and see the changes will be immediately visible the next time the file is executed. Moreover, unlike the previous shebang approach, we can compile this file any time into a real executable with <code>go build</code>.</p><hr /><p><i>Whether you like Go or digging in Linux internals, we have positions for either or these and even both of them at once. Check-out </i><a href="https://www.cloudflare.com/careers/"><i>our careers page.</i></a></p> ]]></content:encoded>
            <category><![CDATA[Linux]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Tech Talks]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Deep Dive]]></category>
            <guid isPermaLink="false">5Mg46SluRhqUD4mQaKqahI</guid>
            <dc:creator>Ignat Korchagin</dc:creator>
        </item>
        <item>
            <title><![CDATA[Go, don't collect my garbage]]></title>
            <link>https://blog.cloudflare.com/go-dont-collect-my-garbage/</link>
            <pubDate>Mon, 13 Nov 2017 10:31:09 GMT</pubDate>
            <description><![CDATA[ Not long ago I needed to benchmark the performance of Golang on a many-core machine. I took several of the benchmarks that are bundled with the Go source code, copied them, and modified them to run on all available threads. ]]></description>
            <content:encoded><![CDATA[ <p>Not long ago I needed to benchmark the performance of Golang on a many-core machine. I took several of the benchmarks that are bundled with the Go source code, copied them, and modified them to run on all available threads. In that case the machine has 24 cores and 48 threads.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1im9xk1mwSCF71CvOgrQYP/b7fef48c9fd09fe3fa09ff5b3bababfb/36963798223_b4da5151aa_k.jpg" />
            
            </figure><p><a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/147079914@N03/36963798223/in/photolist-ZhPe1A-Yjn8pV-ZhPcm3-YfT3xL-ZkG9kP-qLEURD-4rPJbB-uwsT5-9aWgeA-92n4h-5LWz68-92n6p-5gE7TJ-3Scj6p-duNYgz-4rTMKJ-8P3YZ3-8QLKYc-CHFrLH-MuQT2E">image</a> by <a href="https://www.flickr.com/photos/147079914@N03/">sponki25</a></p><p>I started with ECDSA P256 Sign, probably because I have warm feeling for that function, since I <a href="/go-crypto-bridging-the-performance-gap/">optimized it for amd64</a>.</p><p>First, I ran the benchmark on a single goroutine: <code>ECDSA-P256 Sign,30618.50, op/s</code></p><p>That looks good; next I ran it on 48 goroutines: <code>ECDSA-P256 Sign,78940.67, op/s</code>.</p><p>OK, that is not what I expected. Just over 2X speedup, from 24 physical cores? I must be doing something wrong. Maybe Go only uses two cores? I ran <code>top</code>, it showed 2,266% utilization. That is not the 4,800% I expected, but it is also way above 400%.</p><p>How about taking a step back, and running the benchmark on two goroutines? <code>ECDSA-P256 Sign,55966.40, op/s</code>. Almost double, so pretty good. How about four goroutines? <code>ECDSA-P256 Sign,108731.00, op/s.</code> That is actually faster than 48 goroutines, what is going on?</p><p>I ran the benchmark for every number of goroutines from 1 to 48:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4gTjIIpNxaG4OoM8U4M2V3/0e0c43feb83f2b1e462513ad930651a9/goroutines2.png" />
            
            </figure><p>Looks like the number of signatures per second peaks at 274,622, with 17 goroutines. And starts dropping rapidly after that.</p><p>Time to do some profiling.</p>
            <pre><code>(pprof) top 10
Showing nodes accounting for 47.53s, 50.83% of 93.50s total
Dropped 224 nodes (cum &lt;= 0.47s)
Showing top 10 nodes out of 138
      flat  flat%   sum%        cum   cum%
     9.45s 10.11% 10.11%      9.45s 10.11%  runtime.procyield /state/home/vlad/go/src/runtime/asm_amd64.s
     7.55s  8.07% 18.18%      7.55s  8.07%  runtime.futex /state/home/vlad/go/src/runtime/sys_linux_amd64.s
     6.77s  7.24% 25.42%     19.18s 20.51%  runtime.sweepone /state/home/vlad/go/src/runtime/mgcsweep.go
     4.20s  4.49% 29.91%     16.28s 17.41%  runtime.lock /state/home/vlad/go/src/runtime/lock_futex.go
     3.92s  4.19% 34.11%     12.58s 13.45%  runtime.(*mspan).sweep /state/home/vlad/go/src/runtime/mgcsweep.go
     3.50s  3.74% 37.85%     15.92s 17.03%  runtime.gcDrain /state/home/vlad/go/src/runtime/mgcmark.go
     3.20s  3.42% 41.27%      4.62s  4.94%  runtime.gcmarknewobject /state/home/vlad/go/src/runtime/mgcmark.go
     3.09s  3.30% 44.58%      3.09s  3.30%  crypto/elliptic.p256OrdSqr /state/home/vlad/go/src/crypto/elliptic/p256_asm_amd64.s
     3.09s  3.30% 47.88%      3.09s  3.30%  runtime.(*lfstack).pop /state/home/vlad/go/src/runtime/lfstack.go
     2.76s  2.95% 50.83%      2.76s  2.95%  runtime.(*gcSweepBuf).push /state/home/vlad/go/src/runtime/mgcsweepbuf.go</code></pre>
            <p>Clearly Go spends a disproportionate amount of time collecting garbage. All my benchmark does is generates signatures and then dumps them.</p><p>So what are our options? The Go runtime states the following:</p><blockquote><p>The GOGC variable sets the initial garbage collection target percentage. A collection is triggered when the ratio of freshly allocated data to live data remaining after the previous collection reaches this percentage. The default is GOGC=100. Setting GOGC=off disables the garbage collector entirely. The runtime/debug package's SetGCPercent function allows changing this percentage at run time. See <a href="https://golang.org/pkg/runtime/debug/#SetGCPercent">https://golang.org/pkg/runtime/debug/#SetGCPercent</a>.</p></blockquote><blockquote><p>The GODEBUG variable controls debugging variables within the runtime. It is a comma-separated list of name=val pairs setting these named variables:</p></blockquote><p>Let’s see what setting <code>GODEBUG</code> to <code>gctrace=1</code> does.</p>
            <pre><code>gc 1 @0.021s 0%: 0.15+0.37+0.25 ms clock, 3.0+0.19/0.39/0.60+5.0 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 2 @0.024s 0%: 0.097+0.94+0.16 ms clock, 0.29+0.21/1.3/0+0.49 ms cpu, 4-&gt;4-&gt;1 MB, 5 MB goal, 48 P
gc 3 @0.027s 1%: 0.10+0.43+0.17 ms clock, 0.60+0.48/1.5/0+1.0 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 4 @0.028s 1%: 0.18+0.41+0.28 ms clock, 0.18+0.69/2.0/0+0.28 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 5 @0.031s 1%: 0.078+0.35+0.29 ms clock, 1.1+0.26/2.0/0+4.4 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 6 @0.032s 1%: 0.11+0.50+0.32 ms clock, 0.22+0.99/2.3/0+0.64 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 7 @0.034s 1%: 0.18+0.39+0.27 ms clock, 0.18+0.56/2.2/0+0.27 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 8 @0.035s 2%: 0.12+0.40+0.27 ms clock, 0.12+0.63/2.2/0+0.27 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 9 @0.036s 2%: 0.13+0.41+0.26 ms clock, 0.13+0.52/2.2/0+0.26 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 10 @0.038s 2%: 0.099+0.51+0.20 ms clock, 0.19+0.56/1.9/0+0.40 ms cpu, 4-&gt;5-&gt;0 MB, 5 MB goal, 48 P
gc 11 @0.039s 2%: 0.10+0.46+0.20 ms clock, 0.10+0.23/1.3/0.005+0.20 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 12 @0.040s 2%: 0.066+0.46+0.24 ms clock, 0.93+0.40/1.7/0+3.4 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 13 @0.041s 2%: 0.099+0.30+0.20 ms clock, 0.099+0.60/1.7/0+0.20 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 14 @0.042s 2%: 0.095+0.45+0.24 ms clock, 0.38+0.58/2.0/0+0.98 ms cpu, 4-&gt;5-&gt;0 MB, 5 MB goal, 48 P
gc 15 @0.044s 2%: 0.095+0.45+0.21 ms clock, 1.0+0.78/1.9/0+2.3 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
gc 16 @0.045s 3%: 0.10+0.45+0.23 ms clock, 0.10+0.70/2.1/0+0.23 ms cpu, 4-&gt;5-&gt;0 MB, 5 MB goal, 48 P
gc 17 @0.046s 3%: 0.088+0.40+0.17 ms clock, 0.088+0.45/1.9/0+0.17 ms cpu, 4-&gt;4-&gt;0 MB, 5 MB goal, 48 P
.
.
.
.
gc 6789 @9.998s 12%: 0.17+0.91+0.24 ms clock, 0.85+1.8/5.0/0+1.2 ms cpu, 4-&gt;6-&gt;1 MB, 6 MB goal, 48 P
gc 6790 @10.000s 12%: 0.086+0.55+0.24 ms clock, 0.78+0.30/4.2/0.043+2.2 ms cpu, 4-&gt;5-&gt;1 MB, 6 MB goal, 48 P
</code></pre>
            <p>The first round of GC kicks in at 0.021s, then it starts collecting every 3ms and then every 1ms. That is insane, the benchmark runs for 10 seconds, and I saw 6,790 rounds of GC. The number that starts with @ is the time since program start, followed by a percentage that supposedly states the amount of time spent collecting garbage. This number is clearly misleading, because the performance indicates at least 90% of the time is wasted (indirectly) on GC, not 12%. The synchronization overhead is not taken into account. What really is interesting are the three numbers separated by arrows. They show the size of the heap at GC start, GC end, and the live heap size. Remember that a collection is triggered when the ratio of freshly allocated data to live data remaining after the previous collection reaches this percentage, and defaults to 100%.</p><p>I am running a benchmark, where all allocated data is immediately discarded, and collected at the next GC cycle. The only live heap is fixed to the Go runtime, and having more goroutines does not add to the live heap. In contrast the freshly allocated data grows much faster with each additional goroutine, triggering increasingly frequent, and expensive GC cycles.</p><p>Clearly what I needed to do next was to run the benchmark with the GC disabled, by setting <code>GOGC=off</code>. This lead to a dramatic improvement: <code>ECDSA-P256 Sign,413740.30, op/s</code>.</p><p>But still not the number I was looking for, and running an application without garbage collection is unsustainable in the long run. I started playing with the <code>GOGC</code> variable. First I set it to 2,400, which made sense since we have 24 cores, perhaps collecting garbage 24 times less frequently will do the trick: <code>ECDSA-P256 Sign,671538.90, op/s</code>, oh my that is getting better.</p><p>What if I tried 4,800, for the number of threads? <code>ECDSA-P256 Sign,685810.90, op/s</code>. Getting warmer.</p><p>I ran a script to find the best value, from 100 to 20,000, in increments of 100. This is what I got:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2zXh0sUUSQ5Qjuf9RaTPl1/226f072ccfc516fbe92dc0531d0bfa71/gogc.png" />
            
            </figure><p>Looks like the optimal value for <code>GOGC</code> in that case is 11,300 and it gets us 691,054 signatures/second. That is 22.56X times faster than the single core score, and overall pretty good for a 24 core processor. Remember that when running on a single core, the CPU frequency is 3.0GHz, and only 2.1GHz when running on all cores.</p><p>Per goroutine performance when running with <code>GOGC=11300</code> now looks like that:</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4Qjl1zChKIwSlMcLjVanpE/66d0e438bb5cd24ba15442ae0484e193/goroutines3.png" />
            
            </figure><p>The scaling looks much better, and even past 24 goroutines, when we run out of physical cores, and start sharing cores with hyper-threading, the overall performance improves.</p><p>The bottom line here is that although this type of benchmarking is definitely an edge case for garbage collection, where 48 threads allocate large amounts of short lived data, this situation can occur in real world scenarios. As many-core CPUs become a commodity, one should be aware of the pitfalls.</p><p>Most languages with garbage collection offer some sort of garbage collection control. Go has the GOGC variable, that can also be controlled with the SetGCPercent function in the runtime/debug package. Don't be afraid to tune the GC to suit your needs.</p><p>We're always looking for Go programmers, so if you found this blog post interesting, why not check out our <a href="https://www.cloudflare.com/careers/">jobs page</a>?</p> ]]></content:encoded>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Programming]]></category>
            <guid isPermaLink="false">mPdR2DMS30TQDNQOzb1He</guid>
            <dc:creator>Vlad Krasnov</dc:creator>
        </item>
        <item>
            <title><![CDATA[Cloudflare Wants to Buy Your Meetup Group Pizza]]></title>
            <link>https://blog.cloudflare.com/cloudflare-wants-to-buy-your-meetup-group-pizza/</link>
            <pubDate>Fri, 10 Nov 2017 15:00:00 GMT</pubDate>
            <description><![CDATA[ If you’re a web dev / devops / etc. meetup group that also works toward building a faster, safer Internet, I want to support your awesome group by buying you pizza.  ]]></description>
            <content:encoded><![CDATA[ <p></p><p>If you’re a web dev / devops / etc. meetup group that also works toward building a faster, safer Internet, I want to support your awesome group by buying you pizza. If your group’s focus falls within one of the subject categories below and you’re willing to give us a 30 second shout out and tweet a photo of your group and <a href="https://twitter.com/Cloudflare">@Cloudflare</a>, your meetup’s pizza expense will be reimbursed.</p><p><a href="https://docs.google.com/document/d/1wvJjiS1iuzf_XYNaah20xTwNfjcBQeiqjmrHi9CEFWM/edit?usp=sharing">Get Your Pizza $ Reimbursed »</a></p>
    <div>
      <h3>Developer Relations at Cloudflare &amp; why we’re doing this</h3>
      <a href="#developer-relations-at-cloudflare-why-were-doing-this">
        
      </a>
    </div>
    <p>I’m <a href="https://twitter.com/fitchaj">Andrew Fitch</a> and I work on the Developer Relations team at <a href="https://www.cloudflare.com/">Cloudflare</a>. One of the things I like most about working in DevRel is empowering community members who are already doing great things out in the world. Whether they’re starting conferences, hosting local meetups, or writing educational content, I think it’s important to support them in their efforts and reward them for doing what they do. Community organizers are the glue that holds developers together socially. Let’s support them and make their lives easier by taking care of the pizza part of the equation.</p>
            <figure>
            <a href="https://www.cloudflare.com/apps/">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2LFJE5nWDC74sln8mrtauZ/de98413ff1b6f611461c5c4649444c60/FingerPhotography-Cloudfare-8733.jpg" />
            </a>
            </figure>
    <div>
      <h4>What’s in it for Cloudflare?</h4>
      <a href="#whats-in-it-for-cloudflare">
        
      </a>
    </div>
    <ol><li><p>We want web developers to target the <a href="https://www.cloudflare.com/apps/">apps platform</a></p></li><li><p>We want more people to think about <a href="https://www.cloudflare.com/careers/">working at Cloudflare</a></p></li><li><p>Some people only know of <a href="https://www.cloudflare.com/">Cloudflare</a> as a CDN, but it’s actually a security company and does much more than that. General awareness helps tell the story of what Cloudflare is about.</p></li></ol>
    <div>
      <h4>What kinds of groups we most want to support</h4>
      <a href="#what-kinds-of-groups-we-most-want-to-support">
        
      </a>
    </div>
    <p>We want to work with groups that are closely aligned with Cloudflare, groups which focus on web development, web security, devops, or tech ops. We often work with language-specific meetups (such as Go London User Group) or diversity &amp; inclusion meetups (such as Women Who Code Portland). We’d also love to work with college student groups and any other coding groups which are focused on sharing technical knowledge with the community.</p><p>To get sponsored pizza, groups must be focused on...</p><ul><li><p>Web performance &amp; optimization</p></li><li><p>Front-end frameworks</p></li><li><p>Language-specific (JavaScript / PHP / Go / Lua / etc.)</p></li><li><p>Diversity &amp; inclusion meetups for web devs / devops / tech ops</p></li><li><p>Workshops / classes for web devs / devops / tech ops</p></li></ul>
    <div>
      <h4>How it works</h4>
      <a href="#how-it-works">
        
      </a>
    </div>
    <ol><li><p>Interested groups need to read our <a href="https://docs.google.com/document/d/1wvJjiS1iuzf_XYNaah20xTwNfjcBQeiqjmrHi9CEFWM/edit">Cloudflare Meetup Group Pizza Reimbursement Rules document</a>.</p></li><li><p>If the group falls within the requirements, the group should proceed to schedule their meetup and pull the <a href="https://docs.google.com/presentation/d/1afluXpf2eYeQ7SkmV2ONrojeZwosMTNifhnZR1chNTw/edit?usp=sharing">Cloudflare Introductory Slides</a> ahead of time.</p></li><li><p>At the event, an organizer should present the Cloudflare Introductory Slides at the beginning, giving us a 30 second shout out, and take a photo of the group in front of the slides. Someone from the group should Tweet the photo and @Cloudflare, so our Community Manager may retweet.</p></li><li><p>After the event, an organizer will need to fill out our <a href="https://docs.google.com/forms/d/e/1FAIpQLSe7iY-mjum-hfEtu8W08uf8e6H5IMDevRgCZ_YXtzaEwkLEag/viewform">reimbursement form</a> where they will upload a <a href="https://www.irs.gov/pub/irs-pdf/fw9.pdf">completed W-9</a>, their mailing address, group details, and the link to the Tweet.</p></li><li><p>Within a month, the organizer should have a check from Cloudflare (and some laptop stickers for their group, if they want) in their hands.</p></li></ol>
    <div>
      <h4>Here are some examples of groups we’ve worked with so far</h4>
      <a href="#here-are-some-examples-of-groups-weve-worked-with-so-far">
        
      </a>
    </div>
    <p><a href="https://www.meetup.com/preview/Go-London-User-Group"><b>Go London User Group (GLUG)</b></a></p>
            <figure>
            <a href="https://twitter.com/LondonGophers/status/920353032746995712">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4oWPqXK3ZLOH0BA3mbJO7M/ddc7337f74e01171d7e91655dfa35f0e/Screen-Shot-2017-11-01-at-2.32.00-PM.png" />
            </a>
            </figure><p>The Go London User Group is a London-based community for anyone interested in the Go programming language.</p><p>GLUG provides offline opportunities to:</p><ul><li><p>Discuss Go and related topics</p></li><li><p>Socialize with friendly people who are interested in Go</p></li><li><p>Find or fill Go-related jobs</p></li></ul><p>They want GLUG to be a diverse and inclusive community. As such all attendees, organizers and sponsors are required to follow the <a href="https://golang.org/conduct">community code of conduct</a>.</p><p>This group’s mission is very much in alignment with Cloudflare’s guidelines, so we sponsored the pizza for their <a href="https://www.meetup.com/preview/Go-London-User-Group/events/243800263">October Gophers</a> event.</p><p><a href="https://www.meetup.com/preview/Women-Who-Code-Portland"><b>Women Who Code Portland</b></a></p>
            <figure>
            <a href="https://twitter.com/superissarah/status/923370521684688896">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1t1S26RRHOCUC2b3YwEAMD/5aec722ff115aab5edbb7da5700bee35/Screen-Shot-2017-11-01-at-2.37.09-PM.png" />
            </a>
            </figure><p>Women Who Code’s mission statement</p><p>Women Who Code is a global nonprofit dedicated to inspiring women to excel in technology careers by creating a global, connected community of women in technology.</p><p>What they offer</p><ul><li><p>Monthly Networking Nights</p></li><li><p>Study Nights (JavaScript, React, DevOps, Design + Product, Algorithms)</p></li><li><p>Technical Workshops</p></li><li><p>Community Events (Hidden Figures screening, Women Who Strength Train, Happy Hours, etc.)</p></li><li><p>Free or discounted tickets to conferences</p></li></ul><p>Women Who Code are a great example of an inclusive technical group. Cloudflare reimbursed them for their pizza at their <a href="https://www.meetup.com/preview/Women-Who-Code-Portland/events/242929022">October JavaScript Study Night</a>.</p><p><a href="https://www.meetup.com/preview/PHX-Android"><b>GDG Phoenix / PHX Android</b></a></p>
            <figure>
            <a href="https://twitter.com/GDGPhoenix/status/924314879875465216">
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2PyMqJ00eEnGypcoxjmQST/878da7d678babf0a506f8ff099449db8/Screen-Shot-2017-11-01-at-2.41.46-PM.png" />
            </a>
            </figure><p>GDG Phoenix / PHX Android group is for anyone interested in Android design and development. All skill levels are welcome. Participants are welcome to the meet up to hang out and watch or be part of the conversation at events.</p><p>This group is associated with the <a href="https://developers.google.com/groups/">Google Developer Group</a> program and coordinate activities with the national organization. Group activities are not exclusively Android related, however, they can cover any technology.</p><p>Cloudflare sponsored their October event “<a href="https://www.meetup.com/preview/PHX-Android/events/242897401">How espresso works . . . Android talk with Michael Bailey</a>”.</p><hr /><p>I hope a lot of awesome groups around the world will take advantage of our offer. <b>Enjoy the pizza!</b></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5kKeJF3uYWwJyAkZ67TmQg/1f948496f05932879b8165e87730e456/giphy-downsized.gif" />
            
            </figure><p><a href="https://docs.google.com/document/d/1wvJjiS1iuzf_XYNaah20xTwNfjcBQeiqjmrHi9CEFWM/edit?usp=sharing">Get Your Pizza $ Reimbursed »</a></p><p>© 2017 Cloudflare, Inc. All rights reserved. The Cloudflare logo and marks are trademarks of Cloudflare. All other company and product names may be trademarks of the respective companies with which they are associated.</p> ]]></content:encoded>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[JavaScript]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[MeetUp]]></category>
            <category><![CDATA[Cloudflare Meetups]]></category>
            <category><![CDATA[Community]]></category>
            <guid isPermaLink="false">5luIi07exijfTyC4t91k0H</guid>
            <dc:creator>Andrew Fitch</dc:creator>
        </item>
        <item>
            <title><![CDATA[ARM Takes Wing:  Qualcomm vs. Intel CPU comparison]]></title>
            <link>https://blog.cloudflare.com/arm-takes-wing/</link>
            <pubDate>Wed, 08 Nov 2017 20:03:14 GMT</pubDate>
            <description><![CDATA[ One of the nicer perks I have here at Cloudflare is access to the latest hardware, long before it even reaches the market. Until recently I mostly played with Intel hardware.  ]]></description>
            <content:encoded><![CDATA[ <p>One of the nicer perks I have here at Cloudflare is access to the latest hardware, long before it even reaches the market.</p><p>Until recently I mostly played with Intel hardware. For example Intel supplied us with an engineering sample of their Skylake based Purley platform back in August 2016, to give us time to evaluate it and optimize our software. As a former Intel Architect, who did a lot of work on Skylake (as well as Sandy Bridge, Ivy Bridge and Icelake), I really enjoy that.</p><p>Our previous generation of servers was based on the Intel Broadwell micro-architecture. Our configuration includes dual-socket Xeons E5-2630 v4, with 10 cores each, running at 2.2GHz, with a 3.1GHz turboboost and hyper-threading enabled, for a total of 40 threads per server.</p><p>Since Intel was, and still is, the undisputed leader of the server CPU market with greater than 98% market share, our upgrade process until now was pretty straightforward: every year Intel releases a new generation of CPUs, and every year we buy them. In the process we usually get two extra cores per socket, and all the extra architectural features such upgrade brings: hardware AES and CLMUL in Westmere, AVX in Sandy Bridge, AVX2 in Haswell, etc.</p><p>In the current upgrade cycle, our next server processor ought to be the Xeon Silver 4116, also in a dual-socket configuration. In fact, we have already purchased a significant number of them. Each CPU has 12 cores, but it runs at a lower frequency of 2.1GHz, with 3.0GHz turboboost. It also has smaller last level cache: 1.375 MiB/core, compared to 2.5 MiB the Broadwell processors had. In addition, the Skylake based platform supports 6 memory channels and the AVX-512 instruction set.</p><p>As we head into 2018, however, change is in the air. For the first time in a while, Intel has serious competition in the server market: Qualcomm and Cavium both have new server platforms based on the ARMv8 64-bit architecture (aka aarch64 or arm64). Qualcomm has the Centriq platform (code name Amberwing), based on the Falkor core, and Cavium has the ThunderX2 platform, based on the ahm ... ThunderX2 core?</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2OerKvEoy4NXTwjEpDA1tY/d8d9c4dad28ab5bc7100710b3dcf644e/25704115174_061e907e57_o.jpg" />
            
            </figure><p>The majestic Amberwing powered by the Falkor CPU <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC BY-SA 2.0</a> <a href="https://www.flickr.com/photos/drphotomoto/25704115174/in/photolist-FaoiVy-oqK2j2-f6A8TL-6PTBkR-gRasf9-f2R2Hz-7bZeUp-fmxSzZ-o9fogQ-8evb42-f4tgSX-eGzXYi-6umTDd-8evd8H-gdCU2L-uhCbnz-fmxSsX-oxnuko-wb7in9-oqsJSH-uxxAS2-CzS4Eh-6y8KQA-brLjKf-YT2jrY-eGG5QJ-8pLnKt-8eyvgY-cnQqJs-fXYs9f-f2R2jK-28ahBA-fXYjkD-a9K25u-289gvW-PHrqDS-cmkggf-Ff9NXa-EhMcP4-f36dMm-289xP7-Ehrz1y-f2QZRZ-GqT3vt-uUeHBq-xUDQoa-ymMxE9-wWFi3q-MDva8W-8CWG5X">image</a> by <a href="https://www.flickr.com/photos/drphotomoto/">DrPhotoMoto</a></p><p>Recently, both Qualcomm and Cavium provided us with engineering samples of their ARM based platforms, and in this blog post I would like to share my findings about Centriq, the Qualcomm platform.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/4t48heslIVcJiaqGTuxwhl/a968a4b7f0a6a5dd25fc8481029db354/IMG_7222.jpg" />
            
            </figure><p>The actual Amberwing in question</p>
    <div>
      <h3>Overview</h3>
      <a href="#overview">
        
      </a>
    </div>
    <p>I tested the Qualcomm Centriq server, and compared it with our newest Intel Skylake based server and previous Broadwell based server.</p><table><tr><td><p><b>Platform</b></p></td><td><p><b>Grantley
(Intel)</b></p></td><td><p><b>Purley
(Intel)</b></p></td><td><p><b>Centriq
(Qualcomm)</b></p></td></tr><tr><td><p>Core</p></td><td><p>Broadwell</p></td><td><p>Skylake</p></td><td><p>Falkor</p></td></tr><tr><td><p>Process</p></td><td><p>14nm</p></td><td><p>14nm</p></td><td><p>10nm</p></td></tr><tr><td><p>Issue</p></td><td><p>8 µops/cycle</p></td><td><p>8 µops/cycle</p></td><td><p>8 instructions/cycle</p></td></tr><tr><td><p>Dispatch</p></td><td><p>4 µops/cycle</p></td><td><p>5 µops/cycle</p></td><td><p>4 instructions/cycle</p></td></tr><tr><td><p># Cores</p></td><td><p>10 x 2S + HT (40 threads)</p></td><td><p>12 x 2S + HT (48 threads)</p></td><td><p>46</p></td></tr><tr><td><p>Frequency</p></td><td><p>2.2GHz (3.1GHz turbo)</p></td><td><p>2.1GHz (3.0GHz turbo)</p></td><td><p>2.5 GHz</p></td></tr><tr><td><p>LLC</p></td><td><p>2.5 MB/core</p></td><td><p>1.35 MB/core</p></td><td><p>1.25 MB/core</p></td></tr><tr><td><p>Memory Channels</p></td><td><p>4</p></td><td><p>6</p></td><td><p>6</p></td></tr><tr><td><p>TDP</p></td><td><p>170W (85W x 2S)</p></td><td><p>170W (85W x 2S)</p></td><td><p>120W</p></td></tr><tr><td><p>Other features</p></td><td><p>AES
CLMUL
AVX2</p></td><td><p>AES
CLMUL
AVX512</p></td><td><p>AES
CLMUL
NEON
Trustzone
CRC32</p></td></tr></table><p>Overall on paper Falkor looks very competitive. In theory a Falkor core can process 8 instructions/cycle, same as Skylake or Broadwell, and it has higher base frequency at a lower TDP rating.</p>
    <div>
      <h3>Ecosystem readiness</h3>
      <a href="#ecosystem-readiness">
        
      </a>
    </div>
    <p>Up until now, a major obstacle to the deployment of ARM servers was lack, or weak, support by the majority of the software vendors. In the past two years, ARM’s enablement efforts have paid off, as most Linux distros, as well as most popular libraries support the 64-bit ARM architecture. Driver availability, however, is unclear at that point.</p><p>At Cloudflare, we run a complex software stack that consists of many integrated services, and running each of them efficiently is top priority.</p><p>On the edge we have the NGINX server software, that does support ARMv8. NGINX is written in C, and it also uses several libraries written in C, such as zlib and BoringSSL, therefore solid C compiler support is very important.</p><p>In addition, our flavor of NGINX is highly integrated with the <a href="https://github.com/openresty/lua-nginx-module">lua-nginx-module</a>, and we rely a lot on <a href="/pushing-nginx-to-its-limit-with-lua/">LuaJIT</a>.</p><p>Finally, a lot of our services, such as our DNS server, <a href="/what-weve-been-doing-with-go/#sts=RRDNS">RRDNS</a>, are written in Go.</p><p>The good news is that both gcc and clang not only support ARMv8 in general, but have optimization profiles for the Falkor core.</p><p>Go has official support for ARMv8 as well, and they improve the arm64 backend constantly.</p><p>As for LuaJIT, the stable version, 2.0.5 does not support ARMv8, but the beta version, 2.1.0 does. Let’s hope it gets out of beta soon.</p>
    <div>
      <h3>Benchmarks</h3>
      <a href="#benchmarks">
        
      </a>
    </div>
    
    <div>
      <h4>OpenSSL</h4>
      <a href="#openssl">
        
      </a>
    </div>
    <p>The first benchmark I wanted to perform, was OpenSSL version 1.1.1 (development version), using the bundled <code>openssl speed</code> tool. Although we recently switched to BoringSSL, I still prefer OpenSSL for benchmarking, because it has almost equally well optimized assembly code paths for both ARMv8 and the latest Intel processors.</p><p>In my opinion handcrafted assembly is the best measure of a CPU’s potential, as it bypasses the compiler bias.</p>
    <div>
      <h4>Public key cryptography</h4>
      <a href="#public-key-cryptography">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5jqlU0sjyAGrZaT2Y1x8JR/9fc0bccc931f0e8f8cbf1c8fcd2bdecf/pub_key_1_core-2.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/19nPDhEQXutllHbY08nO6O/0da82dc7260b6dbd732cc3cf79455ba8/pub_key_all_core-2.png" />
            
            </figure><p>Public key cryptography is all about raw ALU performance. It is interesting, but not surprising to see that in the single core benchmark, the Broadwell core is faster than Skylake, and both in turn are faster than Falkor. This is because Broadwell runs at a higher frequency, while architecturally it is not much inferior to Skylake.</p><p>Falkor is at a disadvantage here. First, in a single core benchmark, the turbo is engaged, meaning the Intel processors run at a higher frequency. Second, in Broadwell, Intel introduced two special instructions to accelerate big number multiplication: ADCX and ADOX. These perform two independent add-with-carry operations per cycle, whereas ARM can only do one. Similarly, the ARMv8 instruction set does not have a single instruction to perform 64-bit multiplication, instead it uses a pair of MUL and UMULH instructions.</p><p>Nevertheless, at the SoC level, Falkor wins big time. It is only marginally slower than Skylake at an RSA2048 signature, and only because RSA2048 does not have an optimized implementation for ARM. The <a href="https://www.cloudflare.com/learning/dns/dnssec/ecdsa-and-dnssec/">ECDSA</a> performance is ridiculously fast. A single Centriq chip can satisfy the ECDSA needs of almost any company in the world.</p><p>It is also very interesting to see Skylake outperform Broadwell by a 30% margin, despite losing the single core benchmark, and only having 20% more cores. This can be explained by more efficient all-core turbo, and improved hyper-threading.</p>
    <div>
      <h4>Symmetric key cryptography</h4>
      <a href="#symmetric-key-cryptography">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5c1gb11NBOBVq2PyFyxHIJ/05ddba2c522eecce2fe1fceca405c3ac/sym_key_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3HzScBUWaLPW2l7t0bvsuo/8c235d691f67a6fd9bbfe2176e3037d4/sym_key_all_core.png" />
            
            </figure><p>Symmetric key performance of the Intel cores is outstanding.</p><p>AES-GCM uses a combination of special hardware instructions to accelerate AES and CLMUL (carryless multiplication). Intel first introduced those instructions back in 2010, with their Westmere CPU, and every generation since they have improved their performance. ARM introduced a set of similar instructions just recently, with their 64-bit instruction set, and as an optional extension. Fortunately every hardware vendor I know of implemented those. It is very likely that Qualcomm will improve the performance of the cryptographic instructions in future generations.</p><p>ChaCha20-Poly1305 is a more generic algorithm, designed in such a way as to better utilize wide SIMD units. The Qualcomm CPU only has the 128-bit wide NEON SIMD, while Broadwell has 256-bit wide AVX2, and Skylake has 512-bit wide AVX-512. This explains the huge lead Skylake has over both in single core performance. In the all-cores benchmark the Skylake lead lessens, because it has to lower the clock speed when executing AVX-512 workloads. When executing AVX-512 on all cores, the base frequency goes down to just 1.4GHz---keep that in mind if you are mixing AVX-512 and other code.</p><p>The bottom line for symmetric crypto is that although Skylake has the lead, Broadwell and Falkor both have good enough performance for any real life scenario, especially considering the fact that on our edge, RSA consumes more CPU time than all the other crypto algorithms combined.</p>
    <div>
      <h3>Compression</h3>
      <a href="#compression">
        
      </a>
    </div>
    <p>The next benchmark I wanted to see was compression. This is for two reasons. First, it is a very important workload on the edge, as having better compression saves bandwidth, and helps deliver content faster to the client. Second, it is a very demanding workload, with a high rate of branch mispredictions.</p><p>Obviously the first benchmark would be the popular zlib library. At Cloudflare, we use an <a href="/cloudflare-fights-cancer/">improved version of the library</a>, optimized for 64-bit Intel processors, and although it is written mostly in C, it does use some Intel specific intrinsics. Comparing this optimized version to the generic zlib library wouldn’t be fair. Not to worry, with little effort I <a href="https://github.com/cloudflare/zlib/tree/vlad/aarch64">adapted the library</a> to work very well on the ARMv8 architecture, with the use of NEON and CRC32 intrinsics. In the process it is twice as fast as the generic library for some files.</p><p>The second benchmark is the emerging brotli library, it is written in C, and allows for a level playing field for all platforms.</p><p>All the benchmarks are performed on the HTML of <a href="/">blog.cloudflare.com</a>, in memory, similar to the way NGINX performs streaming compression. The size of the specific version of the HTML file is 29,329 bytes, making it a good representative of the type of files we usually compress. The parallel benchmark compresses multiple files in parallel, as opposed to compressing a single file on many threads, also similar to the way NGINX works.</p>
    <div>
      <h4>gzip</h4>
      <a href="#gzip">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2pi68sRQQHPJLXZO5vIbhW/72c6e8568f4d95e3e8d592dd72577ea8/gzip_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/S2VrG4fcrmbDUeOtJ453S/bbc5092e3565339bb7cb44ba7c8dd14d/gzip_all_core.png" />
            
            </figure><p>When using gzip, at the single core level Skylake is the clear winner. Despite having lower frequency than Broadwell, it seems that having lower penalty for branch misprediction helps it pull ahead. The Falkor core is not far behind, especially with lower quality settings. At the system level Falkor performs significantly better, thanks to the higher core count. Note how well gzip scales on multiple cores.</p>
    <div>
      <h4>brotli</h4>
      <a href="#brotli">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5LA2CLLkYa9iCe1eQzgs6x/1ff12aa354d80166407fe4f9fd538d78/brot_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1cuPwzCY4eJzgsOXmNrLXu/f7be60b7ac3497c13b3c0a2abe6ac522/brot_all_core.png" />
            
            </figure><p>With brotli on single core the situation is similar. Skylake is the fastest, but Falkor is not very much behind, and with quality setting 9, Falkor is actually faster. Brotli with quality level 4 performs very similarly to gzip at level 5, while actually compressing slightly better (8,010B vs 8,187B).</p><p>When performing many-core compression, the situation becomes a bit messy. For levels 4, 5 and 6 brotli scales very well. At level 7 and 8 we start seeing lower performance per core, bottoming with level 9, where we get less than 3x the performance of single core, running on all cores.</p><p>My understanding is that at those quality levels Brotli consumes significantly more memory, and starts thrashing the cache. The scaling improves again at levels 10 and 11.</p><p>Bottom line for brotli, Falkor wins, since we would not consider going above quality 7 for dynamic compression.</p>
    <div>
      <h3>Golang</h3>
      <a href="#golang">
        
      </a>
    </div>
    <p>Golang is another very important language for Cloudflare. It is also one of the first languages to offer ARMv8 support, so one would expect good performance. I used some of the built-in benchmarks, but modified them to run on multiple goroutines.</p>
    <div>
      <h4>Go crypto</h4>
      <a href="#go-crypto">
        
      </a>
    </div>
    <p>I would like to start the benchmarks with crypto performance. Thanks to OpenSSL we have good reference numbers, and it is interesting to see just how good the Go library is.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/64U9LsIbiAKp7Ut75mMmhj/c73c1142233e260e8733b079dac06ff8/go_pub_key_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5e9MFqm53p78KdB211Z8rZ/bc16992088b6aa826819bec645f99581/go_pub_key_all_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3TZyK91xQAJk4yfvYLnVjZ/c33931e0ead0f425c157746b9d637fc5/go_sym_key_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1S2LKr04vDIi1WrrZNaJn1/827505e17425e0521142cb397e209504/go_sym_key_all_core.png" />
            
            </figure><p>As far as Go crypto is concerned ARM and Intel are not even on the same playground. Go has very optimized assembly code for ECDSA, AES-GCM and Chacha20-Poly1305 on Intel. It also has Intel optimized math functions, used in RSA computations. All those are missing for ARMv8, putting it at a big disadvantage.</p><p>Nevertheless, the gap can be bridged with a relatively small effort, and we know that with the right optimizations, performance can be on par with OpenSSL. Even a very minor change, such as implementing the function <a href="https://go-review.googlesource.com/c/go/+/76270">addMulVVW</a> in assembly, lead to an over tenfold improvement in RSA performance, putting Falkor ahead of both Broadwell and Skylake, with 8,009 signatures/second.</p><p>Another interesting thing to note is that on Skylake, the Go Chacha20-Poly1305 code, that uses AVX2 performs almost identically to the OpenSSL AVX512 code, this is again due to AVX2 running at higher clock speeds.</p>
    <div>
      <h4>Go gzip</h4>
      <a href="#go-gzip">
        
      </a>
    </div>
    <p>Next in Go performance is gzip. Here again we have a reference point to pretty well optimized code, and we can compare it to Go. In the case of the gzip library, there are no Intel specific optimizations in place.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1GbKt2HcdJT5eNMdfsLw4d/7c55522afbfa58653a91c28479de8c3d/go_gzip_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/59TTlWALNqIkryEc7IwOnB/73ee80ab27313c3f55d3cb22c06b6704/go_gzip_all_core.png" />
            
            </figure><p>Gzip performance is pretty good. The single core Falkor performance is way below both Intel processors, but at the system level it manages to outperform Broadwell, and lags behind Skylake. Since we already know that Falkor outperforms both when C is used, it can only mean that Go’s backend for ARMv8 is still pretty immature compared to gcc.</p>
    <div>
      <h4>Go regexp</h4>
      <a href="#go-regexp">
        
      </a>
    </div>
    <p>Regexp is widely used in a variety of tasks, so its performance is quite important too. I ran the built-in benchmarks on 32KB strings.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2AhmqRQhO37Z03KXfz9PUk/9b39646f7e800c9a7c8565134d516815/go_regexp_easy_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/6PH0IDtvODvYcGbECgOvEt/fbb7c4a099ad2b478aa12b8f3b7fb0a0/go_regexp_easy_all_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/7eAhDauk00ZR4A37NPqQm5/8f1c94f9d34087b57b8672a4928e76a7/go_regexp_comp_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3ytsG1skhi4B1v24tqlrWw/d0d803c543a990854bd60916ed03b089/go_regexp_comp_all_core.png" />
            
            </figure><p>Go regexp performance is not very good on Falkor. In the medium and hard tests it takes second place, thanks to the higher core count, but Skylake is significantly faster still.</p><p>Doing some profiling shows that a lot of the time is spent in the function bytes.IndexByte. This function has an assembly implementation for amd64 (runtime.indexbytebody), but generic implementation for Go. The easy regexp tests spend most time in this function, which explains the even wider gap.</p>
    <div>
      <h4>Go strings</h4>
      <a href="#go-strings">
        
      </a>
    </div>
    <p>Another important library for a web server is the Go strings library. I only tested the basic Replacer class here.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/G20n7Ru5izVdUBOMM8af7/9a257ef47b5a38e3f745a22da7f36da5/go_str_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2W6GTABFY1t23YOIhyLc1A/ce51cb7081718a724b797f39e7ff80e2/go_str_all_core.png" />
            
            </figure><p>In this test again, Falkor lags behind, and loses even to Broadwell. Profiling shows significant time is spent in the function runtime.memmove. Guess what? It has a highly optimized assembly code for amd64, that uses AVX2, but only very simple ARM assembly, that copies 8 bytes at a time. By changing three lines in that code, and using the LDP/STP instructions (load pair/store pair) to copy 16 bytes at a time, I improved the performance of memmove by 30%, which resulted in 20% faster EscapeString and UnescapeString performance. And that is just scratching the surface.</p>
    <div>
      <h4>Go conclusion</h4>
      <a href="#go-conclusion">
        
      </a>
    </div>
    <p>Go support for aarch64 is quite disappointing. I am very happy to say that everything compiles and works flawlessly, but on the performance side, things should get better. Is seems like the enablement effort so far was concentrated on the compiler back end, and the library was left largely untouched. There are a lot of low hanging optimization fruits out there, like my 20-minute fix for <a href="https://go-review.googlesource.com/c/go/+/76270">addMulVVW</a> clearly shows. Qualcomm and other ARMv8 vendors intends to put significant engineering resources to amend this situation, but really anyone can contribute to Go. So if you want to leave your mark, now is the time.</p>
    <div>
      <h3>LuaJIT</h3>
      <a href="#luajit">
        
      </a>
    </div>
    <p>Lua is the glue that holds Cloudflare together.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/eTdeElawEbvCLpjM9XMUa/8527a83cf68acc1e6a48af94860b190c/luajit_1_core.png" />
            
            </figure>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/2ohY0uFyotdk0eJt9lU725/472f32803de7ecd6e2d95f27948aa85a/luajit_all_cores.png" />
            
            </figure><p>Except for the binary_trees benchmark, the performance of LuaJIT on ARM is very competitive. It wins two benchmarks, and is in almost a tie in a third one.</p><p>That being said, binary_trees is a very important benchmark, because it triggers many memory allocations and garbage collection cycles. It will require deeper investigation in the future.</p>
    <div>
      <h3>NGINX</h3>
      <a href="#nginx">
        
      </a>
    </div>
    <p>For the NGINX workload, I decided to generate a load that would resemble an actual server.</p><p>I set up a server that serves the HTML file used in the gzip benchmark, over https, with the ECDHE-ECDSA-AES128-GCM-SHA256 cipher suite.</p><p>It also uses LuaJIT to redirect the incoming request, remove all line breaks and extra spaces from the HTML file, while adding a timestamp. The HTML is then compressed using brotli with quality 5.</p><p>Each server was configured to work with as many workers as it has virtual CPUs. 40 for Broadwell, 48 for Skylake and 46 for Falkor.</p><p>As the client for this test, I used the <a href="https://github.com/rakyll/hey">hey</a> program, running from 3 Broadwell servers.</p><p>Concurrently with the test, we took power readings from the respective BMC units of each server.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/3d3OUyJ1m0q11IoWUNCyTp/5cde6f742d596d71d14e5f1355a4b570/nginx.png" />
            
            </figure><p>With the NGINX workload Falkor handled almost the same amount of requests as the Skylake server, and both significantly outperform Broadwell. The power readings, taken from the BMC show that it did so while consuming less than half the power of other processors. That means Falkor managed to get 214 requests/watt vs the Skylake’s 99 requests/watt and Broadwell’s 77.</p><p>I was a bit surprised to see Skylake and Broadwell consume about the same amount of power, given both are manufactured with the same process, and Skylake has more cores.</p><p>The low power consumption of Falkor is not surprising, Qualcomm processors are known for their great power efficiency, which has allowed them to be a dominant player in the mobile phone CPU market.</p>
    <div>
      <h2>Conclusion</h2>
      <a href="#conclusion">
        
      </a>
    </div>
    <p>The engineering sample of Falkor we got certainly impressed me a lot. This is a huge step up from any previous attempt at ARM based servers. Certainly core for core, the Intel Skylake is far superior, but when you look at the system level the performance becomes very attractive.</p><p>The production version of the Centriq SoC will feature up to 48 Falkor cores, running at a frequency of up to 2.6GHz, for a potential additional 8% better performance.</p><p>Obviously the Skylake server we tested is not the flagship Platinum unit that has 28 cores, but those 28 cores come both with a big price and over 200W TDP, whereas we are interested in improving our bang for buck metric, and performance per watt.</p><p>Currently, my main concern is weak Go language performance, but that is bound to improve quickly once ARM based servers start gaining some market share.</p><p>Both C and LuaJIT performance is very competitive, and in many cases outperforms the Skylake contender. In almost every benchmark Falkor shows itself as a worthy upgrade from Broadwell.</p><p>The largest win by far for Falkor is the low power consumption. Although it has a TDP of 120W, during my tests it never went above 89W (for the go benchmark). In comparison, Skylake and Broadwell both went over 160W, while the TDP of the two CPUs is 170W.</p><p><i>If you enjoy testing and selecting hardware on behalf of millions of Internet properties, come [join us](</i><a href="https://www.cloudflare.com/careers/"><i>https://www.cloudflare.com/careers/</i></a><i>).</i></p> ]]></content:encoded>
            <category><![CDATA[SSL]]></category>
            <category><![CDATA[OpenSSL]]></category>
            <category><![CDATA[Compression]]></category>
            <category><![CDATA[Speed & Reliability]]></category>
            <category><![CDATA[LUA]]></category>
            <category><![CDATA[Security]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Cryptography]]></category>
            <guid isPermaLink="false">3Rk7Ip66PBd0Hn31OM4NuO</guid>
            <dc:creator>Vlad Krasnov</dc:creator>
        </item>
        <item>
            <title><![CDATA[WHOIS going to be at the Grace Hopper Celebration?]]></title>
            <link>https://blog.cloudflare.com/ghc/</link>
            <pubDate>Tue, 03 Oct 2017 10:00:00 GMT</pubDate>
            <description><![CDATA[ Ubuntu us are doing the round trip! It’s time to live - WAN you arrive at GHC, come meet us and say HELO (we love GNU faces, we’ll be very api to meet you). When you’re exhausted like IPv4, git over to the Cloudflare corner to reboot. ]]></description>
            <content:encoded><![CDATA[ <p><a href="https://en.wikipedia.org/wiki/Ubuntu_(operating_system)">Ubuntu</a> us are doing the <a href="https://en.wikipedia.org/wiki/Round-trip_delay_time">round trip</a>! It’s <a href="https://en.wikipedia.org/wiki/Time_to_live">time to live</a> - <a href="https://en.wikipedia.org/wiki/Wide_area_network">WAN</a> you arrive at GHC, come meet us and say <a href="https://en.wikipedia.org/wiki/Simple_Mail_Transfer_Protocol">HELO</a> (we love <a href="https://en.wikipedia.org/wiki/GNU">GNU</a> faces, we’ll be very <a href="https://en.wikipedia.org/wiki/Application_programming_interface">api</a> to meet you). When you’re exhausted like <a href="https://en.wikipedia.org/wiki/IPv4">IPv4</a>, <a href="https://en.wikipedia.org/wiki/Git">git</a> over to the Cloudflare corner to reboot –– we’ll have chargers and Wi-Fi (it’s not a <a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol#CONNECTION-ESTABLISHMENT">SYN</a> to <a href="https://en.wikipedia.org/wiki/Representational_state_transfer">REST</a>). <a href="https://en.wikipedia.org/wiki/R_(programming_language)">R</a> booth can be your <a href="https://en.wikipedia.org/wiki/Esc_key">ESC</a>. Then Thursday morning <a href="https://www.eventbrite.com/e/grace-hopper-better-together-breakfast-sponsored-by-cloudflare-zendesk-tickets-38404240116">we’re hosting a breakfast</a> <a href="https://en.wikipedia.org/wiki/Bash_(Unix_shell)">bash</a> with Zendesk –– it will be quite the <a href="https://en.wikipedia.org/wiki/Assembly_language">Assembly</a>, you should definitely <a href="https://en.wikipedia.org/wiki/Go_(programming_language)">Go</a>,<a href="https://en.wikipedia.org/wiki/Compiler">compile</a> a bowl of <a href="https://en.wikipedia.org/wiki/Serial_communication">serial</a>, drink a <a href="https://en.wikipedia.org/wiki/Bit">bit</a> of <a href="https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing">CIDR</a> or a cup of <a href="https://en.wikipedia.org/wiki/Tee_(command)">tee</a>.</p><p>I’m also speaking at 1:30PM on Wednesday in OCCC W414 <a href="https://en.wikipedia.org/wiki/Cryptographic_hash_function">hashing</a> out encryption and updates for IoT –– <a href="https://en.wikipedia.org/wiki/Data_Encryption_Standard">DES</a> should be a fun <a href="https://en.wikipedia.org/wiki/Session_(computer_science)">session</a>.</p><p><a href="https://en.wikipedia.org/wiki/Transmission_Control_Protocol">ACK!</a> I did <a href="https://en.wikipedia.org/wiki/Network_address_translation">NAT</a> tell you how to find us. <a href="https://en.wikipedia.org/wiki/Checksum">Check for sum</a> women in capes a few <a href="https://en.wikipedia.org/wiki/Hop_(networking)">hops away</a> from the booths with the lava <a href="https://en.wikipedia.org/wiki/LAMP_(software_bundle)">LAMP</a> stack. I'm the one with <a href="https://en.wikipedia.org/wiki/CURL">cURLs</a>.</p><p>In <a href="https://en.wikipedia.org/wiki/D_(programming_language)">D</a> air! Excited to <a href="https://en.wikipedia.org/wiki/Local_area_network">LAN</a>d. <a href="https://en.wikipedia.org/wiki/C_(programming_language)">C</a> you soon.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/1tjItgsesKtLjcPjox0PI0/231114e3a4bc152a74ecc2b9f77a0534/gradient-Corgi.png" />
            
            </figure> ]]></content:encoded>
            <category><![CDATA[Events]]></category>
            <category><![CDATA[Grace Hopper]]></category>
            <category><![CDATA[API]]></category>
            <category><![CDATA[IPv4]]></category>
            <category><![CDATA[Go]]></category>
            <guid isPermaLink="false">6tkfLf5eLUToHtJa1JZTXr</guid>
            <dc:creator>Dani Grant</dc:creator>
        </item>
        <item>
            <title><![CDATA[Go Hack Nights at Cloudflare]]></title>
            <link>https://blog.cloudflare.com/go-hack-nights/</link>
            <pubDate>Sun, 01 Oct 2017 17:00:00 GMT</pubDate>
            <description><![CDATA[ Recently we launched an internal monthly Go Hack Night at our San Francisco office, open to anyone who works at Cloudflare regardless of their department or position.  ]]></description>
            <content:encoded><![CDATA[ <p>At Cloudflare we're extensively using the <a href="https://golang.org/">Go programming language</a> to build a better Internet. Go is a free and open source programming language created by Google in 2007 and open sourced in 2009. Earlier this year, Go made news when it entered the list of top 10 programming languages on the <a href="https://www.tiobe.com/tiobe-index/go/">TIOBE Index</a>.</p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/5hCaWYCUgyRkHAUTHVqxoD/bd0e22393405c711621296474dd4aa86/IMG_6782-pixelized.JPG.jpeg" />
            
            </figure><p>Recently we launched an internal monthly Go Hack Night at our San Francisco office, open to anyone who works at Cloudflare regardless of their department or position. Anyone from newbie programmers to our most experienced Go engineers are encouraged to attend, and experienced engineers are asked to throw on a mentor badge and help guide colleagues with installing and learning Go.</p><p>We had over 30 attendees at our inaugural Go Hack Night, and our survey reveals some great stats:</p><ul><li><p>26% of attendees were completely new to programming</p></li><li><p>61% of attendees were experienced in other languages but new to Go</p></li><li><p>Every attendee said they learned something!</p></li></ul><p>We actively encourage an inclusive learning culture and we're super excited to make the Go programming language more accessible to our entire company.</p><p>If you're interested in working with Go and helping to build a better Internet, <a href="https://www.cloudflare.com/careers/">we're hiring</a>!</p><p>P.S. if you're attending the <a href="https://ghc.anitaborg.org/2017-attend/">2017 Grace Hopper Celebration</a> this week, stop by the Cloudflare booth to say hello!</p> ]]></content:encoded>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Hackathon]]></category>
            <category><![CDATA[Developers]]></category>
            <category><![CDATA[Events]]></category>
            <guid isPermaLink="false">ScENo9yfkgQmkK8Gu4qWa</guid>
            <dc:creator>Ryan Djurovich</dc:creator>
        </item>
        <item>
            <title><![CDATA[The complete guide to Go net/http timeouts]]></title>
            <link>https://blog.cloudflare.com/the-complete-guide-to-golang-net-http-timeouts/</link>
            <pubDate>Wed, 29 Jun 2016 13:09:27 GMT</pubDate>
            <description><![CDATA[ When writing an HTTP server or client in Go, timeouts are amongst the easiest and most subtle things to get wrong: there’s many to choose from, and a mistake can have no consequences for a long time, until the network glitches and the process hangs. ]]></description>
            <content:encoded><![CDATA[ <p>When writing an HTTP server or client in Go, timeouts are amongst the easiest and most subtle things to get wrong: there’s many to choose from, and a mistake can have no consequences for a long time, until the network glitches and the process hangs.</p><p><a href="https://www.cloudflare.com/learning/ddos/glossary/hypertext-transfer-protocol-http/">HTTP</a> is a complex multi-stage protocol, so there's no one-size fits all solution to timeouts. Think about a <a href="https://www.cloudflare.com/learning/video/what-is-streaming/">streaming</a> endpoint versus a JSON API versus a <a href="https://en.wikipedia.org/wiki/Comet_%28programming%29">Comet</a> endpoint. Indeed, the defaults are often not what you want.</p><p>In this post I’ll take apart the various stages you might need to apply a timeout to, and look at the different ways to do it, on both the Server and the Client side.</p>
    <div>
      <h3>SetDeadline</h3>
      <a href="#setdeadline">
        
      </a>
    </div>
    <p>First, you need to know about the network primitive that Go exposes to implement timeouts: Deadlines.</p><p>Exposed by <a href="https://golang.org/pkg/net/#Conn"><code>net.Conn</code></a> with the <code>Set[Read|Write]Deadline(time.Time)</code> methods, Deadlines are an absolute time which when reached makes all I/O operations fail with a timeout error.</p><p><b>Deadlines are not timeouts.</b> Once set they stay in force forever (or until the next call to <code>SetDeadline</code>), no matter if and how the connection is used in the meantime. So to build a timeout with <code>SetDeadline</code> you'll have to call it before <i>every</i> <code>Read</code>/<code>Write</code> operation.</p><p>You probably don't want to call <code>SetDeadline</code> yourself, and let <code>net/http</code> call it for you instead, using its higher level timeouts. However, keep in mind that all timeouts are implemented in terms of Deadlines, so they <b>do NOT reset every time data is sent or received</b>.</p>
    <div>
      <h3>Server Timeouts</h3>
      <a href="#server-timeouts">
        
      </a>
    </div>
    <p><i>The </i><a href="/exposing-go-on-the-internet/"><i>"So you want to expose Go on the Internet" post</i></a><i> has more information on server timeouts, in particular about HTTP/2 and Go 1.7 bugs.</i></p>
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/sOlH0CkRueHYFHY9JhYag/3688eee879f10624eb42b75302000929/Timeouts-001.png" />
            
            </figure><p>It's critical for an HTTP server exposed to the Internet to enforce timeouts on client connections. Otherwise very slow or disappearing clients might leak file descriptors and eventually result in something along the lines of:</p>
            <pre><code>http: Accept error: accept tcp [::]:80: accept4: too many open files; retrying in 5ms</code></pre>
            <p>There are two timeouts exposed in <code>http.Server</code>: <code>ReadTimeout</code> and <code>WriteTimeout</code>. You set them by explicitly using a Server:</p>
            <pre><code>srv := &amp;http.Server{
    ReadTimeout: 5 * time.Second,
    WriteTimeout: 10 * time.Second,
}
log.Println(srv.ListenAndServe())</code></pre>
            <p><code>ReadTimeout</code> covers the time from when the connection is accepted to when the request body is fully read (if you do read the body, otherwise to the end of the headers). It's implemented in <code>net/http</code> by calling <code>SetReadDeadline</code> <a href="https://github.com/golang/go/blob/3ba31558d1bca8ae6d2f03209b4cae55381175b3/src/net/http/server.go#L750">immediately after Accept</a>.</p><p><code>WriteTimeout</code> normally covers the time from the end of the request header read to the end of the response write (a.k.a. the lifetime of the ServeHTTP), by calling <code>SetWriteDeadline</code> <a href="https://github.com/golang/go/blob/3ba31558d1bca8ae6d2f03209b4cae55381175b3/src/net/http/server.go#L753-L755">at the end of readRequest</a>.</p><p>However, when the connection is <a href="https://www.cloudflare.com/learning/ssl/what-is-https/">HTTPS</a>, <code>SetWriteDeadline</code> is called <a href="https://github.com/golang/go/blob/3ba31558d1bca8ae6d2f03209b4cae55381175b3/src/net/http/server.go#L1477-L1483">immediately after Accept</a> so that it also covers the packets written as part of the TLS handshake. Annoyingly, this means that (in that case only) <code>WriteTimeout</code> ends up including the header read and the first byte wait.</p><p>You should set both timeouts when you deal with untrusted clients and/or networks, so that a client can't hold up a connection by being slow to write or read.</p><p>Finally, there's <a href="https://golang.org/pkg/net/http/#TimeoutHandler"><code>http.TimeoutHandler</code></a>. It’s not a Server parameter, but a Handler wrapper that limits the maximum duration of <code>ServeHTTP</code> calls. It works by buffering the response, and sending a <i>504 Gateway Timeout</i> instead if the deadline is exceeded. Note that it is <a href="https://github.com/golang/go/issues/15327">broken in 1.6 and fixed in 1.6.2</a>.</p>
    <div>
      <h4>http.ListenAndServe is doing it wrong</h4>
      <a href="#http-listenandserve-is-doing-it-wrong">
        
      </a>
    </div>
    <p>Incidentally, this means that the package-level convenience functions that bypass <code>http.Server</code> like <code>http.ListenAndServe</code>, <code>http.ListenAndServeTLS</code> and <code>http.Serve</code> are unfit for public Internet servers.</p><p>Those functions leave the Timeouts to their default off value, with no way of enabling them, so if you use them you'll soon be leaking connections and run out of file descriptors. I've made this mistake at least half a dozen times.</p><p>Instead, create a <code>http.Server</code> instance with ReadTimeout and WriteTimeout and use its corresponding methods, like in the example a few paragraphs above.</p>
    <div>
      <h4>About streaming</h4>
      <a href="#about-streaming">
        
      </a>
    </div>
    <p>Very annoyingly, there is no way of accessing the underlying <code>net.Conn</code> from <code>ServeHTTP</code> so a server that intends to stream a response is forced to unset the <code>WriteTimeout</code> (which is also possibly why they are 0 by default). This is because without <code>net.Conn</code> access, there is no way of calling <code>SetWriteDeadline</code> before each <code>Write</code> to implement a proper idle (not absolute) timeout.</p><p>Also, there's no way to cancel a blocked <code>ResponseWriter.Write</code> since <code>ResponseWriter.Close</code> (which you can access via an interface upgrade) is not documented to unblock a concurrent Write. So there's no way to build a timeout manually with a Timer, either.</p><p>Sadly, this means that streaming servers can't really defend themselves from a slow-reading client.</p><p>I submitted <a href="https://github.com/golang/go/issues/16100">an issue with some proposals</a>, and I welcome feedback there.</p>
    <div>
      <h3>Client Timeouts</h3>
      <a href="#client-timeouts">
        
      </a>
    </div>
    
            <figure>
            
            <img src="https://cf-assets.www.cloudflare.com/zkvhlag99gkb/255U6cjjLCH1vUEJoA9QWo/b73eae7e11ea4e42c847a5ee9c9c8f96/Timeouts-002.png" />
            
            </figure><p>Client-side timeouts can be simpler or much more complex, depending which ones you use, but are just as important to prevent leaking resources or getting stuck.</p><p>The easiest to use is the <code>Timeout</code> field of <a href="https://golang.org/pkg/net/http/#Client"><code>http.Client</code></a>. It covers the entire exchange, from Dial (if a connection is not reused) to reading the body.</p>
            <pre><code>c := &amp;http.Client{
    Timeout: 15 * time.Second,
}
resp, err := c.Get("https://blog.filippo.io/")</code></pre>
            <p>Like the server-side case above, the package level functions such as <code>http.Get</code> use <a href="https://golang.org/pkg/net/http/#DefaultClient">a Client without timeouts</a>, so are dangerous to use on the open Internet.</p><p>For more granular control, there are a number of other more specific timeouts you can set:</p><ul><li><p><code>net.Dialer.Timeout</code> limits the time spent establishing a TCP connection (if a new one is needed).</p></li><li><p><code>http.Transport.TLSHandshakeTimeout</code> limits the time spent performing the TLS handshake.</p></li><li><p><code>http.Transport.ResponseHeaderTimeout</code> limits the time spent reading the headers of the response.</p></li><li><p><code>http.Transport.ExpectContinueTimeout</code> limits the time the client will wait between sending the request headers <i>when including an </i><code><i>Expect: 100-continue</i></code> and receiving the go-ahead to send the body. Note that setting this in 1.6 <a href="https://github.com/golang/go/issues/14391">will disable HTTP/2</a> (<code>DefaultTransport</code> <a href="https://github.com/golang/go/commit/406752b640fcc56a9287b8454564cffe2f0021c1#diff-6951e7593bfb1e773c9121df44df1c36R179">is special-cased from 1.6.2</a>).</p></li></ul>
            <pre><code>c := &amp;http.Client{
    Transport: &amp;http.Transport{
        Dial: (&amp;net.Dialer{
                Timeout:   30 * time.Second,
                KeepAlive: 30 * time.Second,
        }).Dial,
        TLSHandshakeTimeout:   10 * time.Second,
        ResponseHeaderTimeout: 10 * time.Second,
        ExpectContinueTimeout: 1 * time.Second,
    }
}</code></pre>
            <p>As far as I can tell, there's no way to limit the time spent sending the request specifically. The time spent reading the request body can be controlled manually with a <code>time.Timer</code> since it happens after the Client method returns (see below for how to cancel a request).</p><p>Finally, new in 1.7, there's <code>http.Transport.IdleConnTimeout</code>. It does not control a blocking phase of a client request, but how long an idle connection is kept in the connection pool.</p><p>Note that a Client will follow redirects by default. <code>http.Client.Timeout</code> includes all time spent following redirects, while the granular timeouts are specific for each request, since <code>http.Transport</code> is a lower level system that has no concept of redirects.</p>
    <div>
      <h4>Cancel and Context</h4>
      <a href="#cancel-and-context">
        
      </a>
    </div>
    <p><code>net/http</code> offers two ways to cancel a client request: <code>Request.Cancel</code> and, new in 1.7, Context.</p><p><code>Request.Cancel</code> is an optional channel that when set and then closed causes the request to abort as if the <code>Request.Timeout</code> had been hit. (They are actually implemented through the same mechanism, and while writing this post I <a href="https://github.com/golang/go/issues/16094">found a bug</a> in 1.7 where all cancellations would be returned as timeout errors.)</p><p>We can use <code>Request.Cancel</code> and <code>time.Timer</code> to build a more granular timeout that allows streaming, pushing the deadline back every time we successfully read some data from the Body:</p>
            <pre><code>package main

import (
	"io"
	"io/ioutil"
	"log"
	"net/http"
	"time"
)

func main() {
	c := make(chan struct{})
	timer := time.AfterFunc(5*time.Second, func() {
		close(c)
	})

        // Serve 256 bytes every second.
	req, err := http.NewRequest("GET", "http://httpbin.org/range/2048?duration=8&amp;chunk_size=256", nil)
	if err != nil {
		log.Fatal(err)
	}
	req.Cancel = c

	log.Println("Sending request...")
	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		log.Fatal(err)
	}
	defer resp.Body.Close()

	log.Println("Reading body...")
	for {
		timer.Reset(2 * time.Second)
                // Try instead: timer.Reset(50 * time.Millisecond)
		_, err = io.CopyN(ioutil.Discard, resp.Body, 256)
		if err == io.EOF {
			break
		} else if err != nil {
			log.Fatal(err)
		}
	}
}</code></pre>
            <p>In the example above, we put a timeout of 5 seconds on the Do phases of the request, but then we spend at least 8 seconds reading the body in 8 rounds, each time with a timeout of 2 seconds. We could go on streaming like this forever without risk of getting stuck. If we were not to receive body data for more than 2 seconds, then io.CopyN would return <code>net/http: request canceled</code>.</p><p>In 1.7 the <code>context</code> package graduated to the standard library. There's <a href="https://blog.golang.org/context">a lot to learn about Contexts</a>, but for our purposes you should know that they replace and deprecate <code>Request.Cancel</code>.</p><p>To use Contexts to cancel a request we just obtain a new Context and its <code>cancel()</code> function with <code>context.WithCancel</code> and create a Request bound to it with <code>Request.WithContext</code>. When we want to cancel the request, we cancel the Context by calling <code>cancel()</code> (instead of closing the Cancel channel):</p>
            <pre><code>ctx, cancel := context.WithCancel(context.TODO())
timer := time.AfterFunc(5*time.Second, func() {
	cancel()
})

req, err := http.NewRequest("GET", "http://httpbin.org/range/2048?duration=8&amp;chunk_size=256", nil)
if err != nil {
	log.Fatal(err)
}
req = req.WithContext(ctx)</code></pre>
            <p>Contexts have the advantage that if the parent context (the one we passed to <code>context.WithCancel</code>) is canceled, ours will be, too, propagating the command down the entire pipeline.</p><p>This is all. I hope I didn't exceed your <code>ReadDeadline</code>!</p><p>If this kind of deep dive into the Go standard libraries sound entertaining to you, know that <a href="https://www.cloudflare.com/join-our-team/">we are hiring in London, Austin (TX), Champaign (IL), San Francisco and Singapore.</a></p> ]]></content:encoded>
            <category><![CDATA[Reliability]]></category>
            <category><![CDATA[API]]></category>
            <category><![CDATA[Programming]]></category>
            <category><![CDATA[Go]]></category>
            <guid isPermaLink="false">5IUTFQotCX6VHDqnrENjnx</guid>
            <dc:creator>Filippo Valsorda</dc:creator>
        </item>
        <item>
            <title><![CDATA[Building the simplest Go static analysis tool]]></title>
            <link>https://blog.cloudflare.com/building-the-simplest-go-static-analysis-tool/</link>
            <pubDate>Wed, 27 Apr 2016 15:01:15 GMT</pubDate>
            <description><![CDATA[ Go native vendoring (a.k.a. GO15VENDOREXPERIMENT) allows you to freeze dependencies by putting them in a vendor folder in your project. The compiler will then look there before searching the GOPATH. ]]></description>
            <content:encoded><![CDATA[ <p><a href="https://docs.google.com/document/d/1Bz5-UB7g2uPBdOx-rw5t9MxJwkfpx90cqG9AFL0JAYo/edit">Go native vendoring</a> (a.k.a. GO15VENDOREXPERIMENT) allows you to freeze dependencies by putting them in a <code>vendor</code> folder in your project. The compiler will then look there before searching the GOPATH.</p><p>The only annoyance compared to using a per-project GOPATH, which is what we used to do, is that you might forget to vendor a package that you have in your GOPATH. The program will build for you, but it won't for anyone else. Back to the <a href="https://www.urbandictionary.com/define.php?term=wfm">WFM</a> times!</p><p>I decided I wanted something, a tool, to check that all my (non-stdlib) dependencies were vendored.</p><p>At first I thought of using <a href="https://golang.org/cmd/go/#hdr-List_packages"><code>go list</code></a>, which Dave Cheney appropriately called a <a href="http://dave.cheney.net/2014/09/14/go-list-your-swiss-army-knife">swiss army knife</a>, but while it can show the entire recursive dependency tree (format <code>.Deps</code>), there's no way to know from the templating engine if a dependency is in the standard library.</p><p>We could just pass each output back into <code>go list</code> to check for <code>.Standard</code>, but I thought this would be a good occasion to build a very simple static analysis tool. Go's simplicity and libraries make it a very easy task, as you will see.</p>
    <div>
      <h3>First, loading the program</h3>
      <a href="#first-loading-the-program">
        
      </a>
    </div>
    <p>We use <a href="https://godoc.org/golang.org/x/tools/go/loader"><code>golang.org/x/tools/go/loader</code></a> to load the packages passed as arguments on the command line, including the test files based on a flag.</p>
            <pre><code>var conf loader.Config
for _, p := range flag.Args() {
    if *tests {
        conf.ImportWithTests(p)
    } else {
        conf.Import(p)
    }
}
prog, err := conf.Load()
if err != nil {
    log.Fatal(err)
}
for p := range prog.AllPackages {
    fmt.Println(p.Path())
}</code></pre>
            <p>With these few lines we already replicated <code>go list -f {{ .Deps }}</code>!</p><p>The only missing loading feature here is wildcard (<code>./...</code>) support. That code <a href="https://github.com/golang/go/blob/87bca88c703c1f14fe8473dc2f07dc521cf2b989/src/cmd/go/main.go#L365">is in the go tool source</a> and it's unexported. There's an <a href="https://github.com/golang/go/issues/8768">issue</a> about exposing it, but for now packages <a href="https://github.com/golang/lint/blob/58f662d2fc0598c6c36a92ae29af1caa6ec89d7a/golint/import.go">are just copy-pasting it</a>. We'll use a packaged version of that code, <a href="https://github.com/kisielk/gotool"><code>github.com/kisielk/gotool</code></a>:</p>
            <pre><code>for _, p := range gotool.ImportPaths(flag.Args()) {</code></pre>
            <p>Finally, since we are only interested in the dependency tree today we instruct the parser to only go as far as the imports statements and we ignore the resulting "not used" errors:</p>
            <pre><code>conf.ParserMode = parser.ImportsOnly
conf.AllowErrors = true
conf.TypeChecker.Error = func(error) {}</code></pre>
            
    <div>
      <h3>Then, the actual logic</h3>
      <a href="#then-the-actual-logic">
        
      </a>
    </div>
    <p>We now have a <code>loader.Program</code> object, which holds references to various <code>loader.PackageInfo</code> objects, which in turn are a combination of package, AST and types information. All you need to perform any kind of complex analysis. Not that we are going to do that today :)</p><p>We'll just replicate <a href="https://github.com/golang/go/blob/87bca88c703c1f14fe8473dc2f07dc521cf2b989/src/cmd/go/pkg.go#L183-L194">the <code>go list</code> logic to recognize stdlib packages</a> and remove the packages passed on the command line from the list:</p>
            <pre><code>initial := make(map[*loader.PackageInfo]bool)
for _, pi := range prog.InitialPackages() {
    initial[pi] = true
}

var packages []*loader.PackageInfo
for _, pi := range prog.AllPackages {
    if initial[pi] {
        continue
    }
    if len(pi.Files) == 0 {
        continue // virtual stdlib package
    }
    filename := prog.Fset.File(pi.Files[0].Pos()).Name()
    if !strings.HasPrefix(filename, build.Default.GOROOT) ||
        !isStandardImportPath(pi.Pkg.Path()) {
        packages = append(packages, pi)
    }
}</code></pre>
            <p>Then we just have to print a warning if any remaining package is not in a <code>/vendor/</code> folder:</p>
            <pre><code>for _, pi := range packages {
    if strings.Index(pi.Pkg.Path(), "/vendor/") == -1 {
        fmt.Println("[!] dependency not vendored:", pi.Pkg.Path())
    }
}</code></pre>
            <p>Done! You can find the tool here: <a href="https://github.com/FiloSottile/vendorcheck">https://github.com/FiloSottile/vendorcheck</a></p>
    <div>
      <h3>Further reading</h3>
      <a href="#further-reading">
        
      </a>
    </div>
    <p><a href="https://github.com/golang/example/tree/master/gotypes#gotypes-the-go-type-checker">This document</a> maintained by Alan Donovan will tell you more than I'll ever know about the static analysis tooling.</p><p>Note that you might be tempted to use <code>go/importer</code> and <code>types.Importer[From]</code> instead of <code>x/go/loader</code>. Don't do that. That doesn't load the source but reads compiled <code>.a</code> files, which <b>can be stale or missing</b>. Static analysis tools that spit out "package not found" for existing packages or, worse, incorrect results because of this are a pet peeve of mine.</p><p><i>If you now feel the urge to write static analysis tools, know that the CloudFlare Go team </i><a href="https://www.cloudflare.com/join-our-team/"><i>is hiring in London, San Francisco and Singapore</i></a><i>!</i></p> ]]></content:encoded>
            <category><![CDATA[Tools]]></category>
            <category><![CDATA[Go]]></category>
            <category><![CDATA[Programming]]></category>
            <guid isPermaLink="false">7f5NBXh02bwJ9WyQmBdtZK</guid>
            <dc:creator>Filippo Valsorda</dc:creator>
        </item>
    </channel>
</rss>