<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.7.4">Jekyll</generator><link href="https://githubengineering.com/atom.xml" rel="self" type="application/atom+xml" /><link href="https://githubengineering.com/" rel="alternate" type="text/html" /><updated>2019-02-07T22:12:18+00:00</updated><id>https://githubengineering.com/atom.xml</id><title type="html">GitHub Engineering</title><subtitle>The Blog of the GitHub Engineering Team</subtitle><author><name>GitHub Engineering</name></author><entry><title type="html">An open source parser for GitHub Actions</title><link href="https://githubengineering.com/an-open-source-parser-for-github-actions/" rel="alternate" type="text/html" title="An open source parser for GitHub Actions" /><published>2019-02-07T00:00:00+00:00</published><updated>2019-02-07T00:00:00+00:00</updated><id>https://githubengineering.com/an-open-source-parser-for-github-actions</id><content type="html" xml:base="https://githubengineering.com/an-open-source-parser-for-github-actions/">&lt;p&gt;Since the beta &lt;a href=&quot;https://github.blog/2018-10-17-action-demos/&quot;&gt;release of GitHub Actions&lt;/a&gt; last October, thousands of users have added workflow files to their repositories.  But until now, those files only work with the tools GitHub provided: the Actions editor, the Actions execution platform, and the syntax highlighting built into pull requests.  To expand that universe, we need to release the &lt;a href=&quot;https://github.com/actions/workflow-parser&quot;&gt;parser&lt;/a&gt; and the &lt;a href=&quot;https://github.com/actions/workflow-parser/blob/master/language.md&quot;&gt;specification&lt;/a&gt; for the Actions workflow language as open source.  Today, we’re doing that.&lt;/p&gt;

&lt;p&gt;We believe that tools beyond GitHub should be able to run workflows.  We believe there should be programs to check, format, compose, and visualize workflow files.  We believe that text editors can provide syntax highlighting and autocompletion for Actions workflows.  And we believe all that can only happen if the Actions community is empowered to build these tools along with us.  That can happen better and faster if there is a single language &lt;a href=&quot;https://github.com/actions/workflow-parser/blob/master/language.md&quot;&gt;specification&lt;/a&gt; and a free parser implementation.&lt;/p&gt;

&lt;p&gt;The first project to use the open source parser will be &lt;a href=&quot;https://github.com/nektos/act/&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;act&lt;/code&gt;&lt;/a&gt;, which is &lt;a href=&quot;https://github.com/nektos/&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;@nektos&lt;/code&gt;&lt;/a&gt;’s tool for running Actions workflows in a local development environment.&lt;/p&gt;

&lt;p&gt;The parser and language specification are both in &lt;a href=&quot;https://github.com/actions/workflow-parser&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;actions/workflow-parser&lt;/code&gt;&lt;/a&gt;, which we’re sharing under an MIT license.  As of today, there is a &lt;a href=&quot;https://github.com/actions/workflow-parser/tree/master/parser&quot;&gt;Go implementation&lt;/a&gt;, which is the same code that powers both the Actions UI and the Actions execution platform.  The repository also contains a &lt;a href=&quot;https://github.com/actions/workflow-parser/pull/10&quot;&gt;Javascript parser in development&lt;/a&gt;, along with syntax-highlighting configurations for Atom and Vim.&lt;/p&gt;

&lt;h1 id=&quot;github-actions&quot;&gt;GitHub Actions&lt;/h1&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/features/actions/&quot;&gt;GitHub Actions&lt;/a&gt; is platform for automating software development workflows, from idea to production.  Developers add a simple text file to their repository, &lt;code class=&quot;highlighter-rouge&quot;&gt;.github/main.workflow&lt;/code&gt;, to describe automation.  The workflow file describes how events like pushing code or opening and closing issues map to automation actions, implemented in any Docker container.  Those automation actions have whatever powers you grant them: pushing commits to the repository, cutting a new release, building it through continuous integration, deploying it to staging in the cloud, testing the deployment, flipping it to production, and announcing it to the world – and any others you can build.&lt;/p&gt;

&lt;p&gt;Every workflow begins with an event and runs through a set of actions to reach some target or goal.  Those events and actions are described in a &lt;code class=&quot;highlighter-rouge&quot;&gt;main.workflow&lt;/code&gt; file, which &lt;a href=&quot;https://help.github.com/articles/creating-a-workflow-with-github-actions/&quot;&gt;you can create and edit&lt;/a&gt; with the visual editor or any text editor you like.  Here is a simple example:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-hcl&quot;&gt;workflow &quot;when I push&quot; {
  on = &quot;push&quot;
  resolves = &quot;ci&quot;
}

action &quot;ci&quot; {
  uses = &quot;docker://golang:latest&quot;
  runs = &quot;./script/cibuild&quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Whenever I push to a branch that contains that file, the &lt;code class=&quot;highlighter-rouge&quot;&gt;when I push&lt;/code&gt; workflow executes.  It resolves the target action &lt;code class=&quot;highlighter-rouge&quot;&gt;ci&lt;/code&gt;, which runs &lt;code class=&quot;highlighter-rouge&quot;&gt;./script/cibuild&lt;/code&gt; in a &lt;code class=&quot;highlighter-rouge&quot;&gt;golang:latest&lt;/code&gt; Docker container.  I can add more &lt;code class=&quot;highlighter-rouge&quot;&gt;workflow&lt;/code&gt; blocks to harness more events, and I can add more &lt;code class=&quot;highlighter-rouge&quot;&gt;action&lt;/code&gt; blocks to run after the &lt;code class=&quot;highlighter-rouge&quot;&gt;ci&lt;/code&gt; action or in parallel with it.&lt;/p&gt;

&lt;h1 id=&quot;the-actions-workflow-language&quot;&gt;The Actions workflow language&lt;/h1&gt;

&lt;p&gt;All &lt;code class=&quot;highlighter-rouge&quot;&gt;main.workflow&lt;/code&gt; files are written in the Actions workflow language, which is a subset of Hashicorp’s HCL.  In fact, our parser builds on top of the open source &lt;a href=&quot;https://github.com/hashicorp/hcl&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;hashicorp/hcl&lt;/code&gt;&lt;/a&gt; parser.&lt;/p&gt;

&lt;p&gt;All Actions workflow files are valid HCL, but not all HCL files are valid workflows.  The Actions workflow parser is stricter, allowing only a specific set of keywords and prohibiting nested objects, among other restrictions.  The reason for that is a long-standing goal of Actions: making the &lt;a href=&quot;https://help.github.com/articles/creating-a-workflow-with-github-actions/&quot;&gt;Actions editor&lt;/a&gt; and the text representation of workflows equivalent and interchangeable.  Any file you write in the graphical editor can be expressed in a &lt;code class=&quot;highlighter-rouge&quot;&gt;main.workflow&lt;/code&gt; file, of course, but also: any &lt;code class=&quot;highlighter-rouge&quot;&gt;main.workflow&lt;/code&gt; can be fully displayed and edited in the graphical editor.  There is one exception to this: the graphical editor does not display comments.  But it preserves them: changes you make in the graphical editor do not disturb comments you have added to your &lt;code class=&quot;highlighter-rouge&quot;&gt;main.workflow&lt;/code&gt; file.&lt;/p&gt;

&lt;h1 id=&quot;contributing&quot;&gt;Contributing&lt;/h1&gt;

&lt;p&gt;We have two reasons for releasing the parser.  First, we want to encourage the Actions community to build tools that generate and manipulate workflow files.  The language &lt;a href=&quot;https://github.com/actions/workflow-parser/blob/master/language.md&quot;&gt;specification&lt;/a&gt; should help developers understand the language, and the parser should save developers the trouble of writing their own.&lt;/p&gt;

&lt;p&gt;Second, we welcome your contributions.  If you find bugs, please open an issue or send a pull request.  If you want to add a syntax highlighter for a new editor or implement the parser in another language, we welcome that.  The only real limitation is on features that go beyond the parser to the rest of Actions.  For broader questions and suggestions about the rest of Actions, reach out through support; &lt;a href=&quot;https://github.com/contact?form%5Bsubject%5D=Re:%20GitHub%20Actions&quot;&gt;we’re listening&lt;/a&gt;.&lt;/p&gt;</content><author><name>Patrick Reynolds</name></author><summary type="html">Since the beta release of GitHub Actions last October, thousands of users have added workflow files to their repositories. But until now, those files only work with the tools GitHub provided: the Actions editor, the Actions execution platform, and the syntax highlighting built into pull requests. To expand that universe, we need to release the parser and the specification for the Actions workflow language as open source. Today, we’re doing that.</summary></entry><entry><title type="html">Upgrading GitHub from Rails 3.2 to 5.2</title><link href="https://githubengineering.com/upgrading-github-from-rails-3-2-to-5-2/" rel="alternate" type="text/html" title="Upgrading GitHub from Rails 3.2 to 5.2" /><published>2018-09-28T00:00:00+00:00</published><updated>2018-09-28T00:00:00+00:00</updated><id>https://githubengineering.com/upgrading-github-from-rails-3-2-to-5-2</id><content type="html" xml:base="https://githubengineering.com/upgrading-github-from-rails-3-2-to-5-2/">&lt;p&gt;On August 15th GitHub celebrated a major milestone: our main application is now running on the latest version of Rails: 5.2.1! :tada:&lt;/p&gt;

&lt;p&gt;In total the project took a year and a half to upgrade from Rails 3.2 to Rails 5.2. Along the way we took time to clean up technical debt and improve the overall codebase while doing the upgrade. Below we’ll talk about how we upgraded Rails, lessons we learned and whether we’d do it again.&lt;/p&gt;

&lt;h2 id=&quot;how-did-we-do-it&quot;&gt;How did we do it?&lt;/h2&gt;

&lt;p&gt;Upgrading Rails on an application as large and as trafficked as GitHub is no small task. It takes careful planning, good organization, and patience. The upgrade started out as kind of a hobby; engineers would work on it when they had free time. There was no dedicated team. As we made progress and gained traction it became not only something we hoped we could do, but a priority.&lt;/p&gt;

&lt;p&gt;Since GitHub is so important to our community, we can’t stop feature development or bug fixes in order to upgrade Rails.&lt;/p&gt;

&lt;p&gt;Instead of using a long-running branch to upgrade Rails we added the ability to dual boot the application in multiple versions of Rails. We created two Gemfile.lock’s: one for the current version &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile.lock&lt;/code&gt; and one for the future version &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile_next.lock&lt;/code&gt;. The dual booting allows us to regularly deploy changes for the next version to GitHub without requiring long running branches or altering how production works. We do this by conditionally loading the code.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GitHub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rails_3_2?&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;## 3.2 code (i.e. production a year and a half ago)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GitHub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rails_4_2?&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# 4.2 code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# all 5.0+ future code, ensuring we never accidentally&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# fall back into an old version going forward&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Each time we got a minor version of Rails green we’d make the CI job required for all pushes to the GitHub application and start work on the next version. While we worked on Rails 4.1 a CI job would run on every push for 3.2 and 4.0. When 4.1 was green we’d swap out 4.1 for 4.0 and get to work on 4.2. This allowed us to prevent regressions once a version of Rails was green, and time for engineers to get used to writing code that worked in multiple versions of Rails.&lt;/p&gt;

&lt;p&gt;The two versions that we deployed were 4.2 and 5.2. We deployed 4.2 because it was a huge milestone and was the first version of Rails that hadn’t been EOL’d yet (as an aside: we’d been backporting security fixes to 3.2 but not to 4.0+ so we couldn’t deploy 4.0 or 4.1. Rest assured your security is our top priority).&lt;/p&gt;

&lt;p&gt;To roll out the Rails upgrade we created a careful and iterative process. We’d first deploy to our testing environment and requested volunteers from each team to click test their area of the codebase to find any regressions the test suite missed.&lt;/p&gt;

&lt;p&gt;After fixing those regressions, we deployed in off-hours to a percentage of production servers. During each deploy we’d collect data about exceptions and performance of the site. With that information we’d fix bugs that came up and repeat those steps until the error rate was low enough be considered equal to the previous version. We merged the upgrade once we could deploy to full production for 30 minutes at peak traffic with no visible impact.&lt;/p&gt;

&lt;p&gt;This process allowed us to deploy 4.2 and 5.2 with minimal customer impact and no down time.&lt;/p&gt;

&lt;h2 id=&quot;lessons-learned&quot;&gt;Lessons Learned&lt;/h2&gt;

&lt;p&gt;The Rails upgrade took a year and a half. This was for a few reasons. First, Rails upgrades weren’t always smooth and some versions had major breaking changes. Rails improved the upgrade process for the 5 series so this meant that while 3.2 to 4.2 took 1 year, 4.2 to 5.2 only took 5 months.&lt;/p&gt;

&lt;p&gt;Another reason is the GitHub codebase is 10 years old. Over the years technical debt builds and there’s bound to be gremlins lurking in the codebase. If you’re on an old version of Rails, your engineers will need to add more monkey patches or implement features that exist upstream.&lt;/p&gt;

&lt;p&gt;Lastly, when we started it wasn’t clear what resources were needed to support the upgrade and since most of us had never done a Rails upgrade before, we were learning as we went. The project originally began with 1 full-time engineer and a small army of volunteers. We grew that team to 4 full-time engineers plus the volunteers. Each version bump meant we learned more and the next version went even faster.&lt;/p&gt;

&lt;p&gt;Through this work we learned some important lessons that we hope make your next upgrade easier:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Upgrade early and upgrade often.&lt;/strong&gt; The closer you are to a new version of Rails, the easier upgrades will be. This encourages your team to fix bugs in Rails instead of monkey-patching the application or reinventing features that exist upstream.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Keep upgrade infrastructure in place.&lt;/strong&gt; There will always be a new version to upgrade to, so once you’re on a modern version of Rails add a build to run against the master branch. This will catch bugs in Rails and your application early, make upgrades easier, and increase your upstream contributions.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Upstream your tooling instead of rolling your own.&lt;/strong&gt; The more you push upstream to gems or Rails, the less logic you need in your application. Save your application code for what truly makes your company special (i.e. Pull Requests), instead of tools to make your application run smoothly (i.e. concurrent testing libraries)&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Avoid using private API’s in your frameworks.&lt;/strong&gt; Rails has a lot of code that’s not private but isn’t documented on purpose. That code is subject to change without notice, so writing code that relies on private code can easily break in an upgrade.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Address technical debt often.&lt;/strong&gt; It’s easy to think “this is working, why mess with it”, but if no one knows how that code works, it can quickly become a bottleneck for upgrades. Try to prevent coupling your application logic too closely to your framework. Ensure that the line where your application ends and your framework begins is clear. You can do this by addressing technical debt before it becomes difficult to remove.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Do incremental upgrades.&lt;/strong&gt; Each minor version of Rails provides the deprecation warnings for the next version. By upgrading from 3.2 to 4.0, 4.0 to 4.1, etc we were able to identify problems in the next version early and define clear milestones.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Keep up the momentum.&lt;/strong&gt; Rails upgrades can seem daunting. Create ways in which your team can have quick wins to keep momentum going. Share the responsibility across teams so that everyone is familiar with the new version of the framework and prevent burnout. Once you’re on the newest version add a build to your app that periodically runs your suite against edge Rails so you can catch bugs in your code or your framework early.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Expect things to break.&lt;/strong&gt; Upgrades are hard and in an application as large as GitHub things are bound to break. While we didn’t take the site down during the upgrade we had issues with CI, local development, slow queries, and other problems that didn’t show up in our CI builds or click testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;was-it-worth-it&quot;&gt;Was it worth it?&lt;/h2&gt;

&lt;p&gt;Absolutely.&lt;/p&gt;

&lt;p&gt;Upgrading Rails has allowed us to address technical debt in our application. Our test suite is now closer to vanilla Rails, we were able to remove StateMachine in favor of Active Record enums, and start replacing our job runner with Active Job. And that’s just the beginning.&lt;/p&gt;

&lt;p&gt;Rails upgrades are a lot of hard work and can be time-consuming, but they also open up a ton possibilities. We can push more of our tooling upstream to Rails, address areas of technical debt, and be one of the largest codebases running on the most recent version of Rails. Not only does this benefit us at GitHub, it benefits our customers and the open source community.&lt;/p&gt;</content><author><name>eileencodes</name></author><summary type="html">On August 15th GitHub celebrated a major milestone: our main application is now running on the latest version of Rails: 5.2.1! :tada:</summary></entry><entry><title type="html">Towards Natural Language Semantic Code Search</title><link href="https://githubengineering.com/towards-natural-language-semantic-code-search/" rel="alternate" type="text/html" title="Towards Natural Language Semantic Code Search" /><published>2018-09-18T00:00:00+00:00</published><updated>2018-09-18T00:00:00+00:00</updated><id>https://githubengineering.com/towards-natural-language-semantic-code-search</id><content type="html" xml:base="https://githubengineering.com/towards-natural-language-semantic-code-search/">&lt;p&gt;&lt;img src=&quot;/images/semantic_code_search/main.jpg&quot; alt=&quot;Hubot&quot; /&gt;&lt;/p&gt;

&lt;h5 id=&quot;this-blog-post-complements-a-live-demonstration-on-our-recently-announced-site-experimentsgithubcom&quot;&gt;This blog post complements a live demonstration on our &lt;a href=&quot;https://blog.github.com/2018-09-18-introducing-experiments-an-ongoing-research-effort-from-github/&quot;&gt;recently announced&lt;/a&gt; site: &lt;a href=&quot;https://experiments.github.com/&quot;&gt;experiments.github.com&lt;/a&gt;&lt;/h5&gt;

&lt;h2 id=&quot;motivation&quot;&gt;Motivation&lt;/h2&gt;

&lt;p&gt;Searching code on GitHub is currently limited to keyword search.  This assumes either the user knows the syntax, or can anticipate what keywords might be in comments surrounding the code they are looking for.  Our machine learning scientists have been researching ways to enable the &lt;a href=&quot;https://en.wikipedia.org/wiki/Semantic_search&quot;&gt;semantic search&lt;/a&gt; of code.&lt;/p&gt;

&lt;p&gt;To fully grasp the concept of semantic search, consider the below search query, &lt;em&gt;“ping REST api and return results”&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/semantic_code_search/hubot_codesearch.gif&quot; alt=&quot;Vector-space diagram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Note that the demonstrated semantic search returns reasonable results even though there are no keywords in common between the search query and the text (the code &amp;amp; comments found do not contain the words “Ping”, “REST” or “api”)! The implications of augmenting keyword search with semantic search are profound.  For example, such a capability would expedite the process of on-boarding new software engineers onto projects and bolster the discoverability of code in general.&lt;/p&gt;

&lt;p&gt;In this post, we want to share how we are leveraging deep learning to make progress towards this goal.  &lt;em&gt;We also share an open source example with code and data that you can use to reproduce these results!&lt;/em&gt;&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;One of the key areas of machine learning research underway at GitHub is representation learning of entities, such as repos, code, issues, profiles and users.  We have made significant progress towards enabling semantic search by learning representations of code that share a common vector space as text.  For example, consider the below diagram:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/semantic_code_search/shared_vecs.png&quot; alt=&quot;Vector-space diagram&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the above example, Text 2 (blue) is a reasonable description of the code, whereas Text 1 (red) is not related to the code at all.  Our goal is to learn representations where (text, code) pairs that describe the same concept are close neighbors, whereas unrelated (text, code) pairs are further apart.  By representing text and code in the same vector space, we can vectorize a user’s search query and lookup the nearest neighbor that represents code.  Below is a four-part description of the approach we are currently using to accomplish this task:&lt;/p&gt;

&lt;h3 id=&quot;1-learning-representations-of-code&quot;&gt;1. Learning Representations of Code&lt;/h3&gt;

&lt;p&gt;In order to learn a representation of code, we train a &lt;a href=&quot;https://towardsdatascience.com/how-to-create-data-products-that-are-magical-using-sequence-to-sequence-models-703f86a231f8&quot;&gt;sequence-to-sequence model&lt;/a&gt; that learns to summarize code.  A way to accomplish this for Python is to supply (code, docstring) pairs where the docstring is the target variable the model is trying to predict.   One active area of research for us is incorporating domain specific optimizations like &lt;a href=&quot;https://arxiv.org/pdf/1802.00921.pdf&quot;&gt;tree-based LSTMs&lt;/a&gt;, &lt;a href=&quot;https://github.com/Microsoft/gated-graph-neural-network-samples&quot;&gt;gated-graph networks&lt;/a&gt; and syntax-aware tokenization.  Below is a screenshot that showcases the code summarizer model at work.  In this example, there are two python functions supplied as input, and in both cases the model produces a reasonable summary of the code as output:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/semantic_code_search/code_summarizer.png&quot; alt=&quot;code summarizer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It should be noted that in the above examples, the model produces the summary by using the entire code blob, not merely the function name.&lt;/p&gt;

&lt;p&gt;Building a code summarizer is a very exciting project on its own, however, we can utilize the encoder from this model as a general purpose feature extractor for code.  After extracting the encoder from this model, we can &lt;a href=&quot;https://flyyufelix.github.io/2016/10/03/fine-tuning-in-keras-part1.html&quot;&gt;fine-tune&lt;/a&gt; it for the task of mapping code to the vector space of natural language.&lt;/p&gt;

&lt;p&gt;We can evaluate this model objectively using the &lt;a href=&quot;https://en.wikipedia.org/wiki/BLEU&quot;&gt;BLEU score&lt;/a&gt;.  Currently we have been able to achieve a BLEU score of 13.5 on a holdout set of python code, using the &lt;a href=&quot;https://github.com/pytorch/fairseq&quot;&gt;fairseq-py library&lt;/a&gt; for sequence to sequence models.&lt;/p&gt;

&lt;h3 id=&quot;2-learning-representations-of-text-phrases&quot;&gt;2. Learning Representations of Text Phrases&lt;/h3&gt;

&lt;p&gt;In addition to learning a representation for code, we needed to find a suitable representation for short phrases (like sentences found in Python docstrings).  Initially, we experimented with the &lt;a href=&quot;https://arxiv.org/abs/1803.11175&quot;&gt;Universal Sentence Encoder&lt;/a&gt;, a pre-trained encoder for text that is &lt;a href=&quot;https://www.tensorflow.org/hub/modules/google/universal-sentence-encoder/1&quot;&gt;available on TensorFlow Hub&lt;/a&gt;.  While the embeddings from worked reasonably well, we found that it was advantageous to learn embeddings that were specific to the vocabulary and semantics of software development.  One area of ongoing research involves evaluating different domain-specific corpuses for training our own model, ranging from GitHub issues to third party datasets.&lt;/p&gt;

&lt;p&gt;To learn this representation of phrases, we trained a &lt;a href=&quot;https://en.wikipedia.org/wiki/Language_model&quot;&gt;neural language model&lt;/a&gt; by leveraging the &lt;a href=&quot;https://github.com/fastai/fastai&quot;&gt;fast.ai&lt;/a&gt; library.  This library gave us easy access to state of the art architectures such as &lt;a href=&quot;https://arxiv.org/pdf/1708.02182.pdf&quot;&gt;AWD LSTMs&lt;/a&gt;, and to techniques such as &lt;a href=&quot;https://arxiv.org/abs/1506.01186&quot;&gt;cyclical learning rates&lt;/a&gt; with random restarts.  We extracted representations of phrases from this model by summarizing the hidden states using the concat pooling approach found in &lt;a href=&quot;https://arxiv.org/pdf/1801.06146.pdf&quot;&gt;this paper&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One of the most challenging aspects of this exercise was to evaluate the quality of these embeddings.  We are currently building a variety of downstream supervised tasks similar to those &lt;a href=&quot;https://github.com/facebookresearch/SentEval&quot;&gt;outlined here&lt;/a&gt; that will aid us in evaluating the quality of these embeddings objectively.  In the meantime, we sanity check our embeddings by manually examining the similarity between similar phrases.  The below screenshot illustrates examples where we search the vectorized docstrings for similarity against user-supplied phrases:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/semantic_code_search/vec_sim.png&quot; alt=&quot;vec sim&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;3-mapping-code-representations-to-the-same-vector-space-as-text&quot;&gt;3. Mapping Code Representations To The Same Vector-Space as Text&lt;/h3&gt;

&lt;p&gt;Next, we map the code representations we learned from the code summarization model (part 1) to the vector space of text.  We accomplish this by fine-tuning the encoder of this model.  The inputs to this model are still code blobs, however the target variable the model is now the vectorized version of docstrings.  These docstrings are vectorized using the approach discussed in the previous section.&lt;/p&gt;

&lt;p&gt;Concretely, we perform multi-dimensional regression with &lt;a href=&quot;https://keras.io/losses/&quot;&gt;cosine proximity loss&lt;/a&gt; to bring the hidden state of the encoder into the same vector-space as text.&lt;/p&gt;

&lt;p&gt;We are actively researching alternate approaches that directly learn a joint vector space of code and natural language, borrowing from some ideas outlined &lt;a href=&quot;https://arxiv.org/abs/1705.00652&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;4-creating-a-semantic-search-system&quot;&gt;4. Creating a Semantic Search System&lt;/h3&gt;

&lt;p&gt;Finally, after successfully creating a model that can vectorize code into the same vector-space as text, we can create a semantic search mechanism.  In its most simple form, we can store the vectorized version of all code in a database, and perform nearest neighbor lookups to a vectorized search query.&lt;/p&gt;

&lt;p&gt;Another active area of our research is determining the best way to augment existing keyword search with semantic results and how to incorporate additional information such as context and relevance.
Furthermore, we are actively exploring ways to evaluate the quality of search results that will allow us to iterate quickly on this problem.  We leave these topics for discussion in a future blog post.&lt;/p&gt;

&lt;h2 id=&quot;summary&quot;&gt;Summary&lt;/h2&gt;

&lt;p&gt;The below diagram summarizes all the steps in our current semantic-search workflow:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/semantic_code_search/overview.png&quot; alt=&quot;code summarizer&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We are exploring ways to improve almost every component of this approach, including data preparation, model architecture, evaluation procedures, and overall system design.  What is described in this blog post is only a minimal example that scratches the surface.&lt;/p&gt;

&lt;h2 id=&quot;open-source-examples&quot;&gt;Open Source Examples&lt;/h2&gt;

&lt;p&gt;Our &lt;a href=&quot;https://towardsdatascience.com/semantic-code-search-3cd6d244a39c&quot;&gt;open-source end-to-end tutorial&lt;/a&gt; contains a detailed walkthrough of the approach outlined in this blog, along with code and data you can use to reproduce the results.&lt;/p&gt;

&lt;p&gt;This open source example (with some modifications) is also used as a tutorial for the &lt;a href=&quot;https://www.kubeflow.org/&quot;&gt;kubeflow&lt;/a&gt; project, which is implemented &lt;a href=&quot;https://github.com/kubeflow/examples/tree/master/code_search&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;limitations-and-intended-use-cases&quot;&gt;Limitations and Intended Use Case(s)&lt;/h3&gt;

&lt;p&gt;We believe that semantic code search will be most useful for targeted searches of code within specific entities such as repos, organizations or users as opposed to general purpose “how to” queries.   The &lt;a href=&quot;https://experiments.github.com/semantic-code-search&quot;&gt;live demonstration&lt;/a&gt; of semantic code search hosted on our &lt;a href=&quot;https://blog.github.com/2018-09-18-introducing-experiments-an-ongoing-research-effort-from-github/&quot;&gt;recently announced Experiments site&lt;/a&gt; does not allow users to perform targeted searches of repos.  Instead, this demonstration is designed to share a taste of what might be possible and searches only a limited, static set of python code.&lt;/p&gt;

&lt;p&gt;Furthermore, like all machine learning techniques, the efficacy of this approach is limited by the training data used.  For example, the data used to train these models are (code, docstring) pairs. Therefore, search queries that closely resemble a docstring have the greatest chance of success. On the other hand, queries that do not resemble a docstring or contain concepts for which there is little data may not yield sensible results.  Therefore, it is not difficult to challenge our &lt;a href=&quot;https://experiments.github.com/semantic-code-search&quot;&gt;live demonstration&lt;/a&gt; and discover the limitations of this approach.  Nevertheless, our initial results indicate that this is an extremely fruitful area of research that we are excited to share with you.&lt;/p&gt;

&lt;p&gt;There are many more use cases for semantic code search.  For example, we could extend the ideas presented here to allow users to search for code using the language of their choice (French, Mandarin, Arabic, etc.) across many different programming languages simultaneously.&lt;/p&gt;

&lt;h2 id=&quot;get-in-touch&quot;&gt;Get In Touch&lt;/h2&gt;

&lt;p&gt;This is an exciting time for the machine learning research team at GitHub and we are looking to expand. If our work interests you, please &lt;a href=&quot;https://github.com/about/careers&quot;&gt;get in touch&lt;/a&gt;!&lt;/p&gt;</content><author><name>hamelsmu</name></author><summary type="html"></summary></entry><entry><title type="html">Removing jQuery from GitHub.com frontend</title><link href="https://githubengineering.com/removing-jquery-from-github-frontend/" rel="alternate" type="text/html" title="Removing jQuery from GitHub.com frontend" /><published>2018-09-06T00:00:00+00:00</published><updated>2018-09-06T00:00:00+00:00</updated><id>https://githubengineering.com/removing-jquery-from-github-frontend</id><content type="html" xml:base="https://githubengineering.com/removing-jquery-from-github-frontend/">&lt;p&gt;We have recently completed a milestone where we were able to drop jQuery as a dependency of the frontend code for GitHub.com. This marks the end of a gradual, years-long transition of increasingly decoupling from jQuery until we were able to completely remove the library. In this post, we will explain a bit of history of how we started depending on jQuery in the first place, how we realized when it was no longer needed, and point out that—instead of replacing it with another library or framework—we were able to achieve everything that we needed using standard browser APIs.&lt;/p&gt;

&lt;h2 id=&quot;why-jquery-made-sense-early-on&quot;&gt;Why jQuery made sense early on&lt;/h2&gt;

&lt;p&gt;GitHub.com pulled in &lt;a href=&quot;https://blog.jquery.com/2007/09/16/jquery-1-2-1-released/&quot;&gt;jQuery 1.2.1&lt;/a&gt; as a dependency in late 2007. For a bit of context, that was a year before Google released the first version of their Chrome browser. There was no standard way to query DOM elements by a CSS selector, no standard way to animate visual styles of an element, and the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest&quot;&gt;XMLHttpRequest interface&lt;/a&gt; pioneered by Internet Explorer was, like many other APIs, inconsistent between browsers.&lt;/p&gt;

&lt;p&gt;jQuery made it simple to manipulate the DOM, define animations, and make “AJAX” requests— basically, it enabled web developers to create more modern, dynamic experiences that stood out from the rest. Most importantly of all, the JavaScript features built in one browser with jQuery would generally work in other browsers, too. In those early days of GitHub when most of its features were still getting fleshed out, this allowed the small development team to prototype rapidly and get new features out the door without having to adjust code specifically for each web browser.&lt;/p&gt;

&lt;p&gt;The simple interface of jQuery also served as a blueprint to craft extension libraries that would later serve as building blocks for the rest of GitHub.com frontend: &lt;a href=&quot;https://github.com/defunkt/jquery-pjax&quot;&gt;pjax&lt;/a&gt; and &lt;a href=&quot;https://github.com/defunkt/facebox&quot;&gt;facebox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We will always be thankful to John Resig and the jQuery contributors for creating and maintaining such a useful and, for the time, &lt;em&gt;essential&lt;/em&gt; library.&lt;/p&gt;

&lt;h2 id=&quot;web-standards-in-the-later-years&quot;&gt;Web standards in the later years&lt;/h2&gt;

&lt;p&gt;Over the years, GitHub grew into a company with hundreds of engineers and a dedicated team gradually formed to take responsibility for the size and quality of JavaScript code that we serve to web browsers. One of the things that we’re constantly on the lookout for is technical debt, and sometimes technical debt grows around dependenices that once provided value, but whose value dropped over time.&lt;/p&gt;

&lt;p&gt;When it came to jQuery, we compared it against the rapid evolution of supported web standard in modern browsers and realized:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;$(selector)&lt;/code&gt; pattern can easily be replaced with &lt;code class=&quot;highlighter-rouge&quot;&gt;querySelectorAll()&lt;/code&gt;;&lt;/li&gt;
  &lt;li&gt;CSS classname switching can now be achieved using &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Element/classList&quot;&gt;Element.classList&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;CSS now supports defining &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations&quot;&gt;visual animations in stylesheets&lt;/a&gt; rather than in JavaScript;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;$.ajax&lt;/code&gt; requests can be performed using the &lt;a href=&quot;https://fetch.spec.whatwg.org/&quot;&gt;Fetch Standard&lt;/a&gt;;&lt;/li&gt;
  &lt;li&gt;The &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;addEventListener()&lt;/code&gt;&lt;/a&gt; interface is stable enough for cross-platform use;&lt;/li&gt;
  &lt;li&gt;We could easily encapsulate &lt;a href=&quot;https://github.com/dgraham/delegated-events#readme&quot;&gt;the event delegation pattern&lt;/a&gt; with a lightweight library;&lt;/li&gt;
  &lt;li&gt;Some syntactic sugar that jQuery provides has become reduntant with the evolution of JavaScript language.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Furthermore, the chaining syntax didn’t satisfy how we wanted to write code going forward. For example:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'.js-widget'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'is-loading'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;show&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This syntax is simple to write, but to our standards, doesn’t communicate intent really well. Did the author expect one or more &lt;code class=&quot;highlighter-rouge&quot;&gt;js-widget&lt;/code&gt; elements on this page? Also, if we update our page markup and accidentally leave out the &lt;code class=&quot;highlighter-rouge&quot;&gt;js-widget&lt;/code&gt; classname, will an exception in the browser inform us that something went wrong? By default, jQuery silently skips the whole expresion when nothing matched the initial selector; but to us, such behavior was a bug rather than a feature.&lt;/p&gt;

&lt;p&gt;Finally, we wanted to start annotating types with &lt;a href=&quot;https://flow.org/&quot;&gt;Flow&lt;/a&gt; to perform static type checking at build time, and we concluded that the chaining syntax doesn’t lend itself well to static analysis, since almost every result of a jQuery method call is of the same type. We chose Flow over alternatives because, at the time, features such as &lt;code class=&quot;highlighter-rouge&quot;&gt;@flow weak&lt;/code&gt; mode allowed us to progressively and efficiently start applying types to a codebase which was largely untyped.&lt;/p&gt;

&lt;p&gt;All in all, decoupling from jQuery would mean that we could rely on web standards more, have &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript&quot;&gt;MDN web docs&lt;/a&gt; be de-facto default documentation for our frontend developers, maintain more resilient code in the future, and eventually drop a 30 kB dependency from our packaged bundles, speeding up page load times and JavaScript execution times.&lt;/p&gt;

&lt;h2 id=&quot;incremental-decoupling&quot;&gt;Incremental decoupling&lt;/h2&gt;

&lt;p&gt;Even with an end goal in sight, we knew that it wouldn’t be feasible to just allocate all resources we had to rewriting everything from jQuery to vanilla JS. If anything, such a rushed endeavor would likely lead to many regressions in site functionality that we would later have to weed out. Instead, we:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Set up metrics that tracked ratio of jQuery calls used per overall line of code and monitored that graph over time to make sure that it’s either staying constant or going down, not up.&lt;/p&gt;

    &lt;p&gt;&lt;img src=&quot;/images/removing-jquery-from-github-frontend/jquery-usage.png&quot; alt=&quot;Graph of jQuery usage going down over time.&quot; /&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We discouraged importing jQuery in any new code. To facilitate that using automation, we created &lt;a href=&quot;https://github.com/dgraham/eslint-plugin-jquery#readme&quot;&gt;eslint-plugin-jquery&lt;/a&gt; which would fail CI checks if anyone tried to use jQuery features, for example &lt;code class=&quot;highlighter-rouge&quot;&gt;$.ajax&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;There were now plenty of violations of eslint rules in old code, all of which we’ve annotated with specific &lt;code class=&quot;highlighter-rouge&quot;&gt;eslint-disable&lt;/code&gt; rules in code comments. To the reader of that code, those comments would serve as a clear signal that this code doesn’t represent our current coding practices.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We created a pull request bot that would leave a review comment on a pull request pinging our team whenever somebody tried to add a new &lt;code class=&quot;highlighter-rouge&quot;&gt;eslint-disable&lt;/code&gt; rule. This way we would get involved in code review early and suggest alternatives.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;A lot of old code had explicit coupling to external interfaces of pjax and facebox jQuery plugins, so we’ve kept their interfaces relatively the same while we’ve internally replaced their implementation with vanilla JS. Having static type checking helped us have greater confidence around those refactorings.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Plenty of old code interfaced with &lt;a href=&quot;http://josh.github.io/rails-behaviors/&quot;&gt;rails-behaviors&lt;/a&gt;, our adapter for the Ruby on Rails approach to “unobtrusive” JS, in a way that they would attach an AJAX lifecycle handler to certain forms:&lt;/p&gt;

    &lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;c1&quot;&gt;// LEGACY APPROACH&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;document&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'ajaxSuccess'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'form.js-widget'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;xhr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// insert response data somewhere into the DOM&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;Instead of having to rewrite all of those call sites at once to the new approach, we’ve opted to trigger &lt;em&gt;fake&lt;/em&gt; &lt;code class=&quot;highlighter-rouge&quot;&gt;ajax*&lt;/code&gt; lifecycle events and keep these forms submitting their contents asynchronously as before; only this time &lt;code class=&quot;highlighter-rouge&quot;&gt;fetch()&lt;/code&gt; was used internally.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We maintained a custom build of jQuery and whenever we’ve identified that we’re not using a certain module of jQuery anymore, we would remove it from the custom build and ship a slimmer version. For instance, after we have removed the final usage of jQuery-specific CSS pseudo-selectors such as &lt;code class=&quot;highlighter-rouge&quot;&gt;:visible&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;:checkbox&lt;/code&gt;, we were able to remove the &lt;a href=&quot;https://sizzlejs.com/&quot;&gt;Sizzle module&lt;/a&gt;; and when the last &lt;code class=&quot;highlighter-rouge&quot;&gt;$.ajax&lt;/code&gt; call was replaced with &lt;code class=&quot;highlighter-rouge&quot;&gt;fetch()&lt;/code&gt;, we were able to remove the AJAX module. This served a dual purpose: speeding up JavaScript execution times while at the same time ensuring that no new code is created that would try using the removed functionality.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;We kept dropping support for old Internet Explorer versions as soon as it would be feasible to, as informed by our site analytics. Whenever use of a certain IE version dropped below a certain threshold, we would stop serving JavaScript to it and focus on testing against and supporting more modern browsers. Dropping support for IE 8–9 early on allowed us to adopt many native browser features that would otherwise be hard to polyfill.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;As part of our refined approach to building frontend features on GitHub.com, we focused on getting away with regular HTML foundation as much as we could, and only adding JavaScript behaviors as progressive enhancement. As a result, even those web forms and other UI elements that were enhanced using JS would usually also work with JavaScript disabled in the browser. In some cases, we were able to delete certain legacy behaviors altogether instead of having to rewrite them in vanilla JS.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With these and similar efforts combined over the years, we were able gradually reduce our dependence on jQuery until there was not a single line of code referencing it anymore.&lt;/p&gt;

&lt;h2 id=&quot;custom-elements&quot;&gt;Custom Elements&lt;/h2&gt;

&lt;p&gt;One technology that has been making waves in the recent years is &lt;a href=&quot;https://developers.google.com/web/fundamentals/web-components/customelements&quot;&gt;Custom Elements&lt;/a&gt;: a component library native to the browser, which means that there are no additional bytes of a framework for the user to download, parse and compile.&lt;/p&gt;

&lt;p&gt;We had created a few Custom Elements based on the v0 specification since 2014. However, as standards were still in flux back then, we did not invest as much. It was not until 2017 when the Web Components v1 spec was released and implemented in both Chrome and Safari that &lt;a href=&quot;https://github.com/search?q=topic%3Aweb-components+org%3Agithub&quot;&gt;we began to adopt Custom Elements&lt;/a&gt; on a wider scale.&lt;/p&gt;

&lt;p&gt;During the jQuery migration, we looked for patterns that would be suitable for extraction as custom elements. For example, we converted our facebox usage for displaying modal dialogs to the &lt;a href=&quot;https://github.com/github/details-dialog-element#readme&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;details-dialog&amp;gt;&lt;/code&gt; element&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Our general philosophy of striving for progressive enhancement extends to custom elements as well. This means that we keep as much of the content in markup as possible and only add behaviors on top of that. For example, &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;local-time&amp;gt;&lt;/code&gt; shows the raw timestamp by default and gets upgraded to translate the time to the local timezone, while &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;details-dialog&amp;gt;&lt;/code&gt;, when nested in the &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;details&amp;gt;&lt;/code&gt; element, is interactive even without JavaScript, but gets upgraded with accessibility enhancements.&lt;/p&gt;

&lt;p&gt;Here is an example of how a &lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;local-time&amp;gt;&lt;/code&gt; custom element could be implemented:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// The local-time element displays time in the user's current timezone&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// and locale.&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Example:&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//   &amp;lt;local-time datetime=&quot;2018-09-06T08:22:49Z&quot;&amp;gt;Sep 6, 2018&amp;lt;/local-time&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LocalTimeElement&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;HTMLElement&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kr&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;observedAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'datetime'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;attributeChangedCallback&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attrName&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;oldValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attrName&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'datetime'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;newValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;textContent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toLocaleString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;customElements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'local-time'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;LocalTimeElement&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LocalTimeElement&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;customElements&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;define&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'local-time'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;LocalTimeElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;One aspect of Web Components that we’re looking forward to adopting is &lt;a href=&quot;https://developers.google.com/web/fundamentals/web-components/shadowdom&quot;&gt;Shadow DOM&lt;/a&gt;. The powerful nature of Shadow DOM has the potential to unlock a lot of possibilities for the web, but that also makes it harder to polyfill. Because polyfilling it today incurs a performance penalty even for code that manipulates parts of the DOM &lt;em&gt;unrelated&lt;/em&gt; to web components, it is unfeasible for us to start using it in production.&lt;/p&gt;

&lt;h2 id=&quot;polyfills&quot;&gt;Polyfills&lt;/h2&gt;

&lt;p&gt;These are the polyfills that helped us transition to using standard browser features. We try to serve most of these polyfills only when absolutely necessary, i.e. to outdated browsers as part of a separate “compatibility” JavaScript bundle.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/github/eventlistener-polyfill#readme&quot;&gt;github/eventlistener-polyfill&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/github/fetch#readme&quot;&gt;github/fetch&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/github/form-data-entries#readme&quot;&gt;github/form-data-entries&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/iamdustan/smoothscroll#readme&quot;&gt;iamdustan/smoothscroll&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/javan/details-element-polyfill#readme&quot;&gt;javan/details-element-polyfill&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jonathantneal/closest#readme&quot;&gt;jonathantneal/closest&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/kumarharsh/custom-event-polyfill#readme&quot;&gt;kumarharsh/custom-event-polyfill&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/marvinhagemeister/request-idle-polyfill#readme&quot;&gt;marvinhagemeister/request-idle-polyfill&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mathiasbynens/Array.from#readme&quot;&gt;mathiasbynens/Array.from&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mathiasbynens/String.prototype.codePointAt#readme&quot;&gt;mathiasbynens/String.prototype.codePointAt&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mathiasbynens/String.prototype.endsWith#readme&quot;&gt;mathiasbynens/String.prototype.endsWith&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/mathiasbynens/String.prototype.startsWith#readme&quot;&gt;mathiasbynens/String.prototype.startsWith&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/medikoo/es6-symbol#readme&quot;&gt;medikoo/es6-symbol&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/nicjansma/usertiming.js#readme&quot;&gt;nicjansma/usertiming.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/rubennorte/es6-object-assign#readme&quot;&gt;rubennorte/es6-object-assign&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/stefanpenner/es6-promise#readme&quot;&gt;stefanpenner/es6-promise&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/webcomponents/template#template&quot;&gt;webcomponents/template&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/webcomponents/URL#readme&quot;&gt;webcomponents/URL&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/webcomponents/webcomponentsjs#readme&quot;&gt;webcomponents/webcomponentsjs&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/WebReflection/url-search-params#readme&quot;&gt;WebReflection/url-search-params&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/yola/classlist-polyfill#readme&quot;&gt;yola/classlist-polyfill&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Mislav Marohnić</name></author><summary type="html">We have recently completed a milestone where we were able to drop jQuery as a dependency of the frontend code for GitHub.com. This marks the end of a gradual, years-long transition of increasingly decoupling from jQuery until we were able to completely remove the library. In this post, we will explain a bit of history of how we started depending on jQuery in the first place, how we realized when it was no longer needed, and point out that—instead of replacing it with another library or framework—we were able to achieve everything that we needed using standard browser APIs.</summary></entry><entry><title type="html">GLB: GitHub’s open source load balancer</title><link href="https://githubengineering.com/glb-director-open-source-load-balancer/" rel="alternate" type="text/html" title="GLB: GitHub's open source load balancer" /><published>2018-08-08T00:00:00+00:00</published><updated>2018-08-08T00:00:00+00:00</updated><id>https://githubengineering.com/glb-director-open-source-load-balancer</id><content type="html" xml:base="https://githubengineering.com/glb-director-open-source-load-balancer/">&lt;p&gt;At GitHub, we serve tens of thousands of requests every second out of our network edge, operating on &lt;a href=&quot;http://githubengineering.com/githubs-metal-cloud/&quot;&gt;GitHub’s metal cloud&lt;/a&gt;. We’ve previously &lt;a href=&quot;https://githubengineering.com/introducing-glb/&quot;&gt;introduced GLB&lt;/a&gt;, our scalable load balancing solution for bare metal datacenters, which powers the majority of GitHub’s public web and git traffic, as well as fronting some of our most critical internal systems such as &lt;a href=&quot;https://githubengineering.com/mysql-high-availability-at-github/&quot;&gt;highly available MySQL clusters&lt;/a&gt;. Today we’re excited to share more details about our load balancer’s design, as well as release the GLB Director as open source.&lt;/p&gt;

&lt;p&gt;GLB Director is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Transport_layer&quot;&gt;Layer 4&lt;/a&gt; load balancer which scales a single IP address across a large number of physical machines while attempting to minimise connection disruption during any change in servers. GLB Director does not replace services like haproxy and nginx, but rather is a layer in front of these services (or any TCP service) that allows them to scale across multiple physical machines without requiring each machine to have unique IP addresses.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB&quot; src=&quot;/images/introducing-glb/glb-logo-dark.png&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;scaling-an-ip-using-ecmp&quot;&gt;Scaling an IP using ECMP&lt;/h2&gt;

&lt;p&gt;The basic property of a Layer 4 load balancer is the ability to take a single IP address and spread inbound connections across multiple servers. To scale a single IP address to handle more traffic than any single machine can process, we need to not only split amongst backend servers, but also need to be able to scale up the servers that handle the load balancing themselves. This is essentially another layer of load balancing.&lt;/p&gt;

&lt;p&gt;Typically we think of an IP address as referencing a single physical machine, and routers as moving a packet to the next closest router to that machine. In the simplest case where there’s always a single best next hop, routers pick that hop and forward all packets there until the destination is reached.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;Next Hop Routing&quot; src=&quot;/images/glb-director-open-source-load-balancer/simple-nexthop-routing.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;In reality, most networks are far more complicated. There is often more than a single path available between two machines, for example where multiple ISPs are available or even when two routers are joined together with more than one physical cable to increase capacity and provide redundancy. This is where &lt;a href=&quot;https://en.wikipedia.org/wiki/Equal-cost_multi-path_routing&quot;&gt;Equal-Cost Multi-Path (ECMP) routing&lt;/a&gt; comes in to play - rather than routers picking a single best next hop, where they have multiple hops with the same cost (usually defined as the number of &lt;a href=&quot;https://en.wikipedia.org/wiki/Autonomous_system_(Internet)&quot;&gt;ASes&lt;/a&gt; to the destination), they instead hash traffic so that connections are balanced across all available paths of equal cost.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;ECMP with the same destination server&quot; src=&quot;/images/glb-director-open-source-load-balancer/ecmp-same-destination.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;ECMP is implemented by hashing each packet to determine a relatively consistent selection of one of the available paths. The hash function used here varies by device, but typically it’s a &lt;a href=&quot;https://en.wikipedia.org/wiki/Consistent_hashing&quot;&gt;consistent hash&lt;/a&gt; based on the source and destination IP address as well as the source and destination port for TCP traffic. This means that multiple packets for the same ongoing TCP connection will typically traverse the same path, meaning that packets will arrive in the same order even when paths have different latencies. Notably in this case, the paths can change without any disruption to connections because they will always end up at the same destination server, and at that point the path it took is mostly irrelevant.&lt;/p&gt;

&lt;p&gt;An alternative use of ECMP can come in to play when we want to shard traffic across multiple &lt;em&gt;servers&lt;/em&gt; rather than to the same server over multiple &lt;em&gt;paths&lt;/em&gt;. Each server can announce the same IP address with &lt;a href=&quot;https://en.wikipedia.org/wiki/Border_Gateway_Protocol&quot;&gt;BGP&lt;/a&gt; or another similar network protocol, causing connections to be sharded across those servers, with the routers blissfully unaware that the connections are being handled in different places, not all ending on the same machine as would traditionally be the case.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;ECMP with multiple destination servers&quot; src=&quot;/images/glb-director-open-source-load-balancer/ecmp-shard-traffic.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;While this shards traffic as we had hoped, it has one huge drawback: when the set of servers that are announcing the same IP change (or any path or router along the way changes), connections must rebalance to maintain an equal balance of connections on each server. Routers are typically stateless devices, simply making the best decision for each packet without consideration to the connection it is a part of, which means some connections will break in this scenario.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;ECMP redistribution breaking connections&quot; src=&quot;/images/glb-director-open-source-load-balancer/ecmp-redist-break.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;In the above example on the left, we can imagine that each colour represents an active connection. A new proxy server is added to announce the same IP. The router diligently adjusts the consistent hash to move 1/3 connections to the new server while keeping 2/3 connections where they were. Unfortunately for those 1/3 connections that were already in progress, the packets are now arriving on a server that doesn’t know about the connection, and so they fail.&lt;/p&gt;

&lt;h2 id=&quot;split-directorproxy-load-balancer-design&quot;&gt;Split director/proxy load balancer design&lt;/h2&gt;

&lt;p&gt;The issue with the previous ECMP-only solution is that it isn’t aware of the full context for a given packet, nor is it able to store data for each packet/connection. As it turns out, there are commonly used patterns to help out with this situation by implementing some stateful tracking in software, typically using a tool like &lt;a href=&quot;https://en.wikipedia.org/wiki/Linux_Virtual_Server&quot;&gt;Linux Virtual Server (LVS)&lt;/a&gt;. We create a new tier of “director” servers that take packets from the router via ECMP, but rather than relying on the router’s ECMP hashing to choose the backend proxy server, we instead control the hashing and store state (which backend was chosen) for all in-progress connections. When we change the set of proxy tier servers, the director tier hopefully hasn’t changed, and our connection will continue.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;ECMP redistribution with LVS director missing state&quot; src=&quot;/images/glb-director-open-source-load-balancer/ecmp-redist-lvs-no-state.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Although this works well in many cases, it does have some drawbacks. In the above example, we add both a LVS director and backend proxy server at the same time. The new director receives some set of packets, but doesn’t have any state yet (or has delayed state), so hashes it as a new connection and may get it wrong (and cause the connection to fail). A typical workaround with LVS is to use &lt;a href=&quot;http://www.linuxvirtualserver.org/docs/sync.html&quot;&gt;multicast connection syncing&lt;/a&gt; to keep the connection state shared amongst all LVS director servers. This still requires connection state to propagate, and also still requires duplicate state - not only does each proxy need state for each connection in the Linux kernel network stack, but &lt;em&gt;every&lt;/em&gt; LVS director also needs to store a mapping of connection to backend proxy server.&lt;/p&gt;

&lt;h2 id=&quot;removing-all-state-from-the-director-tier&quot;&gt;Removing all state from the director tier&lt;/h2&gt;

&lt;p&gt;When we were designing GLB, we decided we wanted to improve on this situation and not duplicate state at all. GLB takes a different approach to that described above, by using the flow state already stored in the proxy servers as part of maintaining established Linux TCP connections from clients.&lt;/p&gt;

&lt;p&gt;For each incoming connection, we pick a primary and secondary server that could handle that connection. When a packet arrives on the primary server and isn’t valid, it is forwarded to the secondary server. The hashing to choose the primary/secondary server is done once, up front, and is stored in a lookup table, and so doesn’t need to be recalculated on a per-flow or per-packet basis. When a new proxy server is added, for 1/N connections it becomes the new primary, and the old primary becomes the secondary. This allows existing flows to complete, because the proxy server can make the &lt;a href=&quot;#second-chance-on-proxies-with-iptables&quot;&gt;decisions with its local state&lt;/a&gt;, the single source of truth. Essentially this gives packets a “second chance” at arriving at the expected server that holds their state.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;ECMP redistribution with GLB&quot; src=&quot;/images/glb-director-open-source-load-balancer/ecmp-redist-glb.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Even though the director will still send connections to the wrong server, that server will then know how to forward on the packet to the correct server. The GLB director tier is completely stateless in terms of TCP flows: director servers can come and go at any time, and will always pick the same primary/secondary server providing their forwarding tables match (but they rarely change). To change proxies, some care needs to be taken, which we describe below.&lt;/p&gt;

&lt;h2 id=&quot;maintaining-invariants-rendezvous-hashing&quot;&gt;Maintaining invariants: rendezvous hashing&lt;/h2&gt;

&lt;p&gt;The core of the GLB Director design comes down to picking that primary and secondary server consistently, and to allow the proxy tier servers to drain and fill as needed. We consider each proxy server to have a state, and carefully adjust the state as a way of adding and removing servers.&lt;/p&gt;

&lt;p&gt;We create a static binary forwarding table, which is generated identically on each director server, to map incoming flows to a given primary and secondary server. Rather than having complex logic to pick from all available servers at packet processing time, we instead use some indirection by creating a table (65k rows), with each row containing a primary and secondary server IP address. This is stored in memory as flat array of binary data, taking about 512kb per table. When a packet arrives, we consistently hash it (based on packet data alone) to the same row in that table (using the hash as an index into the array), which provides a consistent primary and secondary server pair.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB Forwarding Table with active servers&quot; src=&quot;/images/glb-director-open-source-load-balancer/forwarding-table-active.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;We want each server to appear approximately equally in both the primary and secondary fields, and to never appear in both in the same row. When we add a new server, we desire some rows to have their primary become secondary, and the new server become primary. Similarly, we desire the new server to become secondary in some rows. When we remove a server, in any rows where it was primary, we want the secondary to become primary, and another server to pick up secondary.&lt;/p&gt;

&lt;p&gt;This sounds complex, but can be summarised succinctly with a couple of &lt;a href=&quot;https://en.wikipedia.org/wiki/Invariant_(computer_science)&quot;&gt;invariants&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;As we change the set of servers, the relative order of existing servers should be maintained.&lt;/li&gt;
  &lt;li&gt;The order of servers should be computable without any state other than the list of servers (and maybe some predefined seeds).&lt;/li&gt;
  &lt;li&gt;Each server should appear at most once in each row.&lt;/li&gt;
  &lt;li&gt;Each server should appear approximately an equal number of times in each column.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reading the problem that way, &lt;a href=&quot;https://en.wikipedia.org/wiki/Rendezvous_hashing&quot;&gt;Rendezvous hashing&lt;/a&gt; is an ideal choice, since it can trivially satisfy these invariants. Each server (in our case, the IP) is hashed along with the row number, the servers are sorted by that hash (which is just a number), and we get a unique order for servers for that given row. We take the first two as the primary and secondary respectively.&lt;/p&gt;

&lt;p&gt;Relative order will be maintained because the hash for each server will be the same regardless of which other servers are included. The only information required to generate the table is the IPs of the servers. Since we’re just sorting a set of servers, the servers only appear once. Finally, if we use a good hash function that is pseudo-random, the ordering will be pseudo-random, and so the distribution will be even as we expect.&lt;/p&gt;

&lt;h2 id=&quot;draining-filling-adding-and-removing-proxies&quot;&gt;Draining, filling, adding and removing proxies&lt;/h2&gt;

&lt;p&gt;Adding or removing proxy servers require some care in our design. This is because a forwarding table entry only defines a primary/secondary proxy, so the draining/failover only works with at most a single proxy host in draining. We define the following valid states and state transitions for a proxy server:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB Proxy server state machine&quot; src=&quot;/images/glb-director-open-source-load-balancer/glb-proxy-state-machine.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;When a proxy server is &lt;code class=&quot;highlighter-rouge&quot;&gt;active&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;draining&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;filling&lt;/code&gt;, it is included in the forwarding table entries. In a stable state, all proxy servers are &lt;code class=&quot;highlighter-rouge&quot;&gt;active&lt;/code&gt;, and the rendezvous hashing described above will have an approximately even and random distribution of each proxy server in both the &lt;code class=&quot;highlighter-rouge&quot;&gt;primary&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;secondary&lt;/code&gt; columns.&lt;/p&gt;

&lt;p&gt;As a proxy server transitions to &lt;code class=&quot;highlighter-rouge&quot;&gt;draining&lt;/code&gt;, we adjust the entries in the forwarding table by swapping the &lt;code class=&quot;highlighter-rouge&quot;&gt;primary&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;secondary&lt;/code&gt; entries we would have otherwise included:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB Forwarding Table with a draining server&quot; src=&quot;/images/glb-director-open-source-load-balancer/forwarding-table-draining.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This has the effect of sending packets to the server that was previously &lt;code class=&quot;highlighter-rouge&quot;&gt;secondary&lt;/code&gt; first. Since it receives the packets first, it will accept SYN packets and therefore take any new connections. For any packet it doesn’t understand as relating to a local flow, it forwards it to the other server (the previous &lt;code class=&quot;highlighter-rouge&quot;&gt;primary&lt;/code&gt;), which allows existing connections to complete.&lt;/p&gt;

&lt;p&gt;This has the effect of draining the desired server of connections gracefully, after which point it can be removed completely, and proxies can shuffle in to fill the empty &lt;code class=&quot;highlighter-rouge&quot;&gt;secondary&lt;/code&gt; slots:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB Forwarding Table with removed server&quot; src=&quot;/images/glb-director-open-source-load-balancer/forwarding-table-removed.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;A node in &lt;code class=&quot;highlighter-rouge&quot;&gt;filling&lt;/code&gt; looks just like &lt;code class=&quot;highlighter-rouge&quot;&gt;active&lt;/code&gt;, since the table inherently allows a second chance:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB Forwarding Table with filling server&quot; src=&quot;/images/glb-director-open-source-load-balancer/forwarding-table-filling.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This implementation requires that no more than one proxy server at a time is in any state other than &lt;code class=&quot;highlighter-rouge&quot;&gt;active&lt;/code&gt;, which in practise has worked well at GitHub. The state changes to proxy servers can happen as quickly as the longest connection duration that needs to be maintained. We’re working on extensions to the design that support more than just a primary and secondary, and some components (like the header listed below) already include initial support for arbitrary server lists.&lt;/p&gt;

&lt;h2 id=&quot;encapsulation-within-the-datacenter&quot;&gt;Encapsulation within the datacenter&lt;/h2&gt;

&lt;p&gt;We now have an algorithm to consistently pick backend proxy servers and operate on them, but how do we actually move packets around the datacenter? How do we encode the secondary server inside the packet so the primary can forward a packet it doesn’t understand?&lt;/p&gt;

&lt;p&gt;Traditionally in the LVS setup, an &lt;a href=&quot;https://en.wikipedia.org/wiki/IP_in_IP&quot;&gt;IP over IP (IPIP)&lt;/a&gt; tunnel is used. The client IP packet is encapsulated inside an internal datacenter IP packet and forwarded on to the proxy server, which decapsulates it. We found that it was difficult to encode the additional server metadata inside IPIP packets, as the only standard space available was the &lt;a href=&quot;https://en.wikipedia.org/wiki/Internet_Protocol_Options&quot;&gt;IP Options&lt;/a&gt;, and our datacenter routers passed packets with unknown IP options to software for processing (which they called “Layer 2 slow path”), taking speeds from millions to thousands of packets per second.&lt;/p&gt;

&lt;p&gt;To avoid this, we needed to hide the data inside a different packet format that the router wouldn’t try to understand. We initially adopted raw &lt;a href=&quot;https://lwn.net/Articles/614348/&quot;&gt;Foo-over-UDP (FOU)&lt;/a&gt; with a custom &lt;a href=&quot;https://en.wikipedia.org/wiki/Generic_Routing_Encapsulation&quot;&gt;Generic Route Encapsulation (GRE)&lt;/a&gt; payload, essentially encapsulating everything inside a UDP packet. We recently transitioned to &lt;a href=&quot;https://tools.ietf.org/html/draft-ietf-nvo3-gue-05&quot;&gt;Generic UDP Encapsulation (GUE)&lt;/a&gt;, which is a layer on top FOU which provides a standard for encapsulating IP protocols inside a UDP packet. We place our secondary server’s IP inside the private data of the GUE header. From a router’s perspective, these packets are all internal datacenter UDP packets between two normal servers.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt; 0                   1                   2                   3  
 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+\
|          Source port          |        Destination port       | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ UDP
|             Length            |            Checksum           | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+/
| 0 |C|   Hlen  |  Proto/ctype  |             Flags             | GUE
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|     Private data type (0)     |  Next hop idx |   Hop count   |\
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|                             Hop 0                             | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ GLB
|                              ...                              | private
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ data
|                             Hop N                             | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Another benefit to using UDP is that the source port can be filled in with a per-connection hash so that they are flow within the datacenter over different paths (where ECMP is used within the datacenter), and received on different RX queues on the proxy server’s NIC (which similarly use a hash of TCP/IP header fields). This is not possible with IPIP because most commodity datacenter NICs are only able to understand plain IP, TCP/IP and UDP/IP (and a few others). Notably, the NICs we use cannot look inside IP/IP packets.&lt;/p&gt;

&lt;p&gt;When the proxy server wants to send a packet back to the client, it doesn’t need to be encapsulated or travel back through our director tier, it can be sent directly to the client (often called “Direct Server Return”). This is typical of this sort of load balancer design and is especially useful for content providers where the majority of traffic flows &lt;em&gt;outbound&lt;/em&gt; with a relatively small amount of traffic &lt;em&gt;inbound&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This leaves us with a packet flow that looks like the following:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB second chance packet flow&quot; src=&quot;/images/glb-director-open-source-load-balancer/second-chance.png&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;dpdk-for-10g-line-rate-packet-processing&quot;&gt;DPDK for 10G+ line rate packet processing&lt;/h2&gt;

&lt;p&gt;Since we first &lt;a href=&quot;https://githubengineering.com/introducing-glb/&quot;&gt;publicly discussed our initial design&lt;/a&gt;, we’ve completely rewritten &lt;code class=&quot;highlighter-rouge&quot;&gt;glb-director&lt;/code&gt; to use &lt;a href=&quot;https://www.dpdk.org/&quot;&gt;DPDK&lt;/a&gt;, an open source project that allows &lt;em&gt;very&lt;/em&gt; fast packet processing from userland by bypassing the Linux kernel. This has allowed us to achieve NIC line rate processing on commodity NICs with commodity CPUs, and allows us to trivially scale our director tier to handle as much inbound traffic as our public connectivity requires. This is particularly important during DDoS attacks, where we do not want our load balancer to be a bottleneck.&lt;/p&gt;

&lt;p&gt;One of our initial goals with GLB was that our load balancer could run on commodity datacenter hardware without any server-specific physical configuration. Both GLB director and proxy servers are provisioned like normal servers in our datacenter. Each server has a &lt;a href=&quot;https://en.wikipedia.org/wiki/Link_aggregation&quot;&gt;bonded pair of network interfaces&lt;/a&gt;, and those interfaces are shared between DPDK and Linux on GLB director servers.&lt;/p&gt;

&lt;p&gt;Modern NICs support &lt;a href=&quot;https://en.wikipedia.org/wiki/Single-root_input/output_virtualization&quot;&gt;SR-IOV&lt;/a&gt;, a technology that enables a single NIC to act like multiple NICs from the perspective of the operating system. This is typically used by virtual machine hypervisors to ask the real NIC (“Physical Function”) to create multiple pretend NICs for each VM (“Virtual Functions”). To enable DPDK and the Linux kernel to share NICs, we use &lt;a href=&quot;https://doc.dpdk.org/guides/howto/flow_bifurcation.html&quot;&gt;flow bifurcation&lt;/a&gt;, which sends specific traffic (destined to GLB-run IP addresses) to our DPDK process on a Virtual Function while leaving the rest of the packets with the Linux kernel’s networking stack on the Physical Function.&lt;/p&gt;

&lt;p&gt;We’ve found that the packet processing rates of DPDK on a Virtual Function are acceptable for our requirements. GLB Director uses a &lt;a href=&quot;https://doc.dpdk.org/guides/prog_guide/packet_distrib_lib.html&quot;&gt;DPDK Packet Distributor&lt;/a&gt; pattern to spread the work of encapsulating packets across any number of CPU cores on the machine, and since it is stateless this can be highly parallelised.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB Flow Paths&quot; src=&quot;/images/glb-director-open-source-load-balancer/flow-paths.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;GLB Director supports matching and forwarding inbound IPv4 and IPv6 packets containing TCP payloads, as well as inbound ICMP Fragmentation Required messages used as part of &lt;a href=&quot;https://en.wikipedia.org/wiki/Path_MTU_Discovery&quot;&gt;Path MTU Discovery&lt;/a&gt;, by peeking into the inner layers of the packet during matching.&lt;/p&gt;

&lt;h2 id=&quot;bringing-test-suites-to-dpdk-with-scapy&quot;&gt;Bringing test suites to DPDK with Scapy&lt;/h2&gt;

&lt;p&gt;One problem that typically arises in creating (or using) technologies that operate at high speeds due to using low-level primitives (like communicating with the NIC directly) is that they become significantly more difficult to test. As part of creating the GLB Director, we also created a test environment that supports simple end-to-end packet flow testing of our DPDK application, by leveraging the way DPDK provides an &lt;a href=&quot;https://doc.dpdk.org/guides/prog_guide/env_abstraction_layer.html&quot;&gt;Environment Abstraction Layer (EAL)&lt;/a&gt; that allows a physical NIC and a libpcap-based local interface to appear the same from the view of the application.&lt;/p&gt;

&lt;p&gt;This allowed us to write tests in &lt;a href=&quot;https://scapy.net/&quot;&gt;Scapy&lt;/a&gt;, a wonderfully simple Python library for reading, manipulating and writing packet data. By creating a Linux &lt;a href=&quot;http://man7.org/linux/man-pages/man4/veth.4.html&quot;&gt;Virtual Ethernet Device&lt;/a&gt;, with Scapy on one side and DPDK on the other, we were able to pass in custom crafted packets and validate what our software would provide on the other side, being a fully GUE-encapsulated packet directed to the expected backend proxy server.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB's Scapy test setup&quot; src=&quot;/images/glb-director-open-source-load-balancer/scapy-setup.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;This allows us to test more complex behaviours such as traversing layers of ICMPv4/ICMPv6 headers to retrieve the original IPs and TCP ports for correct forwarding of ICMP messages from external routers.&lt;/p&gt;

&lt;h2 id=&quot;healthchecking-of-proxies-for-auto-failover&quot;&gt;Healthchecking of proxies for auto-failover&lt;/h2&gt;

&lt;p&gt;Part of the design of GLB is to handle server failure gracefully. The current design of having a designated primary/secondary for a given forwarding table entry / client means that we can work around single-server failure by running health checks from the perspective of each director. We run a service called &lt;code class=&quot;highlighter-rouge&quot;&gt;glb-healthcheck&lt;/code&gt; which continually validates each backend server’s GUE tunnel and arbitrary HTTP port.&lt;/p&gt;

&lt;p&gt;When a server fails, we swap the primary/secondary entries anywhere that server is primary. This performs a “soft drain” of the server, which provides the best chance for connections to gracefully fail over. If the healthcheck failure is a false positive, connections won’t be disrupted, they will just traverse a slightly different path.&lt;/p&gt;

&lt;h2 id=&quot;second-chance-on-proxies-with-iptables&quot;&gt;Second chance on proxies with iptables&lt;/h2&gt;

&lt;p&gt;The final component that makes up GLB is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Netfilter&quot;&gt;Netfilter&lt;/a&gt; module and &lt;a href=&quot;https://en.wikipedia.org/wiki/Iptables&quot;&gt;iptables&lt;/a&gt; target that runs on every proxy server and allows the “second chance” design to function.&lt;/p&gt;

&lt;p&gt;This module provides a simple task deciding whether the inner TCP/IP packet inside every GUE packet is valid locally according to the Linux kernel TCP stack, and if it isn’t, forwards it to the next proxy server (the secondary) rather than decapsulating it locally.&lt;/p&gt;

&lt;p&gt;In the case where a packet is a SYN (new connection) or is valid locally for an established connection, it simply accepts it locally. We then use the Linux kernel 4.x GUE support provided as part of the &lt;code class=&quot;highlighter-rouge&quot;&gt;fou&lt;/code&gt; module to receive the GUE packet and process it locally.&lt;/p&gt;

&lt;h2 id=&quot;available-today-as-open-source&quot;&gt;Available today as open source&lt;/h2&gt;

&lt;p&gt;When we started down the path of writing a better datacenter load balancer, we decided that we wanted to release it open source so that others could benefit from and share in our work. We’re excited to be releasing all the components discussed here as open source at &lt;a href=&quot;https://github.com/github/glb-director&quot;&gt;github/glb-director&lt;/a&gt;. We hope this will allow others to reuse our work and contribute to a common standard software load balancing solution that runs on commodity hardware in physical datacenter environments.&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;GLB component overview&quot; src=&quot;/images/glb-director-open-source-load-balancer/glb-component-overview.png&quot; /&gt;
&lt;/div&gt;

&lt;h2 id=&quot;also-were-hiring&quot;&gt;Also, we’re hiring!&lt;/h2&gt;

&lt;p&gt;GLB and the GLB Director has been an ongoing project designed, authored, reviewed and supported by various members of GitHub’s Production Engineering organisation, including &lt;a href=&quot;https://github.com/joewilliams&quot;&gt;@joewilliams&lt;/a&gt;, &lt;a href=&quot;https://github.com/nautalice&quot;&gt;@nautalice&lt;/a&gt;, &lt;a href=&quot;https://github.com/ross&quot;&gt;@ross&lt;/a&gt;, &lt;a href=&quot;https://github.com/theojulienne&quot;&gt;@theojulienne&lt;/a&gt; and many others. If you’re interested in joining us in building great infrastructure projects like GLB, our Data Center team is hiring production engineers specialising in &lt;a href=&quot;https://boards.greenhouse.io/github/jobs/1138733&quot;&gt;Traffic Systems&lt;/a&gt;, &lt;a href=&quot;https://boards.greenhouse.io/github/jobs/1141785&quot;&gt;Network&lt;/a&gt; and &lt;a href=&quot;https://boards.greenhouse.io/github/jobs/1134999&quot;&gt;Facilities&lt;/a&gt;.&lt;/p&gt;</content><author><name>Theo Julienne</name></author><summary type="html">At GitHub, we serve tens of thousands of requests every second out of our network edge, operating on GitHub’s metal cloud. We’ve previously introduced GLB, our scalable load balancing solution for bare metal datacenters, which powers the majority of GitHub’s public web and git traffic, as well as fronting some of our most critical internal systems such as highly available MySQL clusters. Today we’re excited to share more details about our load balancer’s design, as well as release the GLB Director as open source.</summary></entry><entry><title type="html">MySQL High Availability at GitHub</title><link href="https://githubengineering.com/mysql-high-availability-at-github/" rel="alternate" type="text/html" title="MySQL High Availability at GitHub" /><published>2018-06-20T00:00:00+00:00</published><updated>2018-06-20T00:00:00+00:00</updated><id>https://githubengineering.com/mysql-high-availability-at-github</id><content type="html" xml:base="https://githubengineering.com/mysql-high-availability-at-github/">&lt;p&gt;GitHub uses MySQL as its main datastore for all things non-&lt;code class=&quot;highlighter-rouge&quot;&gt;git&lt;/code&gt;, and its availability is critical to GitHub’s operation. The site itself, GitHub’s API, authentication and more, all require database access. We run multiple MySQL clusters serving our different services and tasks. Our clusters use classic master-replicas setup, where a single node in a cluster (the &lt;em&gt;master&lt;/em&gt;) is able to accept writes. The rest of the cluster nodes (the &lt;em&gt;replicas&lt;/em&gt;) asynchronously replay changes from the master and serve our read traffic.&lt;/p&gt;

&lt;p&gt;The availability of master nodes is particularly critical. With no master, a cluster cannot accept writes: any writes that need to be persisted cannot be persisted. Any incoming changes such as commits, issues, user creation, reviews, new repositories, etc., would fail.&lt;/p&gt;

&lt;p&gt;To support writes we clearly need to have an available writer node, a master of a cluster. But just as important, we need to be able to identify, or &lt;em&gt;discover&lt;/em&gt;, that node.&lt;/p&gt;

&lt;p&gt;On a failure, say a master box crash scenario, we must ensure the existence of a new master, as well as be able to quickly advertise its identity. The time it takes to detect a failure, run the failover and advertise the new master’s identity makes up the total outage time.&lt;/p&gt;

&lt;p&gt;This post illustrates GitHub’s MySQL high availability and master service discovery solution, which allows us to reliably run a cross-data-center operation, be tolerant of data center isolation, and achieve short outage times on a failure.&lt;/p&gt;

&lt;h2 id=&quot;high-availability-objectives&quot;&gt;High availability objectives&lt;/h2&gt;

&lt;p&gt;The solution described in this post iterates on, and improves, previous high availability (HA) solutions implemented at GitHub. As we scale, our MySQL HA strategy must adapt to changes. We wish to have similar HA strategies for our MySQL and for other services within GitHub.&lt;/p&gt;

&lt;p&gt;When considering high availability and service discovery, some questions can guide your path into an appropriate solution. An incomplete list may include:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;How much outage time can you tolerate?&lt;/li&gt;
  &lt;li&gt;How reliable is crash detection? Can you tolerate false positives (premature failovers)?&lt;/li&gt;
  &lt;li&gt;How reliable is failover? Where can it fail?&lt;/li&gt;
  &lt;li&gt;How well does the solution work cross-data-center? On low and high latency networks?&lt;/li&gt;
  &lt;li&gt;Will the solution tolerate a complete data center (DC) failure or network isolation?&lt;/li&gt;
  &lt;li&gt;What mechanism, if any, prevents or mitigates split-brain scenarios (two servers claiming to be the master of a given cluster, both independently and unknowingly to each other accepting writes)?&lt;/li&gt;
  &lt;li&gt;Can you afford data loss? To what extent?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To illustrate some of the above, let’s first consider our previous HA iteration, and why we changed it.&lt;/p&gt;

&lt;h2 id=&quot;moving-away-from-vip-and-dns-based-discovery&quot;&gt;Moving away from VIP and DNS based discovery&lt;/h2&gt;

&lt;p&gt;In our previous iteration, we used:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://githubengineering.com/orchestrator-github/&quot;&gt;orchestrator&lt;/a&gt; for detection and failover, and&lt;/li&gt;
  &lt;li&gt;VIP and DNS for master discovery.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In that iteration, clients discovered the writer node by using a name, e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;mysql-writer-1.github.net&lt;/code&gt;. The name resolved to a Virtual IP address (VIP) which the master host would acquire.&lt;/p&gt;

&lt;p&gt;Thus, on a normal day, clients would just resolve the name, connect to the resolved IP, and find the master listening on the other side.&lt;/p&gt;

&lt;p&gt;Consider this replication topology, spanning three different data centers:&lt;/p&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;sample 3 data center topology&quot; src=&quot;/images/mysql-high-availability-at-github/sample-3dc-topology.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;In the event of a master failure, a new server, one of the replicas, must be promoted in its place.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; will detect a failure, promote a new master, and then act to reassign the name/VIP. Clients don’t actually know the identity of the master: all they have is a &lt;em&gt;name&lt;/em&gt;, and that name must now resolve to the new master. However, consider:&lt;/p&gt;

&lt;p&gt;VIPs are cooperative: they are claimed and owned by the database servers themselves. To acquire or release a VIP, a server must send an ARP request. The server owning the VIP must first release it before the newly promoted master acquires it. This has some undesired effects:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;An orderly failover operation will first contact the dead master and request that it release the VIP, and then contact the newly promoted master and request that it grab the VIP. What if the old master cannot be reached or refuses to release the VIP? Given that there’s a failure scenario on that server in the first place, it is not unlikely that it would fail to respond in a timely manner, or indeed respond at all.
    &lt;ul&gt;
      &lt;li&gt;We can end up with a split-brain: two hosts claiming to have the same VIP. Different clients may connect to either of those servers, depending on the shortest network path.&lt;/li&gt;
      &lt;li&gt;The source of truth here depends on the cooperation of two independent servers, and this setup is unreliable.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Even if the old master does cooperate, the workflow wastes precious time: the switch to the new master waits while we contact the old master.&lt;/li&gt;
  &lt;li&gt;And even as the VIP changes, existing client connections are not guaranteed to disconnect from the old server, and we may still experience a split-brain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In parts of our setup VIPs are bound by physical location. They are owned by a switch or a router. Thus, we can only reassign the VIPs onto co-located servers. In particular, in some cases we cannot assign the VIP to a server promoted in a different data center, and must make a DNS change.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;DNS changes take longer to propagate. Clients cache DNS names for a preconfigured time. A cross-DC failover implies more outage time: it will take more time to make all clients aware of the identity of the new master.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These limitations alone were enough to push us in search of a new solution, but for even more consideration were:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Masters were self-injecting themselves with heartbeats via the &lt;code class=&quot;highlighter-rouge&quot;&gt;pt-heartbeat&lt;/code&gt; service, for the purpose of &lt;a href=&quot;https://githubengineering.com/mitigating-replication-lag-and-reducing-read-load-with-freno/&quot;&gt;lag measurement and throttling control&lt;/a&gt;. The service had to be kicked off on the newly promoted master. If possible, the service would be shut down on the old master.&lt;/li&gt;
  &lt;li&gt;Likewise, &lt;a href=&quot;https://github.com/github/orchestrator/blob/master/docs/pseudo-gtid.md&quot;&gt;Pseudo-GTID&lt;/a&gt; injection was self-managed by the masters. It would need to kick off on the new master, and preferably stop on the old master.&lt;/li&gt;
  &lt;li&gt;The new master was set as writable. The old master was to be set as &lt;code class=&quot;highlighter-rouge&quot;&gt;read_only&lt;/code&gt;, if possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These extra steps were a contributing factor to the total outage time and introduced their own failures and friction.&lt;/p&gt;

&lt;p&gt;The solution worked, and GitHub has had successful MySQL failovers that went well under the radar, but we wanted our HA to improve on the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Be data center agnostic.&lt;/li&gt;
  &lt;li&gt;Be tolerant of data center failure.&lt;/li&gt;
  &lt;li&gt;Remove unreliable cooperative workflows.&lt;/li&gt;
  &lt;li&gt;Reduce total outage time.&lt;/li&gt;
  &lt;li&gt;As much as possible, have lossless failovers.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;githubs-ha-solution-orchestrator-consul-glb&quot;&gt;GitHub’s HA solution: orchestrator, Consul, GLB&lt;/h2&gt;

&lt;p&gt;Our new strategy, along with collateral improvements, solves or mitigates much of the concerns above. In today’s HA setup, we have:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/github/orchestrator&quot;&gt;orchestrator&lt;/a&gt; to run detection and failovers. We use a cross-DC &lt;a href=&quot;https://github.com/github/orchestrator/blob/master/docs/raft.md&quot;&gt;orchestrator/raft&lt;/a&gt; setup as depicted below.&lt;/li&gt;
  &lt;li&gt;Hashicorp’s &lt;a href=&quot;https://www.consul.io/&quot;&gt;Consul&lt;/a&gt; for service discovery.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://githubengineering.com/glb-director-open-source-load-balancer/&quot;&gt;GLB/HAProxy&lt;/a&gt; as a proxy layer between clients and writer nodes. Our GLB director is &lt;a href=&quot;https://github.com/github/glb-director&quot;&gt;open sourced&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;anycast&lt;/code&gt; for network routing.&lt;/li&gt;
&lt;/ul&gt;

&lt;div style=&quot;text-align:center&quot;&gt;
&lt;img alt=&quot;MySQL HA solution at GitHub&quot; src=&quot;/images/mysql-high-availability-at-github/mysql-ha-solution-at-github.png&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;The new setup removes VIP and DNS changes altogether. And while we introduce more components, we are able to decouple the components and simplify the task, as well as be able to utilize solid and stable solutions. A breakdown follows.&lt;/p&gt;

&lt;h3 id=&quot;a-normal-flow&quot;&gt;A normal flow&lt;/h3&gt;

&lt;p&gt;On a normal day the apps connect to the write nodes through GLB/HAProxy.&lt;/p&gt;

&lt;p&gt;The apps are never aware of the master’s identity. As before, they use a name. For example, the master for &lt;code class=&quot;highlighter-rouge&quot;&gt;cluster1&lt;/code&gt; would be &lt;code class=&quot;highlighter-rouge&quot;&gt;mysql-writer-1.github.net&lt;/code&gt;. In our current setup, however, this name gets resolved to an &lt;a href=&quot;https://en.wikipedia.org/wiki/Anycast&quot;&gt;anycast&lt;/a&gt; IP.&lt;/p&gt;

&lt;p&gt;With &lt;code class=&quot;highlighter-rouge&quot;&gt;anycast&lt;/code&gt;, the name resolves to the same IP everywhere, but traffic is routed differently based on a client’s location. In particular, in each of our data centers we have GLB, our highly available load balancer, deployed on multiple boxes. Traffic to &lt;code class=&quot;highlighter-rouge&quot;&gt;mysql-writer-1.github.net&lt;/code&gt; always routes to the local data center’s GLB cluster. Thus, all clients are served by local proxies.&lt;/p&gt;

&lt;p&gt;We run GLB on top of &lt;a href=&quot;https://www.haproxy.com&quot;&gt;HAProxy&lt;/a&gt;. Our HAProxy has &lt;em&gt;writer pools&lt;/em&gt;: one pool per MySQL cluster, where each pool has exactly one backend server: the cluster’s &lt;em&gt;master&lt;/em&gt;. All GLB/HAProxy boxes in all DCs have the exact same pools, and they all indicate the exact same backend servers in these pools. Thus, if an app wishes to write to &lt;code class=&quot;highlighter-rouge&quot;&gt;mysql-writer-1.github.net&lt;/code&gt;, it matters not which GLB server it connects to. It will always get routed to the actual &lt;code class=&quot;highlighter-rouge&quot;&gt;cluster1&lt;/code&gt; master node.&lt;/p&gt;

&lt;p&gt;As far as the apps are concerned, discovery ends at GLB, and there is never a need for re-discovery. It’s all on GLB to route the traffic to the correct destination.&lt;/p&gt;

&lt;p&gt;How does GLB know which servers to list as backends, and how do we propagate changes to GLB?&lt;/p&gt;

&lt;h3 id=&quot;discovery-via-consul&quot;&gt;Discovery via Consul&lt;/h3&gt;

&lt;p&gt;Consul is well known as a service discovery solution, and also offers DNS services. In our solution, however, we utilize it as a highly available key-value (KV) store.&lt;/p&gt;

&lt;p&gt;Within Consul’s KV store we write the identities of cluster masters. For each cluster, there’s a set of KV entries indicating the cluster’s master &lt;code class=&quot;highlighter-rouge&quot;&gt;fqdn&lt;/code&gt;, port, ipv4, ipv6.&lt;/p&gt;

&lt;p&gt;Each GLB/HAProxy node runs &lt;a href=&quot;https://github.com/hashicorp/consul-template&quot;&gt;consul-template&lt;/a&gt;: a service that listens on changes to Consul data (in our case: changes to clusters masters data). &lt;code class=&quot;highlighter-rouge&quot;&gt;consul-template&lt;/code&gt; produces a valid config file and is able to reload HAProxy upon changes to the config.&lt;/p&gt;

&lt;p&gt;Thus, a change in Consul to a master’s identity is observed by each GLB/HAProxy box, which then reconfigures itself, sets the new master as the single entity in a cluster’s backend pool, and reloads to reflect those changes.&lt;/p&gt;

&lt;p&gt;At GitHub we have a Consul setup in each data center, and each setup is highly available. However, these setups are independent of each other. They do not replicate between each other and do not share any data.&lt;/p&gt;

&lt;p&gt;How does Consul get told of changes, and how is the information distributed cross-DC?&lt;/p&gt;

&lt;h3 id=&quot;orchestratorraft&quot;&gt;orchestrator/raft&lt;/h3&gt;

&lt;p&gt;We run an &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator/raft&lt;/code&gt; setup: &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; nodes communicate to each other via &lt;a href=&quot;http://raft.github.io/&quot;&gt;raft&lt;/a&gt; consensus. We have one or two &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; nodes per data center.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; is charged with failure detection, with MySQL failover, and with communicating the change of master to Consul. Failover is operated by the single &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator/raft&lt;/code&gt; leader node, but the &lt;em&gt;change&lt;/em&gt;, the news that a cluster now has a new master, is propagated to all &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; nodes through the &lt;code class=&quot;highlighter-rouge&quot;&gt;raft&lt;/code&gt; mechanism.&lt;/p&gt;

&lt;p&gt;As &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; nodes receive the news of a master change, they each communicate to their local Consul setups: they each invoke a KV write. DCs with more than one &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; representative will have multiple (identical) writes to Consul.&lt;/p&gt;

&lt;h3 id=&quot;putting-the-flow-together&quot;&gt;Putting the flow together&lt;/h3&gt;

&lt;p&gt;In a master crash scenario:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; nodes detect failures.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator/raft&lt;/code&gt; leader kicks off a recovery. A new master gets promoted.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator/raft&lt;/code&gt; advertises the master change to all &lt;code class=&quot;highlighter-rouge&quot;&gt;raft&lt;/code&gt; cluster nodes.&lt;/li&gt;
  &lt;li&gt;Each &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator/raft&lt;/code&gt; member receives a leader change notification. They each update the local Consul’s KV store with the identity of the new master.&lt;/li&gt;
  &lt;li&gt;Each GLB/HAProxy has &lt;code class=&quot;highlighter-rouge&quot;&gt;consul-template&lt;/code&gt; running, which observes the change in Consul’s KV store, and reconfigures and reloads HAProxy.&lt;/li&gt;
  &lt;li&gt;Client traffic gets redirected to the new master.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is a clear ownership of responsibilities for each component, and the entire design is both decoupled as well as simplified. &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; doesn’t know about the load balancers. Consul doesn’t need to know where the information came from. Proxies only care about Consul. Clients only care about the proxy.&lt;/p&gt;

&lt;p&gt;Furthermore:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There are no DNS changes to propagate.&lt;/li&gt;
  &lt;li&gt;There is no TTL.&lt;/li&gt;
  &lt;li&gt;The flow does not need the dead master’s cooperation. It is largely ignored.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;additional-details&quot;&gt;Additional details&lt;/h3&gt;

&lt;p&gt;To further secure the flow, we also have the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;HAProxy is configured with a very short &lt;code class=&quot;highlighter-rouge&quot;&gt;hard-stop-after&lt;/code&gt;. When it reloads with a new backend server in a writer-pool, it automatically terminates any existing connections to the old master.
    &lt;ul&gt;
      &lt;li&gt;With &lt;code class=&quot;highlighter-rouge&quot;&gt;hard-stop-after&lt;/code&gt; we don’t even require cooperation from the clients, and this mitigates a split-brain scenario. It’s noteworthy that this isn’t hermetic, and &lt;em&gt;some time&lt;/em&gt; passes before we kill old connections. But there’s then a point in time after which we’re comfortable and expect no nasty surprises.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;We do not strictly require Consul to be available at all times. In fact, we only need it to be available at failover time. If Consul happens to be down, GLB continues to operate with the last known values and makes no drastic moves.&lt;/li&gt;
  &lt;li&gt;GLB is set to validate the identity of the newly promoted master. Similarly to our &lt;a href=&quot;https://githubengineering.com/context-aware-mysql-pools-via-haproxy/&quot;&gt;context-aware MySQL pools&lt;/a&gt;, a check is made on the backend server, to confirm it is indeed a writer node. If we happen to delete the master’s identity in Consul, no problem; the empty entry is ignored. If we mistakenly write the name of a non-master server in Consul, no problem; GLB will refuse to update it and keep running with last known state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We further tackle concerns and pursue HA objectives in the following sections.&lt;/p&gt;

&lt;h2 id=&quot;orchestratorraft-failure-detection&quot;&gt;orchestrator/raft failure detection&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; uses a &lt;a href=&quot;https://github.com/github/orchestrator/blob/master/docs/failure-detection.md&quot;&gt;holistic approach&lt;/a&gt; to detecting failure, and as such it is very reliable. We do not observe false positives: we do not have premature failovers, and thus do not suffer unnecessary outage time.&lt;/p&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator/raft&lt;/code&gt; further tackles the case for a complete DC network isolation (aka DC fencing). A DC network isolation can cause confusion: servers within that DC can talk to each other. Is it &lt;em&gt;they&lt;/em&gt; that are network isolated from other DCs, or is it &lt;em&gt;other DCs&lt;/em&gt; that are being network isolated?&lt;/p&gt;

&lt;p&gt;In an &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator/raft&lt;/code&gt; setup, the &lt;code class=&quot;highlighter-rouge&quot;&gt;raft&lt;/code&gt; leader node is the one to run the failovers. A leader is a node that gets the support of the majority of the group (quorum). Our &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; node deployment is such that no single data center makes a majority, and any &lt;code class=&quot;highlighter-rouge&quot;&gt;n-1&lt;/code&gt; DCs do.&lt;/p&gt;

&lt;p&gt;In the event of a complete DC network isolation, the &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; nodes in that DC get disconnected from their peers in other DCs. As a result, the &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; nodes in the isolated DC cannot be the leaders of the &lt;code class=&quot;highlighter-rouge&quot;&gt;raft&lt;/code&gt; cluster. If any such node did happen to be the leader, it steps down. A new leader will be assigned from any of the other DCs. That leader will have the support of all the other DCs, which are capable of communicating between themselves.&lt;/p&gt;

&lt;p&gt;Thus, the &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; node that calls the shots will be one that is outside the network isolated data center. Should there be a master in an isolated DC, &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; will initiate the failover to replace it with a server in one of the available DCs. We mitigate DC isolation by delegating the decision making to the quorum in the non-isolated DCs.&lt;/p&gt;

&lt;h2 id=&quot;quicker-advertisement&quot;&gt;Quicker advertisement&lt;/h2&gt;

&lt;p&gt;Total outage time can further be reduced by advertising the master change sooner. How can that be achieved?&lt;/p&gt;

&lt;p&gt;When &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; begins a failover, it observes the fleet of servers available to be promoted. Understanding replication rules and abiding by hints and limitations, it is able to make an educated decision on the best course of action.&lt;/p&gt;

&lt;p&gt;It may recognize that a server available for promotion is also an &lt;em&gt;ideal candidate&lt;/em&gt;, such that:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;There is nothing to prevent the promotion of the server (and potentially the user has hinted that such server is preferred for promotion), and&lt;/li&gt;
  &lt;li&gt;The server is expected to be able to take all of its siblings as replicas.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In such a case &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; proceeds to first set the server as writable, and immediately advertises the promotion of the server (writes to Consul KV in our case), even while asynchronously beginning to fix the replication tree, an operation that will typically take a few more seconds.&lt;/p&gt;

&lt;p&gt;It is likely that by the time our GLB servers have been fully reloaded, the replication tree is already intact, but it is not strictly required. The server is good to receive writes!&lt;/p&gt;

&lt;h2 id=&quot;semi-synchronous-replication&quot;&gt;Semi-synchronous replication&lt;/h2&gt;

&lt;p&gt;In MySQL’s &lt;a href=&quot;https://dev.mysql.com/doc/refman/en/replication-semisync.html&quot;&gt;semi-synchronous replication&lt;/a&gt; a master does not acknowledge a transaction commit until the change is known to have shipped to one or more replicas. It provides a way to achieve lossless failovers: any change applied on the master is either applied or waiting to be applied on one of the replicas.&lt;/p&gt;

&lt;p&gt;Consistency comes with a cost: a risk to availability. Should no replica acknowledge receipt of changes, the master will block and writes will stall. Fortunately, there is a timeout configuration, after which the master can revert back to asynchronous replication mode, making writes available again.&lt;/p&gt;

&lt;p&gt;We have set our timeout at a reasonably low value: &lt;code class=&quot;highlighter-rouge&quot;&gt;500ms&lt;/code&gt;. It is more than enough to ship changes from the master to local DC replicas, and typically also to remote DCs. With this timeout we observe perfect semi-sync behavior (no fallback to asynchronous replication), as well as feel comfortable with a very short blocking period in case of acknowledgement failure.&lt;/p&gt;

&lt;p&gt;We enable semi-sync on local DC replicas, and in the event of a master’s death, we expect (though do not strictly enforce) a lossless failover. Lossless failover on a complete DC failure is costly and we do not expect it.&lt;/p&gt;

&lt;p&gt;While experimenting with semi-sync timeout, we also observed a behavior that plays to our advantage: we are able to influence the identity of the &lt;em&gt;ideal candidate&lt;/em&gt; in the event of a master failure. By enabling semi-sync on designated servers, and by marking them as &lt;em&gt;candidates&lt;/em&gt;, we are able to reduce total outage time by &lt;em&gt;affecting&lt;/em&gt; the outcome of a failure. In our &lt;a href=&quot;https://githubengineering.com/mysql-testing-automation-at-github/&quot;&gt;experiments&lt;/a&gt; we observe that we typically end up with the &lt;em&gt;ideal candidates&lt;/em&gt;, and hence run quick advertisements.&lt;/p&gt;

&lt;h2 id=&quot;heartbeat-injection&quot;&gt;Heartbeat injection&lt;/h2&gt;

&lt;p&gt;Instead of managing the startup/shutdown of the &lt;code class=&quot;highlighter-rouge&quot;&gt;pt-heartbeat&lt;/code&gt; service on promoted/demoted masters, we opted to run it everywhere at all times. This required some &lt;a href=&quot;https://github.com/percona/percona-toolkit/pull/302/files?w=1&quot;&gt;patching&lt;/a&gt; so as to make &lt;code class=&quot;highlighter-rouge&quot;&gt;pt-heartbeat&lt;/code&gt; comfortable with servers either changing their &lt;code class=&quot;highlighter-rouge&quot;&gt;read_only&lt;/code&gt; state back and forth or completely crashing.&lt;/p&gt;

&lt;p&gt;In our current setup &lt;code class=&quot;highlighter-rouge&quot;&gt;pt-heartbeat&lt;/code&gt; services run on masters and on replicas. On masters, they generate the heartbeat events. On replicas, they identify that the servers are &lt;code class=&quot;highlighter-rouge&quot;&gt;read-only&lt;/code&gt; and routinely recheck their status. As soon as a server is promoted as master, &lt;code class=&quot;highlighter-rouge&quot;&gt;pt-heartbeat&lt;/code&gt; on that server identifies the server as writable and begins injecting heartbeat events.&lt;/p&gt;

&lt;h2 id=&quot;orchestrator-ownership-delegation&quot;&gt;orchestrator ownership delegation&lt;/h2&gt;

&lt;p&gt;We further delegated to orchestrator:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Pseudo-GTID injection,&lt;/li&gt;
  &lt;li&gt;Setting the promoted master as writable, clearing its replication state, and&lt;/li&gt;
  &lt;li&gt;Setting the old master as &lt;code class=&quot;highlighter-rouge&quot;&gt;read_only&lt;/code&gt;, if possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On all things new-master, this reduces friction. A master that is just being promoted is clearly expected to be alive and accessible, or else we would not promote it. It makes sense, then, to let &lt;code class=&quot;highlighter-rouge&quot;&gt;orchestrator&lt;/code&gt; apply changes directly to the promoted master.&lt;/p&gt;

&lt;h2 id=&quot;limitations-and-drawbacks&quot;&gt;Limitations and drawbacks&lt;/h2&gt;

&lt;p&gt;The proxy layer makes the apps unaware of the master’s identity, but it also masks the apps’ identities from the master. All the master sees are connections coming from the proxy layer, and we lose information about the actual source of the connection.&lt;/p&gt;

&lt;p&gt;As distributed systems go, we are still left with unhandled scenarios.&lt;/p&gt;

&lt;p&gt;Notably, on a data center isolation scenario, and assuming a master is in the isolated DC, apps in that DC are still able to write to the master. This may result in state inconsistency once network is brought back up. We are working to mitigate this split-brain by implementing a reliable &lt;a href=&quot;https://en.wikipedia.org/wiki/STONITH&quot;&gt;STONITH&lt;/a&gt; from within the very isolated DC. As before, &lt;em&gt;some time&lt;/em&gt; will pass before bringing down the master, and there could be a short period of split-brain. The operational cost of avoiding split-brains altogether is very high.&lt;/p&gt;

&lt;p&gt;More scenarios exist: the outage of Consul at the time of the failover; partial DC isolation; others. We understand that with distributed systems of this nature it is impossible to close all of the loopholes, so we focus on the most important cases.&lt;/p&gt;

&lt;h2 id=&quot;the-results&quot;&gt;The results&lt;/h2&gt;

&lt;p&gt;Our orchestrator/GLB/Consul setup provides us with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Reliable failure detection,&lt;/li&gt;
  &lt;li&gt;Data center agnostic failovers,&lt;/li&gt;
  &lt;li&gt;Typically lossless failovers,&lt;/li&gt;
  &lt;li&gt;Data center network isolation support,&lt;/li&gt;
  &lt;li&gt;Split-brain mitigation (more in the works),&lt;/li&gt;
  &lt;li&gt;No cooperation dependency,&lt;/li&gt;
  &lt;li&gt;Between &lt;code class=&quot;highlighter-rouge&quot;&gt;10 and 13 seconds&lt;/code&gt; of total outage time in most cases.
    &lt;ul&gt;
      &lt;li&gt;We see up to &lt;code class=&quot;highlighter-rouge&quot;&gt;20 seconds&lt;/code&gt; of total outage time in less frequent cases, and up to &lt;code class=&quot;highlighter-rouge&quot;&gt;25 seconds&lt;/code&gt; in extreme cases.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The orchestration/proxy/service-discovery paradigm uses well known and trusted components in a decoupled architecture, which makes it easier to deploy, operate and observe, and where each component can independently scale up or down. We continue to seek improvements as we continuously test our setup.&lt;/p&gt;</content><author><name>Shlomi Noach</name></author><summary type="html">GitHub uses MySQL as its main datastore for all things non-git, and its availability is critical to GitHub’s operation. The site itself, GitHub’s API, authentication and more, all require database access. We run multiple MySQL clusters serving our different services and tasks. Our clusters use classic master-replicas setup, where a single node in a cluster (the master) is able to accept writes. The rest of the cluster nodes (the replicas) asynchronously replay changes from the master and serve our read traffic.</summary></entry><entry><title type="html">Performance Impact of Removing OOBGC</title><link href="https://githubengineering.com/removing-oobgc/" rel="alternate" type="text/html" title="Performance Impact of Removing OOBGC" /><published>2018-05-18T00:00:00+00:00</published><updated>2018-05-18T00:00:00+00:00</updated><id>https://githubengineering.com/removing-oobgc</id><content type="html" xml:base="https://githubengineering.com/removing-oobgc/">&lt;p&gt;Until last week, GitHub used an Out of Band Garbage Collector (OOBGC) in production.  Since removing it, we decreased CPU time across our production machines by 10%.  Let’s talk about what an OOBGC is, when to use it, and when not to use it.  Then follow up with some statistics about the impact of removing it from GitHub’s stack.&lt;/p&gt;

&lt;h2 id=&quot;what-is-an-out-of-band-garbage-collector&quot;&gt;What is an Out of Band Garbage Collector?&lt;/h2&gt;

&lt;p&gt;An OOBGC is not really a Garbage Collector, but more of a technique to use when deciding &lt;em&gt;when&lt;/em&gt; to collect garbage in your program.  Instead of allowing the GC to run normally, the GC is stopped before processing a web request, then restarted after the response has been sent to the client.  Meaning that garbage collection occurs “out of band” of request and response processing.&lt;/p&gt;

&lt;h2 id=&quot;when-to-use-an-out-of-band-garbage-collector&quot;&gt;When to use an Out of Band Garbage Collector&lt;/h2&gt;

&lt;p&gt;Ruby’s GC is a “stop the world, mark and sweep” collector.  Which means that when the GC runs, your program pauses, and when the GC finishes your program resumes.  The time your program is paused is called “pause time”, and while your program is paused it can’t do anything.  Historically, Ruby’s GC would pause the program for long periods of time.  We would rather clients don’t wait around for the GC to run, so only executing GC after each request made sense.&lt;/p&gt;

&lt;h2 id=&quot;when-not-to-use-an-out-of-band-garbage-collector&quot;&gt;When not to use an Out of Band Garbage Collector&lt;/h2&gt;

&lt;p&gt;In the past years, Ruby’s Garbage Collector has undergone many performance improvements.  These changes include: becoming a generational collector, incremental marking, and lazy sweeping.  A generational collector reduces the overall amount of work the GC needs to do.  Incremental marking and lazy sweeping mean that the GC can execute concurrently with your program.  What these techniques add up to is less time spent in GC, and higher throughput of your program.&lt;/p&gt;

&lt;p&gt;Since the OOBGC runs the GC after the response is finished, it can cause the web worker to take longer in order to be ready to process the next incoming request.  This means that clients can suffer from latency due to queuing wait times.&lt;/p&gt;

&lt;p&gt;If a particular request doesn’t allocate enough garbage to warrant a GC execution under normal conditions, then the OOBGC could cause the process to do more work than it would have without the OOBGC.&lt;/p&gt;

&lt;p&gt;Finally, the OOBGC can cause full collections (examining old and new objects) which defeats the generational GC optimizations.&lt;/p&gt;

&lt;p&gt;GitHub has been using Ruby in production for a long time, and at the time adding an OOBGC made sense and worked well.  However, it is always good to question assumptions, especially after technological advancements such as the improvements made in Ruby’s GC.  We wanted to see if running an OOBGC was still necessary for our application after upgrading to Ruby 2.4, so we decided to remove it and observe the impact.&lt;/p&gt;

&lt;h2 id=&quot;impact-of-removing-the-oobgc&quot;&gt;Impact of removing the OOBGC&lt;/h2&gt;

&lt;p&gt;After removing the OOBGC, we saw a 10% drop in Kubernetes cluster CPU utilization:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/469234/39878466-6cd017f4-5446-11e8-8961-521bc43b6988.png&quot; alt=&quot;Kubernetes CPU drop&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This graph compares cluster CPU utilization from the current day, previous day, and previous week:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/469234/39878574-b953997a-5446-11e8-9779-19ccc16165e6.png&quot; alt=&quot;Utilization Comparison&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The blue line is CPU utilization for the day the patch went out.  You can see a great drop around 15:20.&lt;/p&gt;

&lt;p&gt;This graph shows the difference in core utilization before and after OOBGC removal.  In other words “number of cores used yesterday” minus “number of cores used today”:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/469234/39877963-367924a8-5445-11e8-9758-7fc01e002a7b.png&quot; alt=&quot;Difference in core usage&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We saw a savings of between 400 and around 1000 cores depending on usage at that point in the day.&lt;/p&gt;

&lt;p&gt;Finally, removing OOBGC reduced average response times by about 25% (the gray line is with OOBGC, the blue line is without):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/469234/39877883-0a48b236-5445-11e8-8678-b13fe7fc77d1.png&quot; alt=&quot;Response times&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Of course, removing OOBGC was not an all around win.  Incremental marking and lazy sweeping amortize the cost of memory collection over time.  This means that memory usage will increase on average, and that is what we observed in production:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/469234/39879157-13ba5d58-5448-11e8-9443-f59a3fc6808b.png&quot; alt=&quot;Memory usage&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;For our application, the CPU savings far outdid the price we had to pay in average memory usage.  Removing the OOBGC from our system resulted in a great savings for our systems.  Taking measurements, acting on data, and questioning assumptions is one of the most difficult and fun parts of being an engineer.  This time it paid off for us, and hopefully this post can help you too!&lt;/p&gt;</content><author><name>tenderlove</name></author><summary type="html">Until last week, GitHub used an Out of Band Garbage Collector (OOBGC) in production. Since removing it, we decreased CPU time across our production machines by 10%. Let’s talk about what an OOBGC is, when to use it, and when not to use it. Then follow up with some statistics about the impact of removing it from GitHub’s stack.</summary></entry><entry><title type="html">Improving your OSS dependency workflow with Licensed</title><link href="https://githubengineering.com/improving-your-oss-dependency-workflow-with-licensed/" rel="alternate" type="text/html" title="Improving your OSS dependency workflow with Licensed" /><published>2018-03-07T00:00:00+00:00</published><updated>2018-03-07T00:00:00+00:00</updated><id>https://githubengineering.com/improving-your-oss-dependency-workflow-with-licensed</id><content type="html" xml:base="https://githubengineering.com/improving-your-oss-dependency-workflow-with-licensed/">&lt;p&gt;GitHub recently open sourced &lt;a href=&quot;https://github.com/github/licensed&quot;&gt;Licensed&lt;/a&gt; in the hopes that it is as helpful to the OSS community as it has been to us.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;disclaimer&amp;gt;
1 of 1 consulted lawyers agree, Licensed is not a replacement for the legal advice of a human.
&amp;lt;/disclaimer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;glossary&quot;&gt;Glossary&lt;/h2&gt;

&lt;p&gt;Before we go any further, let’s review a few terms that will be repeated throughout this article&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Dependency: An external software package used in an application
    &lt;ul&gt;
      &lt;li&gt;i.e. packages that are &lt;code class=&quot;highlighter-rouge&quot;&gt;require&lt;/code&gt;d or &lt;code class=&quot;highlighter-rouge&quot;&gt;import&lt;/code&gt;ed like Octokit, ActiveRecord, React&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Dependency source: A class that can enumerate dependencies for an application
    &lt;ul&gt;
      &lt;li&gt;i.e. by invoking a package management tool such as bundler, npm, bower, or cabal.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;what-is-licensed&quot;&gt;What is Licensed?&lt;/h2&gt;

&lt;p&gt;Licensed helps GitHub engineers make efficient use of OSS by surfacing potential problems with a dependency’s license early in our development cycle, ensuring we maintain dependency license documentation throughout our development cycle.&lt;/p&gt;

&lt;p&gt;In practice, enumerating dependencies can be difficult.  In the easiest scenario a package manager provides a full listing of project dependencies in a parseable file.  More difficult scenarios require detailed knowledge of CLI tools, such as using &lt;code class=&quot;highlighter-rouge&quot;&gt;go list&lt;/code&gt; for a general purpose &lt;code class=&quot;highlighter-rouge&quot;&gt;Golang&lt;/code&gt; solution or &lt;code class=&quot;highlighter-rouge&quot;&gt;ghc-pkg&lt;/code&gt; for &lt;code class=&quot;highlighter-rouge&quot;&gt;Haskell&lt;/code&gt; package managers.&lt;/p&gt;

&lt;h2 id=&quot;how-licensed-works&quot;&gt;How Licensed works&lt;/h2&gt;

&lt;p&gt;Licensed works in any Git repository to find, cache and check license metadata for dependencies.  It can detect dependencies from multiple language types and package managers across multiple projects in a single repository.  This flexibility allows Licensed to work equally well for a monolith repository as it would for a repository containing a single project.&lt;/p&gt;

&lt;p&gt;Licensed uses a configuration file to determine how and where to enumerate dependencies for a repository. Configuration files specify one or more Licensed applications, where an application describes a location to enumerate dependencies and a directory to store metadata. For more information on configuration files and Licensed applications, see the Licensed &lt;a href=&quot;https://github.com/github/licensed/blob/master/docs/configuration.md&quot;&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&quot;finding-license-metadata&quot;&gt;Finding license metadata&lt;/h4&gt;

&lt;p&gt;Licensed enumerates dependencies for each application’s source path found in the configuration.  For each dependency found, Licensed finds the dependency source location in the local environment and extracts their basic metadata (e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;name&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;version&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;homepage&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;summary&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Licensed uses &lt;a href=&quot;https://github.com/benbalter/licensee&quot;&gt;Licensee&lt;/a&gt; to determine each dependency’s license(s) and find it’s license text (e.g. &lt;code class=&quot;highlighter-rouge&quot;&gt;LICENSE&lt;/code&gt;) from the local dependency source location.&lt;/p&gt;

&lt;h4 id=&quot;caching-license-metadata&quot;&gt;Caching license metadata&lt;/h4&gt;

&lt;p&gt;Once Licensed has the dependency’s metadata, it caches the metadata and license information for the project at the cache path(s) specified in the Licensed configuration file.&lt;/p&gt;

&lt;p&gt;Storing the dependency data in a source control repository enables checking dependency data as part of the development workflow.  Requiring updates to license data whenever dependencies change forces the license data to stay up to date and relevant.&lt;/p&gt;

&lt;p&gt;Keeping the cached data in a source control repository also means you automatically get a history of every dependency change in a single location.  Tracking down when a specific dependency changed becomes easier when there is a common location and fewer commits to look through.&lt;/p&gt;

&lt;p&gt;Many dependencies’ licenses require distributing a copy of the licenses when used in downstream projects.  Licensed makes it easy to automate the build and distribution of these licenses, and collectively an open source bill of materials for your project, along with the project source.&lt;/p&gt;

&lt;h4 id=&quot;checking-license-metadata&quot;&gt;Checking license metadata&lt;/h4&gt;

&lt;p&gt;Lastly, Licensed is used to report any dependencies needing review.  When checking dependency licenses, Licensed performs the following verifications:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Verify cached license metadata exists for the dependency&lt;/li&gt;
  &lt;li&gt;Verify the cached metadata is for the correct dependency version&lt;/li&gt;
  &lt;li&gt;Verify the cached metadata has license text&lt;/li&gt;
  &lt;li&gt;Verify the cached metadata has uses an allowed license, or the dependency has been reviewed and accepted&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;licensed-as-part-of-the-developer-workflow-at-github&quot;&gt;Licensed as part of the developer workflow at GitHub&lt;/h2&gt;

&lt;p&gt;GitHub engineers have a shared responsibility to ensure that their projects stay compliant with our OSS license requirements.&lt;/p&gt;

&lt;p&gt;As the first line of defense in ensuring that dependencies meet our OSS license requirements, each repository has a CI job that checks dependency licenses. This process generally has little impact on developers, and only requires additional effort when a change might not meet our requirements.&lt;/p&gt;

&lt;p&gt;When a license needs to be updated, it’s easy to do:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;A developer opens a pull request that includes changes to the project dependencies&lt;/li&gt;
  &lt;li&gt;The repository CI job shows dependency license(s) need review, providing feedback on next steps to resolving the errors&lt;/li&gt;
  &lt;li&gt;The developer caches license data for the updated dependencies, including the metadata files in the pull request&lt;/li&gt;
  &lt;li&gt;The repository &lt;code class=&quot;highlighter-rouge&quot;&gt;CODEOWNERS&lt;/code&gt; file requests a review from subject matter experts&lt;/li&gt;
  &lt;li&gt;The subject matter expert reviews the changes and provides guidance to resolve any remaining questions.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process works very well at GitHub.  Involving subject matter experts early in the process reduces friction on the developer and prevents the developer from adding dependencies into the product under license terms that don’t meet our requirements.&lt;/p&gt;

&lt;h2 id=&quot;extending-licensed-for-new-dependency-sources&quot;&gt;Extending Licensed for new dependency sources&lt;/h2&gt;

&lt;p&gt;Whenever a new project is started, we always try to use the best tool for the job.  In many cases this means a new language or framework that isn’t supported by Licensed.  To handle these cases, we’ve made adding a new dependency source to Licensed as easy as possible.&lt;/p&gt;

&lt;p&gt;Creating new dependency sources in Licensed is easy.  Here is a simple example:&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;MyProject&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MySource&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Required.  I need a configuration for basic functionality&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;vi&quot;&gt;@config&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;config&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Required.  Tell the world the name of the dependency source&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;my source&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# Required.  Give the world the dependencies found for `@config`&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;dependencies&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Will this parse a package manager file?&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Will this use CLI tools to find dependencies?&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Nope!  I'm a hardcoded list!&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;Dependency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@config&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;source_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# location used to find license text (e.g. LICENSE)&lt;/span&gt;
          &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;licensed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;ss&quot;&gt;homepage: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://github.com/github/licensed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;ss&quot;&gt;version: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;0.13.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
          &lt;span class=&quot;ss&quot;&gt;summary: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Extract and validate the licenses of dependencies.&quot;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;Future development for Licensed will focus on&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Reducing friction when using Licensed in developer workflows&lt;/li&gt;
  &lt;li&gt;Reducing friction when adding new dependency sources&lt;/li&gt;
  &lt;li&gt;Adding new dependency sources :smile:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Licensed isn’t just about open source, it is open source itself. Interested in adapting the tool to your team’s workflow or adding support for your favorite package manager? &lt;a href=&quot;https://github.com/github/licensed&quot;&gt;We’d love your help&lt;/a&gt;.&lt;/p&gt;</content><author><name>jonabc</name></author><summary type="html">GitHub recently open sourced Licensed in the hopes that it is as helpful to the OSS community as it has been to us.</summary></entry><entry><title type="html">February 28th DDoS Incident Report</title><link href="https://githubengineering.com/ddos-incident-report/" rel="alternate" type="text/html" title="February 28th DDoS Incident Report" /><published>2018-03-01T00:00:00+00:00</published><updated>2018-03-01T00:00:00+00:00</updated><id>https://githubengineering.com/ddos-incident-report</id><content type="html" xml:base="https://githubengineering.com/ddos-incident-report/">&lt;p&gt;On Wednesday, February 28, 2018 GitHub.com was unavailable from 17:21 to 17:26 UTC and intermittently unavailable from 17:26 to 17:30 UTC due to a distributed denial-of-service (DDoS) attack. We understand how much you rely on GitHub and we know the availability of our service is of critical importance to our users. To note, at no point was the confidentiality or integrity of your data at risk. We are sorry for the impact of this incident and would like to describe the event, the efforts we’ve taken to drive availability, and how we aim to improve response and mitigation moving forward.&lt;/p&gt;

&lt;h3 id=&quot;background&quot;&gt;Background&lt;/h3&gt;

&lt;p&gt;Cloudflare described an amplification vector using memcached over UDP in their blog post this week, &lt;a href=&quot;https://blog.cloudflare.com/memcrashed-major-amplification-attacks-from-port-11211/&quot;&gt;“Memcrashed - Major amplification attacks from UDP port 11211”&lt;/a&gt;. The attack works by abusing memcached instances that are inadvertently accessible on the public internet with UDP support enabled. Spoofing of IP addresses allows memcached’s responses to be targeted against another address, like ones used to serve GitHub.com, and send more data toward the target than needs to be sent by the unspoofed source. The vulnerability via misconfiguration described in the post is somewhat unique amongst that class of attacks because the amplification factor is up to 51,000, meaning that for each byte sent by the attacker, up to 51KB is sent toward the target.&lt;/p&gt;

&lt;p&gt;Over the past year we have deployed additional transit to our facilities. We’ve more than doubled our transit capacity during that time, which has allowed us to withstand certain volumetric attacks without impact to users. We’re continuing to deploy additional transit capacity and &lt;a href=&quot;https://githubengineering.com/transit-and-peering-how-your-requests-reach-github/&quot;&gt;develop robust peering relationships across a diverse set of exchanges&lt;/a&gt;. Even still, attacks like this sometimes require the help of partners with larger transit networks to provide blocking and filtering.&lt;/p&gt;

&lt;h3 id=&quot;the-incident&quot;&gt;The incident&lt;/h3&gt;

&lt;p&gt;Between 17:21 and 17:30 UTC on February 28th we identified and mitigated a significant volumetric DDoS attack. The attack originated from over a thousand different autonomous systems (ASNs) across tens of thousands of unique endpoints. It was an amplification attack using the memcached-based approach described above that peaked at 1.35Tbps via 126.9 million packets per second.&lt;/p&gt;

&lt;p&gt;At 17:21 UTC our network monitoring system detected an anomaly in the ratio of ingress to egress traffic and notified the on-call engineer and others in our chat system. This graph shows inbound versus outbound throughput over transit links:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/579876/36830510-bd9ea02e-1cd8-11e8-96c0-dc199a530164.png&quot; alt=&quot;more inbound than outbound traffic graph&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Given the increase in inbound transit bandwidth to over 100Gbps in one of our facilities, the decision was made to move traffic to Akamai, who could help provide additional edge network capacity. At 17:26 UTC the command was initiated via our ChatOps tooling to withdraw BGP announcements over transit providers and announce &lt;a href=&quot;https://www.peeringdb.com/net/5152&quot;&gt;AS36459&lt;/a&gt; exclusively over our links to Akamai. Routes reconverged in the next few minutes and access control lists mitigated the attack at their border. Monitoring of transit bandwidth levels and load balancer response codes indicated a full recovery at 17:30 UTC. At 17:34 UTC routes to internet exchanges were withdrawn as a follow-up to shift an additional 40Gbps away from our edge.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/579876/36830539-e48f683a-1cd8-11e8-9ef7-ec7e923a0c7f.png&quot; alt=&quot;graph showing traffic movement off exchanges&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The first portion of the attack peaked at 1.35Tbps and there was a second 400Gbps spike a little after 18:00 UTC. This graph provided by Akamai shows inbound traffic in bits per second that reached their edge:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://user-images.githubusercontent.com/579876/36830593-2ae2cf98-1cd9-11e8-944d-dde6248ac0e5.png&quot; alt=&quot;traffic to akamai edge&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;next-steps&quot;&gt;Next steps&lt;/h3&gt;

&lt;p&gt;Making GitHub’s edge infrastructure more resilient to current and future conditions of the internet and less dependent upon human involvement requires better automated intervention. We’re investigating the use of our monitoring infrastructure to automate enabling DDoS mitigation providers and will continue to measure our response times to incidents like this with a goal of reducing mean time to recovery (MTTR).&lt;/p&gt;

&lt;p&gt;We’re going to continue to expand our edge network and strive to identify and mitigate new attack vectors before they affect your workflow on GitHub.com.&lt;/p&gt;

&lt;p&gt;We know how much you rely on GitHub for your projects and businesses to succeed. We will continue to analyze this and other events that impact our availability, build better detection systems, and streamline response.&lt;/p&gt;</content><author><name>{&quot;username&quot;=&gt;&quot;skottler&quot;, &quot;role&quot;=&gt;&quot;Manager, Site Reliability Engineering&quot;, &quot;twitter&quot;=&gt;&quot;samkottler&quot;, &quot;links&quot;=&gt;[{&quot;name&quot;=&gt;&quot;GitHub Profile&quot;, &quot;url&quot;=&gt;&quot;https://github.com/skottler&quot;}, {&quot;name&quot;=&gt;&quot;Twitter Profile&quot;, &quot;url&quot;=&gt;&quot;https://twitter.com/samkottler&quot;}]}</name></author><summary type="html">On Wednesday, February 28, 2018 GitHub.com was unavailable from 17:21 to 17:26 UTC and intermittently unavailable from 17:26 to 17:30 UTC due to a distributed denial-of-service (DDoS) attack. We understand how much you rely on GitHub and we know the availability of our service is of critical importance to our users. To note, at no point was the confidentiality or integrity of your data at risk. We are sorry for the impact of this incident and would like to describe the event, the efforts we’ve taken to drive availability, and how we aim to improve response and mitigation moving forward.</summary></entry><entry><title type="html">Weak cryptographic standards removal notice</title><link href="https://githubengineering.com/crypto-removal-notice/" rel="alternate" type="text/html" title="Weak cryptographic standards removal notice" /><published>2018-02-01T00:00:00+00:00</published><updated>2018-02-01T00:00:00+00:00</updated><id>https://githubengineering.com/crypto-removal-notice</id><content type="html" xml:base="https://githubengineering.com/crypto-removal-notice/">&lt;p&gt;&lt;a href=&quot;/crypto-deprecation-notice&quot;&gt;Last year&lt;/a&gt; we announced the deprecation of several weak cryptographic standards. Then we provided &lt;a href=&quot;/crypto-deprecation-notice-update-1&quot;&gt;a status update&lt;/a&gt; toward the end of last year outlining some changes we’d made to make the transition easier for clients. We quickly approached the February 1, 2018 cutoff date we mentioned in previous posts and, as a result, pushed back our schedule by one week. On &lt;strong&gt;February 8, 2018&lt;/strong&gt; we’ll start disabling the following:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1&lt;/code&gt;/&lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.1&lt;/code&gt;: This applies to all HTTPS connections, including web, API, and git connections to https://github.com and https://api.github.com.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;diffie-hellman-group1-sha1&lt;/code&gt;: This applies to all SSH connections to github.com&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;diffie-hellman-group14-sha1&lt;/code&gt;: This applies to all SSH connections to github.com&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We’ll disable the algorithms in two stages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;February 8, 2018 19:00 UTC (11:00 am PST)&lt;/strong&gt;: Disable deprecated algorithms for &lt;em&gt;one hour&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;February 22, 2018 19:00 UTC (11:00 am PST)&lt;/strong&gt;: Permanently disable deprecated algorithms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While only a small fraction of traffic currently makes use of the deprecated algorithms, and many clients will automatically transition and start using the new algorithms, there is invariably going to be a small fraction of clients that will be impacted. We expect most of these are older systems that are no longer maintained, but continue to access Git/the GitHub API using the deprecated algorithms. To help mitigate this, we will temporarily disable support for the deprecated algorithms for one hour on &lt;strong&gt;February 8, 2018 19::00 UTC&lt;/strong&gt;. By disabling support for the deprecated algorithms for a small window, these systems will temporarily fail to connect to GitHub. We will then restore support for the deprecated algorithms and provide a two week grace period for these systems to upgrade their libraries before we disable support for the deprecated algorithms &lt;strong&gt;permanently on February 22, 2018&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&quot;known-incompatible-clients&quot;&gt;Known incompatible clients&lt;/h2&gt;

&lt;p&gt;As noted above, the vast majority of traffic should be unaffected by this change. However, there are a few remaining clients that we anticipate will be affected. Fortunately, the majority of clients can be updated to work with &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;git-credential-manager-for-windows--v1140&quot;&gt;Git-Credential-Manager-for-Windows &amp;lt; v1.14.0&lt;/h3&gt;

&lt;p&gt;Git-Credential-Manager-for-Windows &amp;lt; v1.14.0 does not support &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt;. This can be addressed by &lt;a href=&quot;https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases/tag/v1.14.0&quot;&gt;updating to v1.14.0&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;git-on-red-hat-5--68-and--72&quot;&gt;Git on Red Hat 5, &amp;lt; 6.8, and &amp;lt; 7.2&lt;/h3&gt;

&lt;p&gt;Red Hat 5, &lt;a href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=1272504&quot;&gt;6&lt;/a&gt;, and &lt;a href=&quot;https://bugzilla.redhat.com/show_bug.cgi?id=1217477&quot;&gt;7&lt;/a&gt; shipped with Git clients that did not support &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt;. This can be addressed by updating to versions 6.8 and 7.2 (or greater) respectively. Unfortunately, Red Hat 5 does not have a point release that supports &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt;. We advise that users of Red Hat 5 upgrade to a newer version of the operating system.&lt;/p&gt;

&lt;h3 id=&quot;java-releases--jdk-8&quot;&gt;Java releases &amp;lt; JDK 8&lt;/h3&gt;

&lt;p&gt;As noted in &lt;a href=&quot;https://blogs.oracle.com/java-platform-group/diagnosing-tls,-ssl,-and-https&quot;&gt;this blog post by Oracle&lt;/a&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1&lt;/code&gt; was used by default for JDK releases prior to JDK 8. JDK 8 changed this behavior and defaults to &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt;. Any client (ex. JGit is one such popular client) that runs on older versions of the JDK is affected. This can be addressed by updating to JDK &amp;gt;= 8 or explicitly opting in to &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt; in JDK 7 (look at the &lt;code class=&quot;highlighter-rouge&quot;&gt;https.protocols&lt;/code&gt; JSSE tuning parameter). Unfortunately, versions of the JDK &amp;lt;= 6 do not support &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt;. We advise users of JDK &amp;lt;= 6 to upgrade to a newer version of the JDK.&lt;/p&gt;

&lt;h3 id=&quot;visual-studio&quot;&gt;Visual Studio&lt;/h3&gt;

&lt;p&gt;Visual Studio ships with specific versions of Git for Windows and the Git Credential Manager for Windows (GCM). Microsoft has updated the latest versions of Visual Studio 2017 to work with &lt;code class=&quot;highlighter-rouge&quot;&gt;TLSv1.2&lt;/code&gt; Git servers. We advise users of Visual Studio to upgrade to the latest release by clicking on the in-product notification flag or by checking for an update directly from the IDE. Microsoft has provided additional guidance on the &lt;a href=&quot;https://developercommunity.visualstudio.com/content/problem/201457/unable-to-connect-to-github-due-to-tls-12-only-cha.html&quot;&gt;Visual Studio developer community support forum&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;As always, if you have any questions or concerns related to this announcement, please don’t hesitate to &lt;a href=&quot;https://github.com/contact?form[subject]=Crypto+removal+notice&quot;&gt;contact us&lt;/a&gt;.&lt;/p&gt;</content><author><name>Patrick Toomey</name></author><summary type="html">Last year we announced the deprecation of several weak cryptographic standards. Then we provided a status update toward the end of last year outlining some changes we’d made to make the transition easier for clients. We quickly approached the February 1, 2018 cutoff date we mentioned in previous posts and, as a result, pushed back our schedule by one week. On February 8, 2018 we’ll start disabling the following:</summary></entry></feed>