<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Neven Miculinic</title>
    <description>The latest articles on Forem by Neven Miculinic (@nmiculinic).</description>
    <link>https://forem.com/nmiculinic</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F117195%2F2e071310-a095-4c9e-8c66-7dcec50a94f6.jpg</url>
      <title>Forem: Neven Miculinic</title>
      <link>https://forem.com/nmiculinic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nmiculinic"/>
    <language>en</language>
    <item>
      <title>Kubernetes on ARM: a case study</title>
      <dc:creator>Neven Miculinic</dc:creator>
      <pubDate>Tue, 30 Apr 2019 13:01:47 +0000</pubDate>
      <link>https://forem.com/nmiculinic/kubernetes-on-arm-a-case-study-5ha4</link>
      <guid>https://forem.com/nmiculinic/kubernetes-on-arm-a-case-study-5ha4</guid>
      <description>

&lt;p&gt;At KrakenSystems we're working with various IoT devices. They are our main infrastructure for collecting data and sending them to further aggregating pipelines. For now, they are implemented as Beaglebone black devices, armv7l hard float CPU, AM335x 1GHz ARM® Cortex-A8 and only 512MB RAM.  In this blogpost we're covering use case and rationale for using kubernetes on such underpowered devices.&lt;/p&gt;

&lt;p&gt;Those devices perform simple services. Reading Modbus registers, or xbee protocol, or attaching to OBD (On-Board Diagnostic for vehicles), parsing the data, serializing in the protobuf format and sending on the message bus. &lt;/p&gt;

&lt;h2&gt;
  
  
  Design criteria &amp;amp; implementation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Deployment format
&lt;/h3&gt;

&lt;p&gt;We want to deploy software as an immutable binary/container. Due to C++ build process arcane setup at KrakenSystems, and plethora of shared library dependencies container setup makes the most sense for this use case. The static binary is also a viable alternative, but that would require refactoring C++ our current build system written as bash/Makefile script collection running for about 15min from 0, and about a couple of minutes on CI after caching. &lt;/p&gt;

&lt;p&gt;Another solution was deploying services bare metal. In this legacy setup there was a dedicated shared library folder per service and we did &lt;code&gt;&lt;br&gt;
LD_LIBRARY_PATH&lt;/code&gt;  trickery for shared library version management, defeating having shared libraries in the first place. Yet due to build system current state making static binary was (dev) time-consuming.&lt;/p&gt;

&lt;p&gt;Kuberentes with its container management solution fits perfectly to our use-case. Nomad or plain old docker/cri-o/rkt would also satisfy this design criterion. Static binaries with systemd are also a satisfactory choice if it were simple to do in the present codebase state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring
&lt;/h3&gt;

&lt;p&gt;Node &amp;amp; service aliveness monitoring is critical. We require some agent running on the node and sending I'm alive to some system, together with a mature alerting pipeline. Consul is one solution. Kubernetes has this out-of-the-box, and together with Prometheus alerting rules seemed like a natural fit. We're also using Prometheus/grafana/alertmanager throughout our infrastructure which made this option more appealing.&lt;/p&gt;

&lt;p&gt;Additionally, liveness and readiness health check aren't particularly useful for the edge devices since the process crashing signals the issue. They are not server component requiring accepting client connections. &lt;/p&gt;

&lt;p&gt;Nevertheless, in the future, we plan to introduce liveness checks on the services as a failsafe mechanism in case service isn't sending data on the message bus -- its main purpose. &lt;/p&gt;

&lt;p&gt;The remaining Ascalia infrastructure is on the kubernetes, thus it made sense reusing those same tools and setup for our edge devices. Less different moving parts is always better and leads to operational simplicity despite kubernetes being not simple to operate. &lt;/p&gt;

&lt;h3&gt;
  
  
  Updates
&lt;/h3&gt;

&lt;p&gt;The edge devices aren't static islands forever resting int the Pacific Ocean. The code changes often, and configuration even more frequently. &lt;/p&gt;

&lt;p&gt;The services are designed for simplicity. Their configuration is saved as YAML file under &lt;code&gt;inotify&lt;/code&gt; watch for changes. Thus any update mechanism is possible in the future as sidecar, but keeps the development complexity in check. Furthermore, it's easier to debug.&lt;/p&gt;

&lt;p&gt;Per edge device configuration is stored in the RDBMS, Postgres in this instance. Having 100s or 1000s edge devices polling the RDBMS for simple key/value pairs wouldn't end up nicely. Furthermore, there's no push style notification from the RDBMS on key update. Thus we need some additional layer in between. &lt;/p&gt;

&lt;p&gt;We're reusing the kubernetes API server and it's backing key/value etcd store. We've defined each edge device as CRD (custom resource definition) object supporting rich and domain-specific information. The kubernetes also server as primitive inventory management supplementing the real Django backed for the operations (i.e. I don't care what Django does as long as updates the right REST endpoints in the kubernetes API)&lt;/p&gt;

&lt;p&gt;In the future it's possible edge services shall watch the backing key/value store itself, whether it's kube api server, etcd, consul, riak, redis, or any other common key/value implementation.&lt;/p&gt;

&lt;p&gt;Finally, we require async updates. The devices could be offline at the update application time. This rules out all non-agent based configuration management solutions. Ansible, our favorite configuration management tool for its simplicity and power is only used for initial setup, not update procedure (service update that is).&lt;/p&gt;

&lt;h3&gt;
  
  
  Wireguard VPN setup
&lt;/h3&gt;

&lt;p&gt;Since we're using wireguard VPN solution we need to keep client server IP/public key list in sync asynchronously. This entails having an additional agent on the edge device you have to monitor, track and make sure it's alive. &lt;/p&gt;

&lt;p&gt;We also need storing the offline device's public key and easy inspection for those keys/settings. The kubernetes CRDs are the natural fit for this role. We reuse the etcd backing store, have nice RBAC on those object and we've defined custom printer columns for easier VPN node management. &lt;/p&gt;

&lt;p&gt;We used the following open-source inhouse tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/KrakenSystems/wg-cni"&gt;wg-cni&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/KrakenSystems/wg-operator"&gt;wg-operator&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/nmiculinic/wg-quick-go"&gt;wg-quick-go&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Long story short we bootstrapped the wireguard VPN with wg-cni ansible role. This also installed wireguard based CNI for use in our kubernetes cluster.&lt;/p&gt;

&lt;p&gt;The wg-cni role created our custom CRD manifests representing client/servers in the wireguard VPN topology.  &lt;/p&gt;

&lt;p&gt;After applying the manifests we started the wireguard operator daemonset keeping nodes in sync with further additions/removals. &lt;/p&gt;

&lt;h3&gt;
  
  
  Initial deployment
&lt;/h3&gt;

&lt;p&gt;It wasn't without issue. We used &lt;a href="https://github.com/kubernetes-sigs/kubespray"&gt;kubespray&lt;/a&gt; as mature kubernetes deployment solution. It's the only complete solution for bare metal deployment. Being ansible based we're familiar with it and can easily extend it if necessary....and it was necessary.&lt;/p&gt;

&lt;p&gt;We encountered myriad of problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;missing support on ARM&lt;/li&gt;
&lt;li&gt;Default pause image not supporting arm&lt;/li&gt;
&lt;li&gt;missing cpuset (kernel update to 4.19 LTS solved it)&lt;/li&gt;
&lt;li&gt;Run into space issues a few times&lt;/li&gt;
&lt;li&gt;Flannel missing multi-arch support in kubespray (( before we transitioned to wireguard CNI for good ))&lt;/li&gt;
&lt;li&gt;... &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most of these are tracked in the following issue/PRs:&lt;/p&gt;

&lt;p&gt;Issues:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-sigs/kubespray/issues/4294"&gt;Track the gaps when porting to ARM (arm7l)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-sigs/kubespray/issues/4065"&gt;Kubeadm download fails on armv7l&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;PRs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-sigs/kubespray/pull/4261"&gt;Add support for arm images for hyperkube, kubeadm and cni_binary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/kubernetes-sigs/kubespray/pull/4299"&gt;Flannel cross platform support&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After successfully applying the default container runtime, docker, it was time for basic performance analysis.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initial performance analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Basic checklist
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;eMMC is mounted without atime&lt;/li&gt;
&lt;li&gt;using armhf binaries ( &lt;code&gt;readelf -A $(which kubelet | grep Tag_ABI_VFP_args&lt;/code&gt;) &lt;/li&gt;
&lt;li&gt;cat &lt;code&gt;/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  USE
&lt;/h3&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;debian@bbb-test:~$ vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 4  0      0   6088  19916 271064    0    0    25    20   17   32 18 12 69  0  0
 0  0      0   6120  19916 271064    0    0     0     0 1334 4098 13 20 67  0  0
 0  0      0   6120  19916 271064    0    0     0     0 1554 4046 13 19 68  0  0
 0  0      0   6120  19924 271056    0    0     0    16  929 2443 10  8 81  1  0
 0  0      0   6120  19924 271064    0    0     0     0 1611 4128 24 20 56  0  0
 0  0      0   6120  19924 271064    0    0     0     0  919 2443  6 11 83  0  0
 0  0      0   5996  19924 271064    0    0     0     0 1240 3312 29 28 42  0  0
 0  0      0   5996  19924 271064    0    0     0     0  958 2417 13  9 77  0  0
 3  0      0   5996  19924 271064    0    0     0     0 1915 5693 28 25 46  0  0
 0  0      0   5996  19924 271064    0    0     0     0 1089 3296 12 18 70  0  0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;





&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;debian@bbb-test:~$ pidstat 30 1
Linux 4.19.9-ti-r5 (bbb-test)   02/25/2019      _armv7l_        (1 CPU)

04:59:26 PM   UID       PID    %usr %system  %guest    %CPU   CPU  Command

04:59:56 PM     0     26749    3.54    1.62    0.00    5.16     0  dockerd
04:59:56 PM     0     26754    0.44    0.37    0.00    0.81     0  docker-containe
04:59:56 PM     0     26784    0.00    0.07    0.00    0.07     0  kworker/u2:2-flush-179:0
04:59:56 PM     0     28814   10.08   10.79    0.00   20.88     0  kubelet
04:59:56 PM     0     29338    0.51    1.15    0.00    1.65     0  kube-proxy
04:59:56 PM   997     29734    1.42    0.37    0.00    1.79     0  consul
04:59:56 PM     0     30867    0.03    0.00    0.00    0.03     0  docker-containe
04:59:56 PM     0     30885    0.47    0.67    0.00    1.15     0  flanneld
04:59:56 PM  1000     31776    0.30    0.07    0.00    0.37     0  mosh-server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;About 30% CPU is on the kubernetes without any meaningful work. &lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iostat -xz 1
sar -n DEV 1
sar -n TCP,ETCP 1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Don't show significant network pressure. Speedtest-cli shows 30MBit download/upload speeds which are more than sufficient for our use case.&lt;/p&gt;

&lt;p&gt;In summary, there's high CPU usage with low disk, memory and network usage. &lt;/p&gt;

&lt;h2&gt;
  
  
  Performance analysis
&lt;/h2&gt;

&lt;p&gt;Stracing kubelet shows about 66% is spent in the locks:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 65.66    1.671983        5006       334        60 futex
 11.77    0.299775         967       310           epoll_wait
  9.24    0.235263         364       647           nanosleep
  2.58    0.065766          31      2136           clock_gettime
  1.75    0.044623          38      1180        68 read
...
------ ----------- ----------- --------- --------- ----------------
100.00    2.546516                 10290       356 total
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Though using pprof and tracing profiles showed more useful information:&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;debian@bbb-test:~$ wget http://127.0.0.1:10248/debug/pprof/profile?seconds=120
debian@bbb-test:~$ wget http://127.0.0.1:10248/debug/pprof/trace?seconds=120
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;From there we concluded:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;25% time is spent in housekeeping&lt;/li&gt;
&lt;li&gt;Changing --housekeeping-interval=10m from default 10s&lt;/li&gt;
&lt;li&gt;Increasing node update period didn’t considerably affect CPU usage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This housekeeping is mostly for container metrics, which we don't really need them every 10s, once in a while is perfectly fine for our use case.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GODEBUG=gctrace=1,schedtrace=1000
gc 80 @1195.750s 0%: 0.070+217+0.19 ms clock, 0.070+57/63/59+0.19 ms cpu, 24-&amp;gt;24-&amp;gt;12 MB, 25 MB goal, 1 P

SCHED 1196345ms: gomaxprocs=1 idleprocs=1 threads=18 spinningthreads=0 idlethreads=6 runqueue=0 [0]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There are no big issues with go's GC nor scheduler in the kubelet process, thus haven't analyzed this further.&lt;br&gt;
o&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;debian@bbb-test:~$ sudo perf stat -e task-clock,cycles,instructions,branches,branch-misses,instructions,cache-misses,cache-references
^C
 Performance counter stats for 'system wide':

         16,203.12 msec task-clock                #    1.000 CPUs utilized
     4,332,572,389      cycles                    # 267393.223 GHz                    (71.42%)
       911,023,486      instructions              #    0.21  insn per cycle           (71.40%)
        98,098,648      branches                  # 6054350.923 M/sec                 (71.41%)
        30,116,184      branch-misses             #   30.70% of all branches          (71.44%)
       885,259,275      instructions              #    0.20  insn per cycle           (71.45%)
         6,967,361      cache-misses              #    1.836 % of all cache refs      (57.16%)
       379,417,471      cache-references          # 23416495.155 M/sec                (57.14%)

      16.202385758 seconds time elapsed
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We observe 30+% branch misprediction rate in the kubelet process. After further analysis this is system-wide. This cheap ARM processor has horrible branch prediction algorithms. &lt;/p&gt;

&lt;h3&gt;
  
  
  Improvements
&lt;/h3&gt;

&lt;p&gt;We performed the following improvements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nicked the docker and replaced it with CRI plugin. Concretely we used containerd&lt;/li&gt;
&lt;li&gt;increased the housekeeping interval from 10s to 10m&lt;/li&gt;
&lt;li&gt;throw away flannel for wireguard CNI (that is native routing mostly)&lt;/li&gt;
&lt;/ul&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Average:        0         9    0.00    0.14    0.00    0.24    0.14     -  ksoftirqd/0
Average:        0        10    0.00    0.17    0.00    0.35    0.17     -  rcu_preempt
Average:        0       530    0.00    0.03    0.00    0.00    0.03     -  jbd2/mmcblk1p1-
Average:        0       785    0.00    0.07    0.00    0.21    0.07     -  haveged
Average:        0       818    0.03    0.00    0.00    0.00    0.03     -  connmand
Average:        0       821    4.64    4.47    0.00    0.00    9.12     -  kubelet
Average:        0      1416    0.14    0.07    0.00    0.03    0.21     -  fail2ban-server
Average:        0      1760    0.42    0.69    0.00    0.35    1.11     -  kube-proxy
Average:        0      3436    1.70    0.90    0.00    0.00    2.60     -  containerd
Average:        0      4274    0.07    0.03    0.00    0.07    0.10     -  systemd-journal
Average:        0     17442    0.00    0.38    0.00    0.17    0.38     -  kworker/u2:2-events_unbound
Average:        0     19070    0.00    0.03    0.00    0.00    0.03     -  kworker/0:2H-kblockd
Average:        0     26772    0.00    0.24    0.00    0.28    0.24     -  kworker/0:1-wg-crypt-wg0
Average:        0     28212    0.00    0.31    0.00    0.28    0.31     -  kworker/0:3-events_power_efficient
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And in the steady state, we have ~15% CPU usage overhard for the monitoring benefits. &lt;br&gt;
Still, quite a bit, though livable. Maybe cri-o would have lower overhead, though containerd's is pretty slim too.&lt;br&gt;
We'll investigate how can we optimize the kubelet for even lower resource consumption by turning off unneeded features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;To summarize everything, is running kubernetes on the edge devices sane choice? Maybe.&lt;/p&gt;

&lt;p&gt;For us so far so good, everything works with some considerable, though livable overhead. &lt;/p&gt;

&lt;p&gt;Trying to only install Prometheus node_exporter, for example, shoots your CPU every scrape, and slows everything to a crawl for those few 100s milliseconds. &lt;/p&gt;

&lt;p&gt;This hardware is quite underpowered and with bad branch prediction makes any software running on it weaker than on comparable armv8 or x86_64 architectures. &lt;/p&gt;

&lt;p&gt;In the future we'll try to optimize things even further, hopefully reducing kubelet CPU overhead to a more reasonable percentage. We've tried rancher's k3s without a big difference (( actually worse performance since we couldn't change housekeeping interval ))&lt;/p&gt;

&lt;p&gt;There's also &lt;a href="https://kubernetes.io/blog/2019/03/19/kubeedge-k8s-based-edge-intro/"&gt;KubeEdge&lt;/a&gt; project which looks promising for kubernetes on IoT.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.cnx-software.com/2013/04/22/how-to-detect-if-an-arm-elf-binary-is-hard-float-armhf-or-soft-float-armel/"&gt;https://www.cnx-software.com/2013/04/22/how-to-detect-if-an-arm-elf-binary-is-hard-float-armhf-or-soft-float-armel/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/"&gt;https://kubernetes.io/blog/2018/05/24/kubernetes-containerd-integration-goes-ga/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/rancher/k3s"&gt;https://github.com/rancher/k3s&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/"&gt;https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/&lt;/a&gt; &lt;/li&gt;
&lt;/ul&gt;


</description>
      <category>kubernetes</category>
      <category>arm</category>
      <category>casestudy</category>
      <category>devops</category>
    </item>
    <item>
      <title>Golang race detection</title>
      <dc:creator>Neven Miculinic</dc:creator>
      <pubDate>Thu, 28 Mar 2019 14:26:36 +0000</pubDate>
      <link>https://forem.com/nmiculinic/golang-race-detection-3j5h</link>
      <guid>https://forem.com/nmiculinic/golang-race-detection-3j5h</guid>
      <description>&lt;p&gt;Race conditions are pretty nasty bugs. Hard to trace, reproduce and isolate; often occurring under unusual circumstances and often lead to hard to debug issues. Thus it's best to prevent &amp;amp; detect them early. Thankfully, there's a production-ready algorithm to tackle the challenge - ThreadSanitizer v2, a battle proven library for compiler support in Go, Rust, C &amp;amp; C++. &lt;/p&gt;

&lt;p&gt;First, let's display a typical race condition. We have a simple global count variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;Cnt&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and we count the number of events happening, whether we're counting HTTP requests, the number of likes or tinder matches is irrelevant. What's relevant it how we do it. We call function &lt;code&gt;Run&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;fun&lt;/span&gt; &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Cnt&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But that's not all. We're calling it from multiple goroutines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
  &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Cnt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we'd expect our result to be &lt;code&gt;10000&lt;/code&gt;. Yet it's improbably this shall happen on a multicore multithreaded system. You're most likely get results like &lt;code&gt;5234&lt;/code&gt; one run, &lt;code&gt;1243&lt;/code&gt; second run, or even &lt;code&gt;1521&lt;/code&gt; last run without any determinism or repeatability. This is a typical data race!&lt;/p&gt;

&lt;p&gt;Let's not stop on this toy example. Instead, let's evaluate some famous real-world race conditions with serious consequences.&lt;/p&gt;

&lt;h1&gt;
  
  
  Famous examples
&lt;/h1&gt;

&lt;h2&gt;
  
  
  DirtyCOW
&lt;/h2&gt;

&lt;p&gt;This is a race condition in the Linux kernel.  It involves a tricky memory pages interplay, &lt;code&gt;mmap&lt;/code&gt; and &lt;code&gt;madvise&lt;/code&gt; system call which allow for privilege escalation exploit. That is, you could &lt;code&gt;mmap&lt;/code&gt; root owned file Copy-on-write, which is a valid operation (every write to this &lt;code&gt;mmap&lt;/code&gt;-ed region shall not be written to an underlying file), yet under certain conditions write would propagate to underlying file, despite we're an unprivileged user.&lt;/p&gt;

&lt;p&gt;Further &lt;a href="https://dirtycow.ninja/" rel="noopener noreferrer"&gt;info&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Therac-25
&lt;/h2&gt;

&lt;p&gt;Another famous example is the Therac-25 radiotherapy machine. It had a race condition between machine settings and display settings. If the user typed instructions too quickly and changed them quickly the machine could end up in maximum radiation dosage while displaying false information to the operator. This led to multiple accidents and death cases. &lt;br&gt;
Further &lt;a href="https://hownot2code.com/2016/10/22/killer-bug-therac-25-quick-and-dirty/" rel="noopener noreferrer"&gt;info&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Definitions
&lt;/h1&gt;

&lt;p&gt;Before continuing let's briefly iterate over required definitions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Race condition&lt;/strong&gt; - A race condition is an undesirable situation that occurs when a device or system attempts to perform two or more operations at the same time, but because of the nature of the device or system, the operations must be done in the proper sequence to be done correctly&lt;/p&gt;

&lt;p&gt;Due to general race condition scope, and requiring domain knowledge understanding what is &lt;em&gt;correct&lt;/em&gt; behavior, for the rest of this post we're focusing on data race, much more narrow and objective definition.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data race&lt;/strong&gt; - Concurrent access to a memory location, one of which is a write &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concurrent access&lt;/strong&gt; - is one where event ordering isn’t known. There’s no &lt;code&gt;happens before&lt;/code&gt; relation&lt;/p&gt;

&lt;p&gt;Happens before relation requires some further explaining. Each goroutine has its own logical clock. It is incremented on each operation. Within each goroutine there's strict ordering, event happen sequentially (or at least we observe them as if they happened sequentially, various compiler optimization/Out-of-order execution might interfere). Between goroutines, there's no order unless there's synchronization between them. &lt;/p&gt;

&lt;p&gt;In the following image, you can see it visually depicted. &lt;code&gt;happens before&lt;/code&gt; relations are highlighted using arrows. I'd like to remind that &lt;code&gt;happens before&lt;/code&gt; relation is transitive. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffoo69l7zxaz2w9naxuat.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffoo69l7zxaz2w9naxuat.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Common mistakes
&lt;/h1&gt;

&lt;p&gt;Let's observe a few common mistakes in go programs. The examples have a similar equivalent in other major languages, it's in Go since I quite like it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Race on the loop counter
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c"&gt;// Not the 'i' you are looking for.&lt;/span&gt;
            &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Try it out. You might get &lt;code&gt;0 4 4 4 4&lt;/code&gt; as output depending on the event ordering. Certainly not the output you'd expect. The fix is quite simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;wg&lt;/span&gt; &lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitGroup&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;wg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Wait&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Unprotected global
&lt;/h2&gt;

&lt;p&gt;This one is similar to the introductory example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;Cnt&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Cnt&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Solutions are to sync access to global &lt;code&gt;Cnt&lt;/code&gt; variable since increment operations aren't atomic (unless from &lt;code&gt;sync/atomic&lt;/code&gt; package).&lt;/p&gt;

&lt;p&gt;Thus we use a mutex:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;Cnt&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Mutex&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Lock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unlock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;Cnt&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or atomic variable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;Cnt&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddInt64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Cnt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Violating go memory model
&lt;/h2&gt;

&lt;p&gt;Go memory &lt;a href="https://golang.org/ref/mem" rel="noopener noreferrer"&gt;model&lt;/a&gt; specifies what guarantees you have from the compiler. If you breach that contract, you're in for a bad time. The compiler is free to optimize away your code or do unpredictable things with it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"hello, world"&lt;/span&gt;
    &lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="n"&gt;setup&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example go's memory model doesn't guarantee write to done in one goroutine is visible to other goroutines since there was no synchronization between them. The compiler is also free to optimize away:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;done&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into a simpler construct, not loading done variable each iteration. Furthermore, there are no guarantees memory buffers between CPU cores and L1 caches shall be flushed between concurrent reads for the done variable. This is all due to nasty complexity of out-of-order execution and various memory guarantees across architectures. E.g. x86 has stronger memory guaranties on assembly code then ARM architecture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Synchronization primitives
&lt;/h2&gt;

&lt;p&gt;In Go we have following synchronization primitives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;channels, that is sending and receiving is a synchronization point&lt;/li&gt;
&lt;li&gt;sync package

&lt;ul&gt;
&lt;li&gt;Mutex&lt;/li&gt;
&lt;li&gt;atomics&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;For further details look those up, they are not a concept unique to go nor race detection. The important point is they bring happens before ordering into the program code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Detecting race conditions
&lt;/h1&gt;

&lt;p&gt;In Go, this is simply done with &lt;code&gt;-race&lt;/code&gt; compiler flag. We can even run our tests with it and fail on any race condition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;go install -race
go build -race
go test -race
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As said in the beginning it uses ThreadSanitizer library under the hood. You should expect runtime slowdown of 2-20x and increased memory consumption 5-10x. Other requirements are CGO enabled and 64bit operating system. It detects race conditions reliably, without false positives. During its usage is uncovered 1000+bugs in chrome, 100+ in go's standard library and more in other projects.&lt;/p&gt;

&lt;p&gt;What &lt;code&gt;-race&lt;/code&gt; flag does is instrument your code with additional instructions. For example, this simple function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get's compiled into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;movq "".x+8(SP), AX
incq (AX)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However upon turning on &lt;code&gt;-race&lt;/code&gt; you get bunch of assembly &lt;a href="https://go.godbolt.org/z/IWw4hk" rel="noopener noreferrer"&gt;code&lt;/a&gt;, interesting bits being:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
call runtime.raceread(SB)
...
call runtime.racewrite(SB)
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is compiler adds read and write barriers for each concurrently reachable memory location. The compiler is smart enough not to instrument local variables since this incurs a quite performance penalty.&lt;/p&gt;

&lt;h1&gt;
  
  
  Algorithm
&lt;/h1&gt;

&lt;p&gt;First the bad news:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Determining if an arbitrary program contains potential data races is NP-hard.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="//ftp://ftp.cs.wisc.edu/paradyn/technical_papers/RaceComplexity-ICPP1989pdf"&gt;Netzer&amp;amp;Miller 1990&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore our algorithm shall have some tradeoffs. ˍ&lt;/p&gt;

&lt;p&gt;First how &amp;amp; when do we collect our data. Our choices are either dynamic or static analysis. The main static analysis drawback is the time required for proper source code annotation. This dynamic approach is used since it requires no additional programmer intervention except turning it on. Data could be collected on the fly or dumped somewhere for post mortem analysis. ThreadSanitizer uses on the fly approach due to performance consideration. Otherwise, we could pile up huge amounts of unnecessary data.&lt;/p&gt;

&lt;p&gt;There are multiple approaches for dynamic race detection, pure happens before based, lockset based and hybrid models. ThreadSanitizer uses pure happens before. Now we'll go over 3 algorithms, each pure happens before dynamic race detection, each improving upon the last. We'll see how ThreadSanitizer evolved and understand how it works from its humble origins:&lt;/p&gt;

&lt;h3&gt;
  
  
  Vector Clocks
&lt;/h3&gt;

&lt;p&gt;First, let's explain the concept of vector clocks. Instead of each goroutine remembering only its logical clock, we remember the logical clock of the last time we hear from another goroutine. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8csesl2v8wxnl8s22zy9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8csesl2v8wxnl8s22zy9.png" alt="vector-clocks" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vector clocks are partially ordered set, if two events have strictly &lt;code&gt;greater&lt;/code&gt; or &lt;code&gt;less&lt;/code&gt; than relation between them there's &lt;code&gt;happens before&lt;/code&gt; relation between them. Otherwise, they are concurrent.&lt;/p&gt;

&lt;h3&gt;
  
  
  DJIT+
&lt;/h3&gt;

&lt;p&gt;DJIT+ is an application of vector clocks for pure happens before data race detector. &lt;/p&gt;

&lt;p&gt;We remember vector clocks for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each lock $m$ release $$L_m= (t_0, \ldots , t_n)$$&lt;/li&gt;
&lt;li&gt;Last memory read on location x $$R_x = (t_0,\ldots, t_n)$$&lt;/li&gt;
&lt;li&gt;Last memory write on location x $$W_x = (t_0, \ldots, t_n)$$&lt;/li&gt;
&lt;li&gt;Goroutine vector clock, $$C_x = (t_0, \ldots, t_n)$$&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see an example where there are no races:&lt;/p&gt;

&lt;p&gt;Each row represents a single event as our race detector sees it. First, we write to location $x$ from goroutine 0, and it's remembered in $W_x$. Afterward, we release the lock $m$ and goroutine 0 field is updated in $L_m$, that is our lock release vector clock. By acquiring the lock, we max by elements vectors clocks of $L_m$ and $C_1$, because we know lock's lock happens after lock's release. We perform the write-in goroutine 1 and check whether our own vector clock is concurrent to $W_x$ and $R_x$. It's strictly ordered, thus everything is good.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jsd7jykthb8ucgzd0a3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1jsd7jykthb8ucgzd0a3.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And now the same example, but without goroutine synchronization. There are no lock's lock and release. When comparing goroutine 1 vector clock, $(0, 8)$ is concurrent to the last write $W_x = (4,0)$. Thus we have detected the data race. This is the most important concept to understand, rest is optimizations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0ejl1052jkla5o2rsst.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj0ejl1052jkla5o2rsst.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  FastTrack
&lt;/h3&gt;

&lt;p&gt;The Fast track introduces the first optimization. For full details I recommend reading original &lt;a href="https://users.soe.ucsc.edu/~cormac/papers/pldi09.pdf" rel="noopener noreferrer"&gt;paper&lt;/a&gt;, it's quite well written!&lt;/p&gt;

&lt;p&gt;We observe the following property. If there are no data races on writes, each write is sequential. That is, it's sufficient to remember last write's goroutine and logical clock for that goroutine. Thus we create the shadow word, representing last memory write, logical clock and goroutine id. Format &lt;code&gt;&amp;lt;logical clock&amp;gt;@&amp;lt;goroutine id&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw78r58z164i74evehs6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsw78r58z164i74evehs6.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For reads, it's a bit different story. It's perfectly valid having multiple concurrent reads as long as reads and write and strictly ordered. Thus we utilize the shadow word read representation as long as a single goroutine reads the data, and fallback expensive full vector clock in concurrent read scenario:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdpufv1zq17ns9nyog7l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdpufv1zq17ns9nyog7l.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ThreadSanitizer v2
&lt;/h3&gt;

&lt;p&gt;Thread sanitizer further improved on the FastTrack. Instead of having separate $R_x$ and $W_x$, we keep a fixed sized shadow word pool for each 8-byte quadword. That is, we approximate the full vector clock with partial shadow words. Upon full shadow word pool we randomly evict an entry. &lt;/p&gt;

&lt;p&gt;By introducing this trade-off, we trace false negatives for speed and performance. Our fixed shadow word pool is memory mapped, thus allowing cheap access with additions and byte shifts compared to more expensive hashmaps or variable sized array access.&lt;/p&gt;

&lt;p&gt;Let's go over an example. Each shadow word is 8 bytes wide and consists of goroutine logical clock, goroutine id, write/read flag and position in the 8byte word we're reading/writing.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgr5buuovu13l7tivs5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftgr5buuovu13l7tivs5k.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything's good so far. Let's make another operation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj74rehztcp2ct9zejp2m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj74rehztcp2ct9zejp2m.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's introduce a data race. The goroutine 3 vector clock for goroutine 1 is 5, that is smaller than &lt;code&gt;10@1&lt;/code&gt; shadow word written in the pool. Thus we're certain a data race happened. (We assume events for each goroutine arrive in order, otherwise, we couldn't be sure whether &lt;code&gt;10@1&lt;/code&gt; entry for goroutine 3. is bigger or smaller than the current vector clock's entry for goroutine 3. This is enforced by algorithm design and implementation.)&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkh1of0uekm9gwka2v19.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwkh1of0uekm9gwka2v19.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Summary
&lt;/h1&gt;

&lt;p&gt;To summarize this article, we covered the basics of logical and vector clocks, how they are used in happens before data race detector and we build it up to the ThreadSanitizer v2 which is used in go's &lt;code&gt;-race&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We observed the tradeoffs in the algorithm design, it traded higher false negative rate for speed, however, it forbids false positive. This property builds trust, and with that trust, we know certainly, we have a race if it screams at us, not some weird edge case in the algorithm. No flaky race tests, only true positives are reported. &lt;/p&gt;

&lt;p&gt;Though, keep in my this is only data race detector; it's easy to circumvent it. For example, the following code shall pass the data race detector despite being horribly wrong in the concurrent setting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;Cnt&lt;/span&gt; &lt;span class="kt"&gt;int64&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LoadInt64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Cnt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;val&lt;/span&gt; &lt;span class="o"&gt;++&lt;/span&gt;  &lt;span class="c"&gt;// incrementing Cnt isn't atomic, we just load and store the value atomically.&lt;/span&gt;
        &lt;span class="n"&gt;atomic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StoreInt64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Cnt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  References
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/presentation/d/19mLkWBlniCXHxG-DobTSpX_Z-xJZOxMOYMsmxqNjcGs/" rel="noopener noreferrer"&gt;Slides&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://golang.org/doc/articles/race_detector.html" rel="noopener noreferrer"&gt;https://golang.org/doc/articles/race_detector.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://golang.org/doc/articles/race_detector.html#Options" rel="noopener noreferrer"&gt;Race detector options&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/google/sanitizers/wiki/ThreadSanitizerAlgorithm" rel="noopener noreferrer"&gt;https://github.com/google/sanitizers/wiki/ThreadSanitizerAlgorithm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://golang.org/ref/mem" rel="noopener noreferrer"&gt;The Go memory model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5erqWdlhQLA" rel="noopener noreferrer"&gt;""go test -race" Under the Hood" by Kavya Joshi talk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.golang.org/race-detector" rel="noopener noreferrer"&gt;https://blog.golang.org/race-detector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://danluu.com/concurrency-bugs/" rel="noopener noreferrer"&gt;https://danluu.com/concurrency-bugs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/35604.pdf" rel="noopener noreferrer"&gt;ThreadSanitizer – data race detection in practice google paper&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://users.soe.ucsc.edu/~cormac/papers/pldi09.pdf" rel="noopener noreferrer"&gt;FastTrack: Efficient and Precise Dynamic Race Detection&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://events.static.linuxfound.org/images/stories/slides/lfcs2013_vyukov.pdf" rel="noopener noreferrer"&gt;AddressSanitizer/ThreadSanitizer for Linux Kernel and userspace.&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dl.acm.org/citation.cfm?id=1228969" rel="noopener noreferrer"&gt;DJIT+ algo&lt;/a&gt; MultiRace: efficient on-the-fly data race detection in multithreaded C++ programs&lt;/li&gt;
&lt;li&gt;&lt;a href="//ftp://ftp.cs.wisc.edu/paradyn/technical_papers/RaceComplexity-ICPP1989pdf"&gt;On the Complexity of Event Ordering for Shared-Memory Parallel Program Executions (Netzer, Miller, 1990)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>algorithms</category>
    </item>
    <item>
      <title>Pragmatic tracing</title>
      <dc:creator>Neven Miculinic</dc:creator>
      <pubDate>Fri, 23 Nov 2018 11:53:09 +0000</pubDate>
      <link>https://forem.com/nmiculinic/pragmatic-tracing-cnf</link>
      <guid>https://forem.com/nmiculinic/pragmatic-tracing-cnf</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;



&lt;p&gt;&lt;code&gt;A distributed system is one in which the failure of a computer you didn't even know existed can render your own computer unusable - Leslie Lamport&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;The fact of life is we're building bigger, more complex and distributed systems. What used to be single server serving old-style personal home pages turned into the medium.com mediated blog post and various other ecosystems. Simple bulletin board marketplace turning enormous systems of Amazon, eBay, and other online retailers. This evolution is akin to life itself, as we progress from single cellular bacterias to humans we're today, the thing got complicated. More powerful, but complicated. &lt;/p&gt;

&lt;p&gt;Now, let's talk about your current system. Chances are not everything is new. Today almost every system uses numerical routines written in Fortran a few decades ago. Similarly, in your bodies basic cell metabolism haven't changed last 100s million of years. &lt;/p&gt;

&lt;p&gt;Though with added complexity, some things did change. Aside from superior featureset, e.g. sight, speech, consciousness we evolve advanced monitoring equipment. Just a single neuron acting and proto-eye doesn't cut it, but a full-fledged eye does. &lt;/p&gt;

&lt;p&gt;Vast nerve network almost instantaneously detects issues in your body and alerts the control center. Imagine if you had to check every second did you stub your toe or are you bleeding?&lt;/p&gt;

&lt;p&gt;Messages are sent and received via hormones on the gigantic message queue called circulation system, i.e. blood. Much bigger complexity than simple single cell organism and osmosis diffused operations.&lt;/p&gt;

&lt;p&gt;Therefore, your new systems cannot be monitored as they were during lower complexity era. Logs aren't enough anymore, neither are metrics nor pprof and similar toolset. In this article, I'm presenting tracing as another tool in your toolbox, both in monolith application and distributed setting. A very useful tool for specific use cases. &lt;/p&gt;

&lt;h2&gt;
  
  
  Observability toolset
&lt;/h2&gt;

&lt;p&gt;In this chapter, I'll briefly cover basic observability tools at our disposal. I'll also use a football analogy as a metaphor for the clearer explanation. For those familiar feel free to skip to the latest section, tracing. &lt;/p&gt;

&lt;h3&gt;
  
  
  Logs
&lt;/h3&gt;



&lt;p&gt;&lt;code&gt;log - an official record of events during the voyage of a ship or aircraft.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;This is the simplest and most basic tool at our disposal. &lt;br&gt;
One log represents some event happening with associated metadata.&lt;/p&gt;

&lt;p&gt;The most common metadata is when did the event happen, and other which application generated this event, on which host, what's the level of this log event.&lt;/p&gt;

&lt;p&gt;Usually log event levels are modeled after syslog levels, DEBUG, INFO, WARNING, ERROR, CRITICAL being used the most in the software. &lt;/p&gt;

&lt;p&gt;On the application and system level, you usually have log sources and log sink. Each source generates log data, and ships it to sinks. Each sink can apply some fileting, e.g. only ERROR level or higher. &lt;br&gt;
In practical terms this means you're writing log level INFO or greater to &lt;code&gt;stderr&lt;/code&gt;, but to the file, you're dumping all logs. &lt;/p&gt;

&lt;p&gt;There are log management systems for gathering and searching logs. One of the simpler is logfile with grep, more complex being journaling in systemd, and for production distributed systems you're usually using ELK stack or graylog. &lt;/p&gt;

&lt;p&gt;In the football analogy, playing scoring the goal would be a great log. Something like:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;msg="Ivan scored the goal" time="2018-01-12" game_minute="23"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;The log data is useful for unique, rare events or somehow meaningful events. For frequent events, it needs to be sampled down not to kill your log management system. For example, do you want to log every time you received IP package on the server? &lt;/p&gt;

&lt;h3&gt;
  
  
  Metrics
&lt;/h3&gt;



&lt;p&gt;&lt;code&gt;metric - a system or standard of measurement.&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;In observability context, metric is scalar value changed over time. This scalar value is usually a counter (e.g. number of goals scored, HTTP requests), gauge (e.g. temperature, CPU utilization), histogram (e.g. number of 1xx,2xx,3xx,4xx,5xx HTTP response codes) or rank estimation (e.g. 95% percentile response latency).&lt;/p&gt;

&lt;p&gt;They are great for identifying the bottleneck, unusual behavior and setting SLOs(Service level objectives). Usually, alarms are tied to some metric, that is whenever the specified metric is outside given bound perform an action - auto-heal or notify the operator. &lt;/p&gt;

&lt;p&gt;For example, in human, we have a really important metric - blood glucose level. In a healthy human, too high value performs an auto-healing operation and releasing more insulin into our bloodstream. Another human metric would be pain levels in your left leg. Usually, it's near 0, but over the certain threshold you're vividly aware of it -- that is an alarm is raised. &lt;/p&gt;

&lt;p&gt;For computer systems, usual metrics are related to throughput, error rate, latency, resource (CPU/GPU/network/...) utilization. Usual systems mentioned are statsd, graphite, grafana, and Prometheus.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pprof &amp;amp; Flamegraphs
&lt;/h3&gt;

&lt;p&gt;This tool is best for profiling CPU intensive applications. Before I explain what it offers you I want to cover how it works. X times per second it stops your program and checks which line is being executed on the machine. It collects all execution samples into buckets per line/function and later on reconstructed which function/line was executed which time %. As if you're snapshotting the football match and see who has the ball every 10 seconds, and from that reconstructing who had which ball ownership percentage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Traces
&lt;/h3&gt;

&lt;p&gt;If you remember anything from this blog post, remember this comet image:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmphsq5yfhv531dhymis.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flmphsq5yfhv531dhymis.jpg" alt="commet" width="630" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As is burning through Earth's atmosphere it leaves a &lt;em&gt;trace&lt;/em&gt; over its path. From this &lt;em&gt;trace&lt;/em&gt; we can deduce where it has been and how much time is spent there. A similar situation is within our programs. &lt;/p&gt;

&lt;p&gt;The trace represents single execution of request/operation. Trace is composed of multiple spans. Span is a meaningful unit of work in your system -- e.g. database query, RPC call, calculation. Span can be related, e.g. parent/child span. Thus trace forms a tree of spans, or more generally a DAG (if you introduce complex followed by relations and other gimmicks).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m564hunxdgmy32iqool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8m564hunxdgmy32iqool.png" alt="trace example" width="443" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Each span can have useful metadata attached to it -- both indexed tagged key/value pair such as userId, http.statuscode, hostname or additional log data e.g. exact database query. The tracing backend provides expected search capabilities, sorting by time, filtering by tags, etc.&lt;/p&gt;

&lt;p&gt;In football example, we could have a trace representing scoring a goal. It consists of 3 spans:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ivan kicking the ball&lt;/li&gt;
&lt;li&gt;The ball rolling to the goal&lt;/li&gt;
&lt;li&gt;Ball entering the goal post&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Common use cases
&lt;/h2&gt;

&lt;p&gt;In this section, I'm going to cover top use cases for tracing. Compared to other techniques like pprof, tracing can detect when your program was put to sleep due to IO waiting, resource contention or other reason.&lt;/p&gt;
&lt;h3&gt;
  
  
  Overall request overview
&lt;/h3&gt;

&lt;p&gt;It allows you making a case study from an individual trace. Metrics aggregate while trace focuses the story on the individual request. What services did this individual request touch? How much time did it spend there? What's the time breakdown on CPU, GPU, network calls, etc. &lt;/p&gt;

&lt;p&gt;If you're debugging your application searching through your traces for specific edge case and analysing that one is golden. Same with analyzing performance outliers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Big slow bottleneck
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fmedia-p.slid.es%2Fuploads%2F714579%2Fimages%2F5280805%2FUntitled_Diagram.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fs3.amazonaws.com%2Fmedia-p.slid.es%2Fuploads%2F714579%2Fimages%2F5280805%2FUntitled_Diagram.svg" width="481" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you got obvious bottleneck you know where you need to drill down. You've narrowed down your search space to this particular operation. &lt;/p&gt;

&lt;p&gt;The causes for big slow bottleneck could be various. Perhaps you're overusing lock and the program is waiting on one. Or the database query is underoptimizes/missing an index. Finally, your algorithm worked for 10 users but after growing to 10 000 users it's just too slow.&lt;/p&gt;

&lt;p&gt;Find it, observe it, analyze it, and fix it. &lt;/p&gt;
&lt;h3&gt;
  
  
  Fanout
&lt;/h3&gt;

&lt;p&gt;Fan out is the number of outgoing requests a service makes for each incoming requests. The bigger the fan out the bigger the latency. Sometimes fan out is on purpose and useful, however in this context, we're primarily talk about calling the same service over and over again where a bulk operation would be more suitable. &lt;/p&gt;

&lt;p&gt;It's the difference between:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;versus looping over some &lt;code&gt;id&lt;/code&gt; list and querying for each &lt;code&gt;id&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could happen inadvertently, e.g. using ORM framework deciding to do this thing. You've fetched your ids and now you're happily looping over them not knowing you're issuing new database query each time. &lt;/p&gt;

&lt;p&gt;Other times it's the issue with API design. If you have internal API endpoint such as: &lt;code&gt;/api/v1/user/{id}&lt;/code&gt; for fetching user data, but require bulk export it's the same issue.&lt;/p&gt;

&lt;p&gt;On the tracing, you shall see many small requests to the same service. Despite them being parallel (though they're not necessarily) you shall hit tail latency problem. &lt;/p&gt;

&lt;p&gt;The probability you're going to observe p-th percentile latency for the calling services drops exponentially with fanout degree. Here's a simple figure illustrating it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzojox05vgqbq470wwfs5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzojox05vgqbq470wwfs5.png" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Chrome tracing format
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview" rel="noopener noreferrer"&gt;This&lt;/a&gt; is simple JSON format specification for single process tracing. The &lt;a href="https://github.com/catapult-project/catapult" rel="noopener noreferrer"&gt;catapult&lt;/a&gt; project includes the rendered for this specification. The same renderer available in chrome under &lt;code&gt;chrome://tracing/&lt;/code&gt; URL. There are various support for spitting out this format, e.g. tensorflow execution, golang tracing, chrome rendering itself, etc. And it's easy to include it into your application if there's no need for distributed tracing and your requirements are simple.&lt;/p&gt;

&lt;p&gt;For example, this simple file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PERF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ph"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"B"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22630&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22630&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;829&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Asub"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"cat"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PERF"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ph"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"E"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22630&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"tid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;22630&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;833&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Renders as:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fic2nxv42sgnptoacqhiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fic2nxv42sgnptoacqhiw.png" alt="chrome tracing rendering" width="800" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you're interested in more I recommend at least skimming the specification. The biggest downside is working with the visualizer. As a newcomer, I had a hard time finding how can I filter datapoint in categories, by name, and overall advance use cases beyond the basic scroll and see. &lt;/p&gt;
&lt;h2&gt;
  
  
  Distributed tracing
&lt;/h2&gt;

&lt;p&gt;All's fine and dandy on a single node, but trouble starts with distributed systems. The problem is how to connect/correlate traces coming from multiple nodes. Which spans belong to which trace and how are those spans related? &lt;/p&gt;

&lt;p&gt;Today most solutions take notes from Google's dapper &lt;a href="https://ai.google/research/pubs/pub36356" rel="noopener noreferrer"&gt;paper&lt;/a&gt;. Each trace has its own unique traceID and each span unique SpanID which are propagated across the node boundaries. &lt;/p&gt;

&lt;p&gt;Though, there are multiple ideas about how this context should be propagated and whether to include additional data during that propagation (i.e. baggage). Also, each backend has its own ideas how should you deliver trace/span data to them. &lt;/p&gt;

&lt;p&gt;The first available backend was Zipkin, nowadays Uber's Jaeger is now CNCF incubating project and a good place to start. Also, various cloud providers have their own in-house SaaS tracing (Google's stackdriver, AWS X-Ray, etc.)&lt;/p&gt;

&lt;p&gt;Here's a screenshot from Jaeger frontend for searching and looking at your traces:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feng.uber.com%2Fwp-content%2Fuploads%2F2017%2F02%2F7-Screen-Shot-Search-Results.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Feng.uber.com%2Fwp-content%2Fuploads%2F2017%2F02%2F7-Screen-Shot-Search-Results.png" width="" height=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since writing against specific backend could be a hard vendor lock-in, there have emerged two client vendor-neutral APIs  -- open tracing and open census.&lt;/p&gt;
&lt;h3&gt;
  
  
  Client side vendor-neutral APIs
&lt;/h3&gt;

&lt;p&gt;In this subsection, I'm going to compare open census and open tracing standard. Both are evolving project with high GitHub start count, multi-language support with various middleware implementations for databases, HTTP's RPCs, gRPC, etc. &lt;/p&gt;

&lt;p&gt;Open tracing is currently CNCF incubating project while Open census emerged from Google's internal trace tool. Nowadays open census has its own vendor-neutral organization.&lt;/p&gt;

&lt;p&gt;As for the feature set, the open census includes metrics inside its API while open tracing is metrics only.&lt;/p&gt;

&lt;p&gt;In open census, you add trace exporters to the global set, while in the open tracing you have to specify them in each iteration. They have global tracer concept, but at least in go's they don't offer to default on it, but you have to invoke it. Furthermore, open tracing API feels more clunky and less polished compared to the open census. &lt;/p&gt;

&lt;p&gt;For the propagation format, open census specify the standard. Open tracing on the other hand only specifies the API, and each supported backend much implement the standard propagation API. &lt;/p&gt;

&lt;p&gt;What open tracing has is baggage concept, that is forcing some data to be propagated to each downstream service alongside span propagation context. &lt;/p&gt;
&lt;h3&gt;
  
  
  Open census example
&lt;/h3&gt;

&lt;p&gt;This subsection shall describe basic open census building blocks. For complete examples see their official documentation, it's quite good! &lt;br&gt;
They even feature great &lt;a href="https://github.com/census-instrumentation/opencensus-go/tree/master/examples" rel="noopener noreferrer"&gt;examples&lt;/a&gt;. My examples are in go, but they support multiple other languages. For brevity import statement shall be omitted. &lt;/p&gt;

&lt;p&gt;First we start by defining trace exporter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jaeger&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Endpoint&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;    &lt;span class="s"&gt;"http://localhost:14268"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ServiceName&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"opencensus-tracing"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterExporter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can easily start it using Docker. From their getting started &lt;a href="https://www.jaegertracing.io/docs/1.7/getting-started/" rel="noopener noreferrer"&gt;page&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="n"&gt;jaeger&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="n"&gt;COLLECTOR_ZIPKIN_HTTP_PORT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;9411&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="m"&gt;5775&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;5775&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;udp&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="m"&gt;6831&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;6831&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;udp&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="m"&gt;6832&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;6832&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;udp&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="m"&gt;5778&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;5778&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="m"&gt;16686&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;16686&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="m"&gt;14268&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;14268&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="m"&gt;9411&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;9411&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
  &lt;span class="n"&gt;jaegertracing&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;1.7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we start some span:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StartSpan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"some/useful/name"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;End&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ctx&lt;/code&gt; is instance of standard's library &lt;code&gt;context.context&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We can attach some indexed tagged key/value metadata to this span:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StringAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open tracing actually specifies some standardized keys (e.g. error, http.statuscode, ...). If you can I recommend using them despite open census not specifying any.&lt;/p&gt;

&lt;p&gt;Or we could add some log data, that is annotations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"some useful annotation"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;span&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Annotate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Attribute&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BoolAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt;
    &lt;span class="s"&gt;"some useful log data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After we decided to use http let's inject open census middleware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ochttp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Transport&lt;/span&gt;&lt;span class="p"&gt;{}}&lt;/span&gt;  &lt;span class="c"&gt;// client&lt;/span&gt;
&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;ochttp&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="c"&gt;//server&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for client side we only have to include the right context into our request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Do&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While on the server side we grab the context from the request and go on with our life.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;HandleXXX&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;w&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResponseWriter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This chapter could be summarised as open census crash course/cheat sheet/in 5 minutes. &lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;To summarise this blog post I recommend tracing for these use cases the most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reasoning about overall performance overview&lt;/li&gt;
&lt;li&gt;Detecting big slow operations&lt;/li&gt;
&lt;li&gt;Fan out detection&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In here I presented various tools such as chrome tracing format, open tracing, and open census. Of those, I recommend starting with open census and starting jaeger in a docker container. Use middleware wherever possible.&lt;/p&gt;

&lt;p&gt;Finally, reap the benefits! See how tracing benefits you and how can you best leverage it to your success. &lt;/p&gt;

&lt;h2&gt;
  
  
  Reference &amp;amp; links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=kN9PjsDhH-I" rel="noopener noreferrer"&gt;My Webcamp 2018 talk for this blogpost&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview" rel="noopener noreferrer"&gt;Chrome tracing format specification&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.jaegertracing.io/docs/" rel="noopener noreferrer"&gt;https://www.jaegertracing.io/docs/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/catapult-project/catapult" rel="noopener noreferrer"&gt;https://github.com/catapult-project/catapult&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@copyconstruct/monitoring-in-the-time-of-cloud-native-c87c7a5bfa3e" rel="noopener noreferrer"&gt;https://medium.com/@copyconstruct/monitoring-in-the-time-of-cloud-native-c87c7a5bfa3e&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opencensus.io/" rel="noopener noreferrer"&gt;https://opencensus.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://opentracing.io/" rel="noopener noreferrer"&gt;http://opentracing.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=kb-m2fasdDY" rel="noopener noreferrer"&gt;GOTO 2016 • What I Wish I Had Known Before Scaling Uber to 1000 Services • Matt Ranney:&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=lJ8ydIuPFeU" rel="noopener noreferrer"&gt;How NOT to Measure Latency by Gil Tene:&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.pdl.cmu.edu/PDL-FTP/SelfStar/CMU-PDL-14-102.pdf" rel="noopener noreferrer"&gt;So, you want to trace your distributed system? Key design insights from years of practical experience&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>go</category>
      <category>devops</category>
      <category>monitoring</category>
      <category>observability</category>
    </item>
  </channel>
</rss>
