<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
  <id>tag:github.com,2008:/blog</id>
  <link type="text/html" rel="alternate" href="http://github.com/blog" />
  
  <title>The GitHub Blog</title>
  <updated>2009-11-07T09:06:27-08:00</updated>
  <link rel="self" href="http://feeds.feedburner.com/github" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry>
    <id>tag:github.com,2008:Post/544</id>
    <published>2009-11-07T09:06:04-08:00</published>
    <updated>2009-11-07T09:06:27-08:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/544-github-meetup-pozna%C5%84-poland" />
    <title>GitHub Meetup Poznań, Poland</title>
    <content type="html">&lt;p&gt;Tom, PJ, and Scott will be hanging out at &lt;a href="http://moodclub.pl"&gt;&lt;span class="caps"&gt;MOOD&lt;/span&gt; Club&lt;/a&gt; at 21:30 tonight (Saturday) in Poznań, Poland following the first day of the RuPy Conference. If you&amp;#8217;re local or in town for the conference, come by and say hi!&lt;/p&gt;
&lt;div align="center"&gt;&lt;img src="http://moodclub.pl/UserFiles//File/OpenCzerwiec2008/080627_Poznan_Mood_004.JPG"/&gt;&lt;/div&gt;</content>
    <author>
      <name>mojombo</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/543</id>
    <published>2009-11-04T10:35:55-08:00</published>
    <updated>2009-11-04T10:40:19-08:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/543-new-resque-web-ui" />
    <title>New Resque Web UI</title>
    <content type="html">&lt;p&gt;Behold the power of open source! &lt;a href="http://github.com/adamcooke"&gt;adamcooke&lt;/a&gt; has reskinned &lt;a href="http://github.com/defunkt/resque"&gt;Resque&amp;#8217;s&lt;/a&gt; web UI.&lt;/p&gt;
&lt;div align="center"&gt;&lt;a href="http://img.skitch.com/20091104-jsqydh9jgg9ju4tkt66jqm2399.png"&gt;&lt;img src="http://img.skitch.com/20091104-8c41b9jmdtyc79jc76yap53igc.png"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div align="center"&gt;&lt;a href="http://img.skitch.com/20091104-k3iuxw8hqsce86b5pdphsctsg4.png"&gt;&lt;img src="http://img.skitch.com/20091104-cs222tun9yna4s46ywt7jqdjqk.png"/&gt;&lt;/a&gt;&lt;/div&gt; 
&lt;p&gt;Also now includes live updating:&lt;/p&gt;
&lt;div align="center"&gt;&lt;a href="http://img.skitch.com/20091104-88wn3wtc9jnacas3mytxxwn6c9.png"&gt;&lt;img src="http://img.skitch.com/20091104-1nqebsad9kuac6ixaqgykqmste.png"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Thanks Adam!&lt;/p&gt;</content>
    <author>
      <name>defunkt</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/542</id>
    <published>2009-11-03T09:36:46-08:00</published>
    <updated>2009-11-03T10:02:46-08:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/542-introducing-resque" />
    <title>Introducing Resque</title>
    <content type="html">&lt;!-- -*-Markdown-*- --&gt;


&lt;p&gt;&lt;a href="http://github.com/defunkt/resque"&gt;Resque&lt;/a&gt; is our Redis-backed library for creating background jobs, placing
those jobs on multiple queues, and processing them later.&lt;/p&gt;

&lt;p&gt;Background jobs can be any Ruby class or module that responds to
&lt;code&gt;perform&lt;/code&gt;. Your existing classes can easily be converted to background
jobs or you can create new classes specifically to do work. Or, you
can do both.&lt;/p&gt;

&lt;p&gt;All the details are in the &lt;a href="http://github.com/defunkt/resque#readme"&gt;README&lt;/a&gt;. We've used it to process
over 10m jobs since our move to Rackspace and are extremely happy with it.&lt;/p&gt;

&lt;p&gt;But why another background library?&lt;/p&gt;

&lt;h3&gt;A Brief History of Background Jobs&lt;/h3&gt;

&lt;p&gt;We've used many different background job systems at GitHub. SQS,
Starling, ActiveMessaging, BackgroundJob, DelayedJob, and beanstalkd.
Each change was out of necessity: we were running into a
limitation of the current system and needed to either fix it or move
to something designed with that limitation in mind.&lt;/p&gt;

&lt;p&gt;With SQS, the limitation was latency. We were a young site and heard
stories on Amazon forums of multiple minute lag times between push and
pop. That is, once you put something on a queue you wouldn't be able
to get it back for what could be a while. That scared us so we moved.&lt;/p&gt;

&lt;p&gt;ActiveMessaging was next, but only briefly. We wanted something
focused more on Ruby itself and less on libraries. That is, our jobs
should be Ruby classes or objects, whatever makes sense for our app,
and not subclasses of some framework's design.&lt;/p&gt;

&lt;p&gt;BackgroundJob (bj) was a perfect compromise: you could process Ruby
jobs or Rails jobs in the background. How you structured the jobs was
largely up to you. It even included priority levels, which would let
us make "repo create" and "fork" jobs run faster than the "warm some
caches" jobs.&lt;/p&gt;

&lt;p&gt;However, bj loaded the entire Rails environment for each job. Loading
Rails is no small feat: it is CPU-expensive and takes a few
seconds. So for a job that may take less than a second, you could have
8 - 20s of added overhead depending on how big your app is, how many
dependencies it requires, and how bogged down your CPU is at that time.&lt;/p&gt;

&lt;p&gt;DelayedJob (dj) fixed this problem: it is similar to bj, with a
database-backed queue and priorities, but its workers are
persistent. They only load Rails when started, then process jobs in a
loop.&lt;/p&gt;

&lt;p&gt;Jobs are just YAML-marshalled Ruby objects. With some magic you can
turn any method call into a job to be processed later.&lt;/p&gt;

&lt;p&gt;Perfect. DJ lacked a few features we needed but we added them and
contributed the changes back.&lt;/p&gt;

&lt;p&gt;We used DJ very successfully for a few months before running into some
issues. First: backed up queues. DJ works great with small datasets,
but once your site starts overloading and the queue backs up (to, say,
30,000 pending jobs) its queries become expensive. Creating jobs can
take 2s+ and acquiring locks on jobs can take 2s+, as well. This means
an added 2s per job created for each page load. On a page that fires
off two jobs, you're at a baseline of 4s before doing anything else.&lt;/p&gt;

&lt;p&gt;If your queue is backed up because your site is overloaded, this added
overhead just makes the problem worse.&lt;/p&gt;

&lt;p&gt;Solution: move to beanstalkd. beanstalkd is great because it's fast,
supports multiple queues, supports priorities, and speaks YAML
natively. A huge queue has constant time push and pop operations,
unlike a database-backed queue.&lt;/p&gt;

&lt;p&gt;beanstalkd also has experimental persistence - we need persistence.&lt;/p&gt;

&lt;p&gt;However, we quickly missed DJ features: seeing failed jobs, seeing
pending jobs (beanstalkd only allows you to 'peek' ahead at the next
pending job), manipulating the queue (e.g. running through and
removing all jobs that were created by a bug or with a bad job name),
etc. A database-queue gives you a lot of cool features. So we moved
back to DJ - the tradeoff was worth it.&lt;/p&gt;

&lt;p&gt;Second: if a worker gets stuck, or is processing a job that will take
hours, DJ has facilities to release a lock and retry that job when
another worker is looking for work. But that stuck worker, even
though his work has been released, is still processing a job that you
most likely want to abort or fail.&lt;/p&gt;

&lt;p&gt;You want that worker to fail or restart. We added code so that,
instead of simply retrying a job that failed due to timeout, other
workers will a) fail that job permanently then b) restart the locked
worker.&lt;/p&gt;

&lt;p&gt;In a sense, all the workers were babysitting each other.&lt;/p&gt;

&lt;p&gt;But what happens when all the workers are processing stuck or long
jobs? Your queue quickly backs up.&lt;/p&gt;

&lt;p&gt;What you really need is a manager: someone like monit or god who can
watch workers and kill stale ones.&lt;/p&gt;

&lt;p&gt;Also, your workers will probably grow in memory a lot during the
course of their life. So you need to either make sure you never create
too many objects or "leak" memory, or you need to kill them when they
get too large (just like you do with your frontend web instances).&lt;/p&gt;

&lt;p&gt;At this point we have workers processing jobs with god watching them
and killing any that are a) bloated or b) stale.&lt;/p&gt;

&lt;p&gt;But how do we know all this is going on? How do we know what's sitting
on the queue? As I mentioned earlier, we had a web interface which
would show us pending items and try to infer how many workers are
working. But that's not easy - how do you have a worker you just
&lt;code&gt;kill -9&lt;/code&gt;'d gracefully manage its own state? We added a process to
inspect workers and add their info to memcached, which our web
frontend would then read from.&lt;/p&gt;

&lt;p&gt;But who monitors that process. And do we have one running on each
server? This is quickly becoming very complicated.&lt;/p&gt;

&lt;p&gt;Also we have another problem: startup time. There's a multi-second
startup cost when loading a Rails environment, not to mention the
added CPU time. With lots of workers doing lots of jobs being
restarted on a non-trival basis, that adds up.&lt;/p&gt;

&lt;p&gt;It boils down to this: GitHub is a warzone. We are constantly
overloaded and rely very, very heavily on our queue. If it's backed
up, we need to know why. We need to know if we can fix it. We need
workers to not get stuck and we need to know when they are stuck.&lt;/p&gt;

&lt;p&gt;We need to see what the queue is doing. We need to see what jobs have
failed. We need stats: how long are workers living, how many jobs are
they processing, how many jobs have been processed total, how many
errors have there been, are errors being repeated, did a deploy
introduce a new one?&lt;/p&gt;

&lt;p&gt;We need a background job system as serious as our web framework.
I highly recommend DelayedJob to anyone whose site is not 50%
background work.&lt;/p&gt;

&lt;p&gt;But GitHub is 50% background work.&lt;/p&gt;

&lt;h3&gt;In Search of a Solution&lt;/h3&gt;

&lt;p&gt;In the Old Architecture, GitHub had one slice dedicated to processing
background jobs. We ran 25 DJ workers on it and all they did was run
jobs. It was known as our "utility" slice.&lt;/p&gt;

&lt;p&gt;In the New Architecture, certain jobs needed to be run on certain
machines. With our emphasis on sharding data and high availability, a
single utility slice no longer fit the bill.&lt;/p&gt;

&lt;p&gt;Both beanstalkd and bj supported named queues or "tags," but DelayedJob
did not. Basically we needed a way to say "this job has a tag of X"
and then, when starting workers, tell them to only be interested in
jobs with a tag of X.&lt;/p&gt;

&lt;p&gt;For example, our "archive" background job creates tarballs and zip
files for download. It needs to be run on the machine which serves
tarballs and zip files. We'd tag the archive job with "file-serve" and
only run it on the file serving slice. We could then re-use this tag
with other jobs that needed to only be run on the file serving slice.&lt;/p&gt;

&lt;p&gt;We added this feature to DelayedJob but then realized it was an
opportunity to re-evaluate our background job situation. Did someone
else support this already? Was there a system which met our upcoming
needs (distributed worker management - god/monit for workers on
multiple machines along with visibility into the state)? Should we
continue adding features to DelayedJob? Our fork had deviated from
master and the merge (plus subsequent testing) was not going to be fun.&lt;/p&gt;

&lt;p&gt;We made a list of all the things we needed on paper and started
re-evaluating a lot of the existing solutions. Kestrel, AMQP,
beanstalkd (persistence still hadn't been rolled into an official
release a year after being pushed to master).&lt;/p&gt;

&lt;p&gt;Here's that list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Persistence&lt;/li&gt;
&lt;li&gt;See what's pending&lt;/li&gt;
&lt;li&gt;Modify pending jobs in-place&lt;/li&gt;
&lt;li&gt;Tags&lt;/li&gt;
&lt;li&gt;Priorities&lt;/li&gt;
&lt;li&gt;Fast pushing and popping&lt;/li&gt;
&lt;li&gt;See what workers are doing&lt;/li&gt;
&lt;li&gt;See what workers have done&lt;/li&gt;
&lt;li&gt;See failed jobs&lt;/li&gt;
&lt;li&gt;Kill fat workers&lt;/li&gt;
&lt;li&gt;Kill stale workers&lt;/li&gt;
&lt;li&gt;Kill workers that are running too long&lt;/li&gt;
&lt;li&gt;Keep Rails loaded / persistent workers&lt;/li&gt;
&lt;li&gt;Distributed workers (run them on multiple machines)&lt;/li&gt;
&lt;li&gt;Workers can watch multiple (or all) tags&lt;/li&gt;
&lt;li&gt;Don't retry failed jobs&lt;/li&gt;
&lt;li&gt;Don't "release" failed jobs&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Redis to the Rescue&lt;/h3&gt;

&lt;p&gt;Can you name a system with all of these features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Atomic, O(1) list push and pop&lt;/li&gt;
&lt;li&gt;Ability to paginate over lists without mutating them&lt;/li&gt;
&lt;li&gt;Queryable keyspace, high visibility&lt;/li&gt;
&lt;li&gt;Fast&lt;/li&gt;
&lt;li&gt;Easy to install - no dependencies&lt;/li&gt;
&lt;li&gt;Reliable Ruby client library&lt;/li&gt;
&lt;li&gt;Store arbitrary strings&lt;/li&gt;
&lt;li&gt;Support for integer counters&lt;/li&gt;
&lt;li&gt;Persistent&lt;/li&gt;
&lt;li&gt;Master-slave replication&lt;/li&gt;
&lt;li&gt;Network aware&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I can. Redis.&lt;/p&gt;

&lt;p&gt;If we let Redis handle the hard queue problems, we can focus on the
hard worker problems: visibility, reliability, and stats.&lt;/p&gt;

&lt;p&gt;And that's &lt;a href="http://github.com/defunkt/resque#readme"&gt;Resque&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With a web interface for monitoring workers, a parent / child forking
model for responsiveness, swappable failure backends (so we can send
exceptions to, say, Hoptoad), and the power of Redis, we've found
Resque to be a perfect fit for our architecture and needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://github.com/defunkt/resque"&gt;&lt;img src="http://img.skitch.com/20091102-rpekt191w28xfhwyussru44nsw.png" alt="web ui" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We hope you enjoy it. We certainly do!&lt;/p&gt;
</content>
    <author>
      <name>defunkt</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/541</id>
    <published>2009-11-02T20:21:47-08:00</published>
    <updated>2009-11-02T20:21:57-08:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/541-commons-based-peer-production" />
    <title>Commons Based Peer Production</title>
    <content type="html">&lt;p&gt;&lt;a href="http://github.com/ab5tract"&gt;ab5tract&lt;/a&gt; has a &lt;a href="http://mastersofmedia.hum.uva.nl/2009/11/01/git-virtue-github-and-commons-based-peer-production/"&gt;great post&lt;/a&gt; looking at GitHub &amp;#8220;through the lens of the ethics of commons-based peer production.&amp;#8221;&lt;/p&gt;
&lt;p&gt;A key quote which puts it in perspective for me is this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The software further induces virtue in its participants through the `git blame` function, which immediately calls up the person responsible for a commit. In practice it used as much to know who to praise as it is to know who to berate, but it fulfills one of the the paper’s common criteria for extant commons-based peer production: that of a mechanism to mitigate the potential impacts of malicious users. Slashdot has its moderation system, Wikipedia its editors, and git has `blame`. In fact this functionality is a crucial part of what enables the ‘virtue spreading virtue’ element of such peer production.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;div align="center"&gt;&lt;a href="http://mastersofmedia.hum.uva.nl/2009/11/01/git-virtue-github-and-commons-based-peer-production"&gt;&lt;img src="http://img.skitch.com/20091103-wtqrk9ppq3si3sxh2uf3kuwhj.png"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;Read &lt;a href="http://mastersofmedia.hum.uva.nl/2009/11/01/git-virtue-github-and-commons-based-peer-production/"&gt;the blog post&lt;/a&gt; for the whole scope. Thanks &lt;a href="http://github.com/ab5tract"&gt;ab5tract&lt;/a&gt;!&lt;/p&gt;</content>
    <author>
      <name>defunkt</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/540</id>
    <published>2009-11-02T14:22:57-08:00</published>
    <updated>2009-11-02T16:17:57-08:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/540-github-meetup-sf-9" />
    <title>GitHub Meetup SF #9</title>
    <content type="html">&lt;center&gt;
&lt;p&gt;&lt;img src="http://img.skitch.com/20091102-nefu38n6pc6crqr5e9ump6tge6.jpg"/&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Its time for a meetup!  This week we&amp;#8217;ll be going to a faraway place, a place once thought to only exist in legend, a land they call the &amp;#8216;Richmond&amp;#8217;.  According to local lore there&amp;#8217;s a bar called &lt;a href="http://maps.google.com/maps?hl=en&amp;ie=UTF8&amp;q=buckshot&amp;fb=1&amp;gl=us&amp;hq=buckshot&amp;hnear=San+Francisco,+CA&amp;cid=0,0,1774702738057692503&amp;ei=9DzvSprjE42cswPYuNj1Aw&amp;ved=0CCsQnwIwAw&amp;ll=37.782299,-122.460887&amp;spn=0.00987,0.017316&amp;t=h&amp;z=16&amp;iwloc=A"&gt;Buckshot&lt;/a&gt; where you can play skee ball and shuffleboard while you shoot the breeze.  And even if you dont actually spot any mythical beasts, you might get a chance to talk to Chris about &lt;a href="http://github.com/blog/517-unicorn"&gt;unicorns&lt;/a&gt;. 8pm Thursday November 5th.&lt;/p&gt;</content>
    <author>
      <name>luckiestmonkey</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/538</id>
    <published>2009-11-02T11:59:36-08:00</published>
    <updated>2009-11-02T12:03:59-08:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/538-load-balancing-at-github" />
    <title>Load Balancing at GitHub</title>
    <content type="html">&lt;p&gt;We&amp;#8217;ve had a number of inquiries into why we chose &lt;a href="http://www.vergenet.net/linux/ldirectord/"&gt;ldirectord&lt;/a&gt; as our primary load balancer for the new GitHub architecture. As I&amp;#8217;ve mentioned before (and more on this later), we&amp;#8217;ve hired the excellent team at &lt;a href="http://anchor.com.au"&gt;Anchor&lt;/a&gt; as our server specialists. Our team lead over there is Matt Palmer, and we left the choice of load balancer up to him and his expertise. He&amp;#8217;s taken it upon himself to explain the driving factors behind his choice, and it makes for an enlightening read if you&amp;#8217;re interested in such things. Just head on over to the Anchor blog to check it out:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.anchor.com.au/blog/2009/10/load-balancing-at-github-why-ldirectord/"&gt;http://www.anchor.com.au/blog/2009/10/load-balancing-at-github-why-ldirectord/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Be sure to read the comments where the author of &lt;a href="http://haproxy.1wt.eu/"&gt;haproxy&lt;/a&gt; weighs in on the post and adds some additional perspective. Like most technology decisions, there is no single correct answer. Only tradeoffs and preferences.&lt;/p&gt;</content>
    <author>
      <name>mojombo</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/537</id>
    <published>2009-10-30T12:00:13-07:00</published>
    <updated>2009-10-30T12:04:08-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/537-post-mortem-of-this-morning-s-outage" />
    <title>Post-Mortem of This Morning's Outage</title>
    <content type="html">&lt;p&gt;At 07:53 &lt;span class="caps"&gt;PDT&lt;/span&gt; this morning the site was hit with an abnormal number of &lt;span class="caps"&gt;SSH&lt;/span&gt; connections. The script that runs after an &lt;span class="caps"&gt;SSH&lt;/span&gt; connection is accepted makes an &lt;span class="caps"&gt;RPC&lt;/span&gt; call to the backend to check for the existence of the repository so that we can display a nice error message if it is not present. The vast number of these calls that came in simultaneously caused some delays in the backend that cascaded to the frontends and resulted in a piling up of the scripts waiting for their &lt;span class="caps"&gt;RPC&lt;/span&gt; results. This, in turn, caused load to spike on the frontends further exacerbating the problem. I removed the &lt;span class="caps"&gt;RPC&lt;/span&gt; call from the &lt;span class="caps"&gt;SSH&lt;/span&gt; script to prevent this bottlenecking and soon after the barrage of &lt;span class="caps"&gt;SSH&lt;/span&gt; connections ceased.&lt;/p&gt;
&lt;p&gt;Another unrelated problem caused the outage to continue even after the &lt;span class="caps"&gt;SSH&lt;/span&gt; connection load became nominal. Last night I deployed some package upgrades to our &lt;span class="caps"&gt;RPC&lt;/span&gt; stack that had tested out fine in staging for two days. While debugging the &lt;span class="caps"&gt;SSH&lt;/span&gt; problem, I restarted the backend &lt;span class="caps"&gt;RPC&lt;/span&gt; servers to rule them out as the problem source. This was the first time these processes had been restarted since the package upgrades, as they were deemed to be backward compatible with the changes and staging had shown no problems in this regard. However, it appears that these restarts put the &lt;span class="caps"&gt;RPC&lt;/span&gt; servers into an unworking state, and they began serving requests very sporadically. After failing to identify the problem within a short period, we decided to roll back to the previous known working state. After the packages were rolled back and the daemons restarted, the site picked up and began operating normally.&lt;/p&gt;
&lt;p&gt;Full site operation returned at 09:34 &lt;span class="caps"&gt;PDT&lt;/span&gt; (some sporadic uptime was seen during the outage).&lt;/p&gt;
&lt;p&gt;Over the next week we will be doing several things:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Further testing on staging to attempt to reproduce the behavior seen on production and resolve the underlying issue.&lt;/li&gt;
	&lt;li&gt;Better &lt;span class="caps"&gt;SSH&lt;/span&gt; script logging to more quickly identify abnormal behavior.&lt;/li&gt;
	&lt;li&gt;Working towards a more fine-grained rolling deploy of infrastructure packages to limit the impact of unforeseen problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On a positive note, the outage led me to identify the source of several subtle bugs that have been eluding our detection for a few weeks. We are all rapidly learning the quirks of our new architecture in a production environment, and every problem leads to a more robust system in the future. Thanks for your patience over the last month and during the coming months as we work to improve the GitHub experience on every level.&lt;/p&gt;</content>
    <author>
      <name>mojombo</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/536</id>
    <published>2009-10-29T09:40:49-07:00</published>
    <updated>2009-10-29T09:40:56-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/536-jquery" />
    <title>jQuery!</title>
    <content type="html">&lt;p&gt;&lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt;, which we use for GitHub itself, is now hosted right here: &lt;a href="http://github.com/jquery/jquery"&gt;http://github.com/jquery/jquery&lt;/a&gt;&lt;/p&gt;
&lt;div align="center"&gt;&lt;a href="http://github.com/jquery/jquery"&gt;&lt;img src="http://img.skitch.com/20091029-dbpp26n16mqwhxgrbscsgabf89.png"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;If you&amp;#8217;ve never contributed to the project, now&amp;#8217;s a great time. Welcome, team!&lt;/p&gt;</content>
    <author>
      <name>defunkt</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/535</id>
    <published>2009-10-26T14:06:06-07:00</published>
    <updated>2009-10-26T14:07:06-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/535-setting-up-a-mac-to-work-with-git-and-github" />
    <title>Setting up a Mac to Work with Git and GitHub</title>
    <content type="html">&lt;p&gt;Bob Silverberg just posted a nice guide to &lt;a href="http://www.silverwareconsulting.com/index.cfm/2009/10/26/Setting-up-a-Mac-to-Work-with-Git-and-GitHub"&gt;Setting up a Mac to Work with Git and GitHub&lt;/a&gt;.  Thanks Bob!&lt;/p&gt;</content>
    <author>
      <name>tekkub</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/534</id>
    <published>2009-10-25T20:40:53-07:00</published>
    <updated>2009-10-25T20:42:55-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/534-github-rebase-29" />
    <title>GitHub Rebase #29</title>
    <content type="html">&lt;p&gt;Time to get your Rebase on! Send me a message about your project if you want to see it featured here, and please check out the Rebase &lt;a href="http://rebase.github.com/howto.html"&gt;howto&lt;/a&gt; as well. I&amp;#8217;d love to see more than just web development stuff too. (but don&amp;#8217;t stop that either!) Perhaps a collection of computer graphics related projects? AI? Music? You name it, just &lt;a href="http://github.com/qrush"&gt;send me a message!&lt;/a&gt;&lt;/p&gt;
&lt;p style="text-align:center;"&gt;&lt;img src="http://cloud.github.com/downloads/rebase/rebase.github.com/GottaGitItOnLP.jpg" alt="" /&gt;&lt;/p&gt;
&lt;h3&gt;Featured Project&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://github.com/subsonic/SubSonic-3.0"&gt;SubSonic&lt;/a&gt;&lt;/strong&gt; is not your average &lt;span class="caps"&gt;ORM&lt;/span&gt; for .&lt;span class="caps"&gt;NET&lt;/span&gt;. This C# library is a veritable workhorse that follows &lt;a href="http://en.wikipedia.org/wiki/Convention_over_configuration"&gt;convention over configuration&lt;/a&gt; and even allows developers to choose different data mapping paradigms, one such being &lt;a href="http://martinfowler.com/eaaCatalog/activeRecord.html"&gt;Active Record&lt;/a&gt;. I wasn&amp;#8217;t kidding about the workhorse bit: out of the box, it&amp;#8217;s got support for &lt;span class="caps"&gt;LINQ&lt;/span&gt;, connecting to multiple DBs, and even a &lt;a href="http://subsonicproject.com/docs/MVC_Starter_Template"&gt;starter app&lt;/a&gt; to get you going. There&amp;#8217;s an unbelievable amount of information on how to use it with your flavor of .&lt;span class="caps"&gt;NET&lt;/span&gt; on &lt;a href="http://subsonicproject.com/docs/"&gt;their wiki&lt;/a&gt;, and definitely check out &lt;a href="http://subsonicproject.com/docs/Comparisons"&gt;how this shapes up&lt;/a&gt; compared to the other available ORMs. Besides, who else can beat screencasts set to &lt;a href="http://subsonicproject.com/docs/The_5_Minute_Demo"&gt;Led Zeppelin&lt;/a&gt; and &lt;a href="http://subsonicproject.com/docs/T4_Templates"&gt;Rush&lt;/a&gt;?&lt;/p&gt;
&lt;h3&gt;Notably New Projects&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://github.com/evanmiller/ChicagoBoss"&gt;ChicagoBoss&lt;/a&gt;&lt;/strong&gt; claims to bring together the best of Rails and Django into the world of Erlang. Sounds neat, but how exactly does that work? Check out the &lt;a href="http://www.chicagoboss.org/example.html"&gt;&lt;span class="caps"&gt;MVC&lt;/span&gt; examples here&lt;/a&gt; and even some fledgling &lt;a href="http://www.chicagoboss.org/api-view.html"&gt;&lt;span class="caps"&gt;API&lt;/span&gt; docs&lt;/a&gt; for how this framework is shaping up. Another neat thing: &lt;a href="http://1978th.net/tokyocabinet/"&gt;Tokyo Tyrant/Cabinet&lt;/a&gt; support is built in, so you can key/value store to the list of buzzwords that Boss already has. Get forking!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://github.com/thedarkone/firepicker"&gt;Firepicker&lt;/a&gt;&lt;/strong&gt; is a Firefox extension that adds a color picker into &lt;a href="http://getfirebug.com/"&gt;Firebug&lt;/a&gt;. Now, you won&amp;#8217;t have to fumble around trying to find a specific application on your OS to do this when you&amp;#8217;re playing with &lt;span class="caps"&gt;CSS&lt;/span&gt; in Firebug. Secondly, if you&amp;#8217;re new to &lt;span class="caps"&gt;XUL&lt;/span&gt; and Firefox development in the first place, this is a great project to look at to get started. Check out some screenshots and how to install it &lt;a href="http://thedarkone.github.com/firepicker/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="http://github.com/Papervision3D/Papervision3D"&gt;Papervision3D&lt;/a&gt;&lt;/strong&gt;&amp;#8216;s readme may be short, but don&amp;#8217;t let that deter you. It&amp;#8217;s better if you just &lt;a href="http://www.papervision3d.org/"&gt;go look for yourself.&lt;/a&gt; Ok, so it&amp;#8217;s a fully immersable 3D world written in ActionScript that&amp;#8217;s open source. Whoever the first person to write a game for this environment is, please invite me to your private beach and/or yacht. There could be a ton of neat ways to implement this: perhaps a more 3D StreetView, planetarium, panoramas, the list goes on and on. Papervision&amp;#8217;s &lt;a href="http://dev.papervision3d.org/"&gt;dev blog&lt;/a&gt; has a lot of neat related links too.&lt;/p&gt;</content>
    <author>
      <name>qrush</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/532</id>
    <published>2009-10-21T11:16:35-07:00</published>
    <updated>2009-10-21T11:27:15-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/532-github-meetup-sf-8" />
    <title>GitHub Meetup SF #8</title>
    <content type="html">&lt;center&gt;
&lt;p&gt;&lt;img src="http://images-0.redbubble.net/img/art/size:large/view:main/2712622-2-blackbird-fly-away.jpg" /&gt;&lt;/p&gt;
&lt;/center&gt;
&lt;p&gt;Come get your drink on with the people of the Hub at &lt;a href="http://maps.google.com/maps?hl=en&amp;ie=UTF8&amp;q=blackbird+san+francisco&amp;fb=1&amp;gl=us&amp;hq=blackbird&amp;hnear=san+francisco&amp;cid=0,0,6763374940088794175&amp;ei=_E3fSvCtA4S0swO3ntzdDw&amp;ved=0CAsQnwIwAA&amp;ll=37.768086,-122.429688&amp;spn=0.009736,0.017316&amp;t=h&amp;z=16&amp;iwloc=A"&gt;Blackbird&lt;/a&gt; this Thursday October 22nd at 8pm. Also, be sure to look out for a possible Drinkup:Shanghai, China edition in the next few days- PJ and Scott are headed out for &lt;a href="http://kungfurails.com/"&gt;KungFuRails&lt;/a&gt; right now!&lt;/p&gt;</content>
    <author>
      <name>luckiestmonkey</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/531</id>
    <published>2009-10-20T13:43:17-07:00</published>
    <updated>2009-10-21T12:21:41-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/531-introducing-bert-and-bert-rpc" />
    <title>Introducing BERT and BERT-RPC</title>
    <content type="html">&lt;p&gt;As I detailed in &lt;a href="http://github.com/blog/530-how-we-made-github-fast"&gt;How We Made GitHub Fast&lt;/a&gt;, we have created a new data serialization and &lt;span class="caps"&gt;RPC&lt;/span&gt; protocol to power the GitHub backend. We have big plans for these technologies and I&amp;#8217;d like to take a moment to explain what makes them special and the philosophy behind their creation.&lt;/p&gt;
&lt;p&gt;The serialization format is called &lt;span class="caps"&gt;BERT&lt;/span&gt; (Binary ERlang Term) and is based on&lt;br /&gt;
the existing &lt;a href="http://www.erlang.org/doc/apps/erts/erl_ext_dist.html"&gt;external term format&lt;/a&gt; already implemented by Erlang. The &lt;span class="caps"&gt;RPC&lt;/span&gt; protocol is called &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; and is a simple protocol built on top of &lt;span class="caps"&gt;BERT&lt;/span&gt; packets.&lt;/p&gt;
&lt;p&gt;You can view the current specifications at &lt;a href="http://bert-rpc.org"&gt;http://bert-rpc.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is a long article; if you want to see some example code of how easy it is to setup an Erlang/Ruby &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; server and call it from a Ruby &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; client, skip to the end.&lt;/p&gt;
&lt;h3&gt;How &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; Came to Be&lt;/h3&gt;
&lt;p&gt;For the new GitHub architecture, we decided to use a simple &lt;span class="caps"&gt;RPC&lt;/span&gt; mechanism to expose the Git repositories as a service. This allows us to federate users across disparate file servers and eliminates the need for a shared file system.&lt;/p&gt;
&lt;p&gt;Choosing a data serialization and &lt;span class="caps"&gt;RPC&lt;/span&gt; protocol was a difficult task. My first thought was to look at &lt;a href="http://incubator.apache.org/thrift/"&gt;Thrift&lt;/a&gt; and &lt;a href="http://code.google.com/p/protobuf/"&gt;Protocol Buffers&lt;/a&gt; since they are both gaining traction as modern, low-latency &lt;span class="caps"&gt;RPC&lt;/span&gt; implementations.&lt;/p&gt;
&lt;p&gt;I had some contact with Thrift when I worked at Powerset, I talk to a lot of people that use Thrift at their jobs, and Scott is using Thrift as part of some Cassandra experiments we&amp;#8217;re doing. As much as I want to like Thrift, I just can&amp;#8217;t. I find the entire concept behind IDLs and code generation abhorrent. Coming from a background in dynamic languages and automated testing, these ideas just seem silly. The developer overhead required to constantly maintain IDLs and keep the corresponding implementation code up to date is too frustrating. I don&amp;#8217;t do these things when I write application code, so why should I be forced to do them when I write &lt;span class="caps"&gt;RPC&lt;/span&gt; code?&lt;/p&gt;
&lt;p&gt;Protocol Buffers ends up looking very similar to Thrift. More IDLs and more code generation. Any solution that relies on these concepts does not fit well with my worldview. In addition, the set of types available to both Thrift and Protocol Buffers feels limiting compared to what I&amp;#8217;d like to easily transmit over the wire.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.xmlrpc.com/"&gt;&lt;span class="caps"&gt;XML&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt;&lt;/a&gt;, &lt;a href="http://www.w3.org/TR/2003/REC-soap12-part2-20030624/"&gt;&lt;span class="caps"&gt;SOAP&lt;/span&gt;&lt;/a&gt;, and other &lt;span class="caps"&gt;XML&lt;/span&gt; based protocols are hardly even worth mentioning. They are unnecessarily verbose and complex. &lt;span class="caps"&gt;XML&lt;/span&gt; is not convertible to a simple unambiguous data structure in any language I&amp;#8217;ve ever used. I&amp;#8217;ve wasted too many hours of my life clumsily extracting data from &lt;span class="caps"&gt;XML&lt;/span&gt; files to feel anything but animosity towards the format.&lt;/p&gt;
&lt;p&gt;&lt;a href="http://json-rpc.org/"&gt;&lt;span class="caps"&gt;JSON&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt;&lt;/a&gt; is a nice system, much more inline with how I see the world. It&amp;#8217;s simple, relatively compact, has support for a decent set of types, and works well in an agile workflow. A big problem here, though, is the lack of support for native binary data. Our applications will be transmitting large amounts of binary data, and it displeases me to think that every byte of binary data I send across the wire would have to be encoded into an inferior representation just because &lt;span class="caps"&gt;JSON&lt;/span&gt; is a text-based protocol.&lt;/p&gt;
&lt;p&gt;After becoming thoroughly disenfranchised with the current &amp;#8220;state of the art&amp;#8221; &lt;span class="caps"&gt;RPC&lt;/span&gt; protocols, I sat down and started thinking about what the ideal solution would look like. I came up with a list that looked something like this:&lt;/p&gt;
&lt;ul&gt;
	&lt;li&gt;Extreme simplicity&lt;/li&gt;
	&lt;li&gt;Dynamic (No IDLs or code generation)&lt;/li&gt;
	&lt;li&gt;Good set of types (nil, symbols, hashes, bignums, heterogenous arrays, etc)&lt;/li&gt;
	&lt;li&gt;Support for complex types (Time, Regex, etc)&lt;/li&gt;
	&lt;li&gt;No need to encode binary data&lt;/li&gt;
	&lt;li&gt;Synchronous and Asynchronous calls&lt;/li&gt;
	&lt;li&gt;Fast serialization/deserialization&lt;/li&gt;
	&lt;li&gt;Streaming (to and from)&lt;/li&gt;
	&lt;li&gt;Caching directives&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I mentioned before that I like &lt;span class="caps"&gt;JSON&lt;/span&gt;. I love the concept of extracting a subset of a language and using that to facilitate interprocess communication. This got me thinking about the work I&amp;#8217;d done with &lt;a href="http://github.com/mojombo/erlectricity"&gt;Erlectricity&lt;/a&gt;. About two years ago I wrote a C extension for Erlectricity to speed up the deserialization of Erlang&amp;#8217;s external term format. I remember being very impressed with the simplicity of the serialization format and how easy it was to parse. Since I was considering using Erlang more within the GitHub architecture, an Erlang-centric solution might be really nice. Putting these pieces together, I was struck by an idea.&lt;/p&gt;
&lt;p&gt;What if I extracted the generic parts of Erlang&amp;#8217;s external term format and made that into a standard for interprocess communication? What if Erlang had the equivalent of JavaScript&amp;#8217;s &lt;span class="caps"&gt;JSON&lt;/span&gt;? And what if an &lt;span class="caps"&gt;RPC&lt;/span&gt; protocol could be built on top of that format? What would those things look like and how simple could they be made?&lt;/p&gt;
&lt;p&gt;Of course, the first thing any project needs is a good name, so I started brainstorming acronyms. &lt;span class="caps"&gt;EETF&lt;/span&gt; (Erlang External Term Format) is the obvious one, but it&amp;#8217;s boring and not accurate for what I wanted to do since I would only be using a subset of &lt;span class="caps"&gt;EETF&lt;/span&gt;. After a while I came up with &lt;span class="caps"&gt;BERT&lt;/span&gt; for Binary ERlang Term. Not only did this moniker precisely describe the nature of the idea, but it was nearly a person&amp;#8217;s name, just like &lt;span class="caps"&gt;JSON&lt;/span&gt;, offering a tip of the hat to my source of inspiration.&lt;/p&gt;
&lt;p&gt;Over the next few weeks I sketched out specifications for &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; and showed them to a bunch of my developer friends. I got some great feedback on ways to simplify some confusing parts of the spec and was able to boil things down to what I think is the simplest manifestation that still enables the rich set of features that I want these technologies to support.&lt;/p&gt;
&lt;p&gt;The responses were generally positive, and I found a lot of people looking for something simple to replace the nightmarish solutions they were currently forced to work with. If there&amp;#8217;s one thing I&amp;#8217;ve learned in doing open source over the last 5 years, it&amp;#8217;s that if I find an idea compelling, then there are probably a boatload of people out there that will feel the same way. So I went ahead with the project and created reference implementations in Ruby that would eventually become the backbone of the new GitHub architecture.&lt;/p&gt;
&lt;p&gt;But enough talk, let&amp;#8217;s take a look at the Ruby workflow and you&amp;#8217;ll see what I mean when I say that &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; are built around a philosophy of simplicity and Getting Things Done.&lt;/p&gt;
&lt;h3&gt;A Simple Example&lt;/h3&gt;
&lt;p&gt;To give you an idea of how easy it is to get a Ruby based &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; service running, consider the following simple calculator service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# calc.rb
require 'ernie'

mod(:calc) do
  fun(:add) do |a, b|
    a + b
  end
end&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a complete service file suitable for use by my Erlang/Ruby hybrid &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; server framework called &lt;a href="http://github.com/mojombo/ernie"&gt;Ernie&lt;/a&gt;. You start up the service like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;$ ernie -p 9999 -n 10 -h calc.rb&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This fires up the server on port 9999 and spawns ten Ruby workers to handle requests. Ernie takes care of balancing and queuing incoming connections. All you have to worry about is writing your &lt;span class="caps"&gt;RPC&lt;/span&gt; functions, Ernie takes care of the rest.&lt;/p&gt;
&lt;p&gt;To call the service, you can use my Ruby &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; client called &lt;a href="http://github.com/mojombo/bertrpc"&gt;&lt;span class="caps"&gt;BERTRPC&lt;/span&gt;&lt;/a&gt; like so:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;require 'bertrpc'

svc = BERTRPC::Service.new('localhost', 9999)
svc.call.calc.add(1, 2)
# =&amp;gt; 3&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;#8217;s it! Nine lines of code to a working example. No IDLs. No code generation. If the module and function that you call from the client exist on the server, then everything goes well. If they don&amp;#8217;t, then you get an exception, just like your application code.&lt;/p&gt;
&lt;p&gt;Since a &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; client can be written in any language, you could easily call the calculator service from Python or JavaScript or Lua or whatever. &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; are intended to make communicating between different languages as streamlined as possible.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The Ernie framework and the &lt;span class="caps"&gt;BERTRPC&lt;/span&gt; library power the new GitHub and we use them exactly as-is. They&amp;#8217;ve been in use since the move to Rackspace three weeks ago and are responsible for serving over 300 million &lt;span class="caps"&gt;RPC&lt;/span&gt; requests in that period. They are still incomplete implementations of the spec, but I plan to flesh them out as time goes on.&lt;/p&gt;
&lt;p&gt;If you find &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; intriguing, I&amp;#8217;d love to hear your feedback. The best place to hold discussions is on the &lt;a href="http://groups.google.com/group/bert-rpc"&gt;official mailing list&lt;/a&gt;. If you want to participate, I&amp;#8217;d love to see implementations in more languages. Together, we can make &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; the easiest way to get &lt;span class="caps"&gt;RPC&lt;/span&gt; done in every language!&lt;/p&gt;</content>
    <author>
      <name>mojombo</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/530</id>
    <published>2009-10-20T11:54:03-07:00</published>
    <updated>2009-10-21T10:08:08-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/530-how-we-made-github-fast" />
    <title>How We Made GitHub Fast</title>
    <content type="html">&lt;p&gt;Now that things have settled down from the move to Rackspace, I wanted to take some time to go over the architectural changes that we&amp;#8217;ve made in order to bring you a speedier, more scalable GitHub.&lt;/p&gt;
&lt;p&gt;In my first draft of this article I spent a lot of time explaining why we made each of the technology choices that we did. After a while, however, it became difficult to separate the architecture from the discourse and the whole thing became confusing. So I&amp;#8217;ve decided to simply explain the architecture and then write a series of follow up posts with more detailed analyses of exactly why we made the choices we did.&lt;/p&gt;
&lt;p&gt;There are many ways to scale modern web applications. What I will be describing here is the method that we chose. This should by no means be considered the only way to scale an application. Consider it a case study of what worked for us given our unique requirements.&lt;/p&gt;
&lt;h3&gt;Understanding the Protocols&lt;/h3&gt;
&lt;p&gt;We expose three primary protocols to end users of GitHub: &lt;span class="caps"&gt;HTTP&lt;/span&gt;, &lt;span class="caps"&gt;SSH&lt;/span&gt;, and Git. When browsing the site with your favorite browser, you&amp;#8217;re using &lt;span class="caps"&gt;HTTP&lt;/span&gt;. When you clone, pull, or push to a private &lt;span class="caps"&gt;URL&lt;/span&gt; like &lt;span style="background-color:#ddd; padding: 0 .2em; font: 90% Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;"&gt;git&amp;#64;github.com:mojombo/jekyll.git&lt;/span&gt; you&amp;#8217;re doing so via &lt;span class="caps"&gt;SSH&lt;/span&gt;. When you clone or pull from a public repository via a &lt;span class="caps"&gt;URL&lt;/span&gt; like &lt;code&gt;git://github.com/mojombo/jekyll.git&lt;/code&gt; you&amp;#8217;re using the Git protocol.&lt;/p&gt;
&lt;p&gt;The easiest way to understand the architecture is by tracing how each of these requests propagates through the system.&lt;/p&gt;
&lt;h3&gt;Tracing an &lt;span class="caps"&gt;HTTP&lt;/span&gt; Request&lt;/h3&gt;
&lt;p&gt;For this example I&amp;#8217;ll show you how a request for a tree page such as &lt;a href="http://github.com/mojombo/jekyll"&gt;http://github.com/mojombo/jekyll&lt;/a&gt; happens.&lt;/p&gt;
&lt;p&gt;The first thing your request hits after coming down from the internet is the active load balancer. For this task we use a pair of Xen instances running &lt;a href="http://www.vergenet.net/linux/ldirectord/"&gt;ldirectord&lt;/a&gt;. These are called &lt;code&gt;lb1a&lt;/code&gt; and &lt;code&gt;lb1b&lt;/code&gt;. At any given time one of these is active and the other is waiting to take over in case of a failure in the master. The load balancer doesn&amp;#8217;t do anything fancy. It forwards &lt;span class="caps"&gt;TCP&lt;/span&gt; packets to various servers based on the requested IP and port and can remove misbehaving servers from the balance pool if necessary. In the event that no servers are available for a given pool it can serve a simple static site instead of refusing connections.&lt;/p&gt;
&lt;p&gt;For requests to the main website, the load balancer ships your request off to one of the four frontend machines. Each of these is an 8 core, 16GB &lt;span class="caps"&gt;RAM&lt;/span&gt; bare metal server. Their names are &lt;code&gt;fe1&lt;/code&gt;, &amp;#8230;, &lt;code&gt;fe4&lt;/code&gt;. &lt;a href="http://nginx.net/"&gt;Nginx&lt;/a&gt; accepts the connection and sends it to a Unix domain socket upon which sixteen &lt;a href="http://github.com/blog/517-unicorn"&gt;Unicorn&lt;/a&gt; worker processes are selecting. One of these workers grabs the request and runs the &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt; code necessary to fulfill it.&lt;/p&gt;
&lt;p&gt;Many pages require database lookups. Our MySQL database runs on two 8 core, 32GB &lt;span class="caps"&gt;RAM&lt;/span&gt; bare metal servers with 15k &lt;span class="caps"&gt;RPM&lt;/span&gt; &lt;span class="caps"&gt;SAS&lt;/span&gt; drives. Their names are &lt;code&gt;db1a&lt;/code&gt; and &lt;code&gt;db1b&lt;/code&gt;. At any given time, one of them is master and one is slave. MySQL replication is accomplished via &lt;a href="http://www.drbd.org/"&gt;&lt;span class="caps"&gt;DRBD&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If the page requires information about a Git repository and that data is not cached, then it will use our &lt;a href="http://github.com/mojombo/grit"&gt;Grit&lt;/a&gt; library to retrieve the data. In order to accommodate our Rackspace setup, we&amp;#8217;ve modified Grit to do something special. We start by abstracting out every call that needs access to the filesystem into the Grit::Git object. We then replace Grit::Git with a stub that makes &lt;span class="caps"&gt;RPC&lt;/span&gt; calls to our Smoke service. Smoke has direct disk access to the repositories and essentially presents Grit::Git as a service. It&amp;#8217;s called Smoke because Smoke is just Grit in the cloud. Get it?&lt;/p&gt;
&lt;p&gt;The stubbed Grit makes &lt;span class="caps"&gt;RPC&lt;/span&gt; calls to &lt;code&gt;smoke&lt;/code&gt; which is a load balanced hostname that maps back to the &lt;code&gt;fe&lt;/code&gt; machines. Each frontend runs four &lt;a href="http://github.com/mojombo/proxymachine"&gt;ProxyMachine&lt;/a&gt; instances behind &lt;a href="http://haproxy.1wt.eu/"&gt;HAProxy&lt;/a&gt; that act as routing proxies for Smoke calls. ProxyMachine is my content aware (layer 7) &lt;span class="caps"&gt;TCP&lt;/span&gt; routing proxy that lets us write the routing logic in Ruby. The proxy examines the request and extracts the username of the repository that has been specified. We then use a proprietary library called Chimney (it routes the smoke!) to lookup the route for that user. A user&amp;#8217;s route is simply the hostname of the file server on which that user&amp;#8217;s repositories are kept.&lt;/p&gt;
&lt;p&gt;Chimney finds the route by making a call to &lt;a href="http://code.google.com/p/redis/"&gt;Redis&lt;/a&gt;. Redis runs on the database servers. We use Redis as a persistent key/value store for the routing information and a variety of other data.&lt;/p&gt;
&lt;p&gt;Once the Smoke proxy has determined the user&amp;#8217;s route, it establishes a transparent proxy to the proper file server. We have four pairs of fileservers. Their names are &lt;code&gt;fs1a&lt;/code&gt;, &lt;code&gt;fs1b&lt;/code&gt;, &amp;#8230;, &lt;code&gt;fs4a&lt;/code&gt;, &lt;code&gt;fs4b&lt;/code&gt;. These are 8 core, 16GB &lt;span class="caps"&gt;RAM&lt;/span&gt; bare metal servers, each with six 300GB 15K &lt;span class="caps"&gt;RPM&lt;/span&gt; &lt;span class="caps"&gt;SAS&lt;/span&gt; drives arranged in &lt;span class="caps"&gt;RAID&lt;/span&gt; 10. At any given time one server in each pair is active and the other is waiting to take over should there be a fatal failure in the master. All repository data is constantly replicated from the master to the slave via &lt;span class="caps"&gt;DRBD&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Every file server runs two &lt;a href="http://github.com/mojombo/ernie"&gt;Ernie&lt;/a&gt; &lt;span class="caps"&gt;RPC&lt;/span&gt; servers behind HAProxy. Each Ernie spawns 15 Ruby workers. These workers take the &lt;span class="caps"&gt;RPC&lt;/span&gt; call and reconstitute and perform the Grit call. The response is sent back through the Smoke proxy to the Rails app where the Grit stub returns the expected Grit response.&lt;/p&gt;
&lt;p&gt;When Unicorn is finished with the Rails action, the response is sent back through Nginx and directly to the client (outgoing responses do not go back through the load balancer).&lt;/p&gt;
&lt;p&gt;Finally, you see a pretty web page!&lt;/p&gt;
&lt;p&gt;The above flow is what happens when there are no cache hits. In many cases the Rails code uses Evan Weaver&amp;#8217;s Ruby &lt;a href="http://github.com/fauna/memcached/"&gt;memcached&lt;/a&gt; client to query the &lt;a href="http://www.danga.com/memcached/"&gt;Memcache&lt;/a&gt; servers that run on each slave file server. Since these machines are otherwise idle, we place 12GB of Memcache on each. These servers are aliased as &lt;code&gt;memcache1&lt;/code&gt;, &amp;#8230;, &lt;code&gt;memcache4&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;For our data serialization and &lt;span class="caps"&gt;RPC&lt;/span&gt; protocol we are using &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt;. You haven&amp;#8217;t heard of them before because they&amp;#8217;re brand new. I invented them because I was not satisfied with any of the available options that I evaluated, and I wanted to experiment with an idea that I&amp;#8217;ve had for a while. Before you freak out about &lt;span class="caps"&gt;NIH&lt;/span&gt; syndrome (or to help you refine your freak out), please read my accompanying article &lt;a href="http://github.com/blog/531-introducing-bert-and-bert-rpc"&gt;Introducing &lt;span class="caps"&gt;BERT&lt;/span&gt; and &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt;&lt;/a&gt; about how these technologies came to be and what I intend for them to solve.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;d rather just check out the spec, head over to &lt;a href="http://bert-rpc.org"&gt;http://bert-rpc.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For the code hungry, check out my Ruby &lt;span class="caps"&gt;BERT&lt;/span&gt; serialization library &lt;a href="http://github.com/mojombo/bert"&gt;&lt;span class="caps"&gt;BERT&lt;/span&gt;&lt;/a&gt;, my Ruby &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; client &lt;a href="http://github.com/mojombo/bertrpc"&gt;&lt;span class="caps"&gt;BERTRPC&lt;/span&gt;&lt;/a&gt;, and my Erlang/Ruby hybrid &lt;span class="caps"&gt;BERT&lt;/span&gt;-&lt;span class="caps"&gt;RPC&lt;/span&gt; server &lt;a href="http://github.com/mojombo/ernie"&gt;Ernie&lt;/a&gt;. These are the exact libraries we use at GitHub to serve up all repository data.&lt;/p&gt;
&lt;h3&gt;Tracing an &lt;span class="caps"&gt;SSH&lt;/span&gt; Request&lt;/h3&gt;
&lt;p&gt;Git uses &lt;span class="caps"&gt;SSH&lt;/span&gt; for encrypted communications between you and the server. In order to understand how our architecture deals with &lt;span class="caps"&gt;SSH&lt;/span&gt; connections, it is first important to understand how this works in a simpler setup.&lt;/p&gt;
&lt;p&gt;Git relies on the fact that &lt;span class="caps"&gt;SSH&lt;/span&gt; allows you to execute commands on a remote server. For instance, the command &lt;span style="background-color:#ddd; padding: 0 .2em; font: 90% Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;"&gt;ssh tom&amp;#64;frost ls -al&lt;/span&gt; runs &lt;code&gt;ls -al&lt;/code&gt; in the home directory of my user on the &lt;code&gt;frost&lt;/code&gt; server. I get the output of the command on my local terminal. &lt;span class="caps"&gt;SSH&lt;/span&gt; is essentially hooking up the &lt;span class="caps"&gt;STDIN&lt;/span&gt;, &lt;span class="caps"&gt;STDOUT&lt;/span&gt;, and &lt;span class="caps"&gt;STDERR&lt;/span&gt; of the remote machine to my local terminal.&lt;/p&gt;
&lt;p&gt;If you run a command like &lt;span style="background-color:#ddd; padding: 0 .2em; font: 90% Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;"&gt;git clone tom&amp;#64;frost:mojombo/bert&lt;/span&gt;, what Git is doing behind the scenes is SSHing to &lt;code&gt;frost&lt;/code&gt;, authenticating as the &lt;code&gt;tom&lt;/code&gt; user, and then remotely executing &lt;code&gt;git upload-pack mojombo/bert&lt;/code&gt;. Now your client can talk to that process on the remote server by simply reading and writing over the &lt;span class="caps"&gt;SSH&lt;/span&gt; connection. Neat, huh?&lt;/p&gt;
&lt;p&gt;Of course, allowing arbitrary execution of commands is unsafe, so &lt;span class="caps"&gt;SSH&lt;/span&gt; includes the ability to restrict what commands can be executed. In a very simple case, you can restrict execution to &lt;a href="http://www.kernel.org/pub/software/scm/git/docs/git-shell.html"&gt;git-shell&lt;/a&gt; which is included with Git. All this script does is check the command that you&amp;#8217;re trying to execute and ensure that it&amp;#8217;s one of &lt;code&gt;git upload-pack&lt;/code&gt;, &lt;code&gt;git receive-pack&lt;/code&gt;, or &lt;code&gt;git upload-archive&lt;/code&gt;. If it is indeed one of those, it uses &lt;a href="http://linux.die.net/man/3/exec" title="3"&gt;exec&lt;/a&gt; to replace the current process with that new process. After that, it&amp;#8217;s as if you had just executed that command directly.&lt;/p&gt;
&lt;p&gt;So, now that you know how Git&amp;#8217;s &lt;span class="caps"&gt;SSH&lt;/span&gt; operations work in a simple case, let me show you how we handle this in GitHub&amp;#8217;s architecture.&lt;/p&gt;
&lt;p&gt;First, your Git client initiates an &lt;span class="caps"&gt;SSH&lt;/span&gt; session. The connection comes down off the internet and hits our load balancer.&lt;/p&gt;
&lt;p&gt;From there, the connection is sent to one of the frontends where &lt;a href="http://www.au.kernel.org/software/scm/git/docs/git-daemon.html"&gt;&lt;span class="caps"&gt;SSHD&lt;/span&gt;&lt;/a&gt; accepts it. We have patched our &lt;span class="caps"&gt;SSH&lt;/span&gt; daemon to perform public key lookups from our MySQL database. Your key identifies your GitHub user and this information is sent along with the original command and arguments to our proprietary script called Gerve (Git sERVE). Think of Gerve as a super smart version of &lt;code&gt;git-shell&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Gerve verifies that your user has access to the repository specified in the arguments. If you are the owner of the repository, no database lookups need to be performed, otherwise several &lt;span class="caps"&gt;SQL&lt;/span&gt; queries are made to determine permissions.&lt;/p&gt;
&lt;p&gt;Once access has been verified, Gerve uses Chimney to look up the route for the owner of the repository. The goal now is to execute your original command on the proper file server and hook your local machine up to that process. What better way to do this than with another remote &lt;span class="caps"&gt;SSH&lt;/span&gt; execution!&lt;/p&gt;
&lt;p&gt;I know it sounds crazy but it works great. Gerve simply uses &lt;code&gt;exec(3)&lt;/code&gt; to replace itself with a call to&lt;span style="background-color:#ddd; padding: 0 .2em; font: 90% Monaco, 'Courier New', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;"&gt;ssh git&amp;#64;&amp;lt;route&amp;gt; &amp;lt;command&amp;gt; &amp;lt;arg&amp;gt;&lt;/span&gt;. After this call, your client is hooked up to a process on a frontend machine which is, in turn, hooked up to a process on a file server.&lt;/p&gt;
&lt;p&gt;Think of it this way: after determining permissions and the location of the repository, the frontend becomes a transparent proxy for the rest of the session. The only drawback to this approach is that the internal &lt;span class="caps"&gt;SSH&lt;/span&gt; is unnecessarily encumbered by the overhead of encryption/decryption when none is strictly required. It&amp;#8217;s possible we may replace this this internal &lt;span class="caps"&gt;SSH&lt;/span&gt; call with something more efficient, but this approach is just too damn simple (and still very fast) to make me worry about it very much.&lt;/p&gt;
&lt;h3&gt;Tracing a Git Request&lt;/h3&gt;
&lt;p&gt;Performing public clones and pulls via Git is similar to how the &lt;span class="caps"&gt;SSH&lt;/span&gt; method works. Instead of using &lt;span class="caps"&gt;SSH&lt;/span&gt; for authentication and encryption, however, it relies on a server side &lt;a href="http://www.au.kernel.org/software/scm/git/docs/git-daemon.html"&gt;Git Daemon&lt;/a&gt;. This daemon accepts connections, verifies the command to be run, and then uses &lt;code&gt;fork(2)&lt;/code&gt; and &lt;code&gt;exec(3)&lt;/code&gt; to spawn a worker that then becomes the command process.&lt;/p&gt;
&lt;p&gt;With this in mind, I&amp;#8217;ll show you how a public clone operation works.&lt;/p&gt;
&lt;p&gt;First, your Git client issues a &lt;a href="http://github.com/mojombo/egitd/blob/master/docs/protocol.txt"&gt;request&lt;/a&gt; containing the command and repository name you wish to clone. This request enters our system on the load balancer.&lt;/p&gt;
&lt;p&gt;From there, the request is sent to one of the frontends. Each frontend runs four ProxyMachine instances behind HAProxy that act as routing proxies for the Git protocol. The proxy inspects the request and extracts the username (or gist name) of the repo. It then uses Chimney to lookup the route. If there is no route or any other error is encountered, the proxy speaks the Git protocol and sends back an appropriate messages to the client. Once the route is known, the repo name (e.g. &lt;code&gt;mojombo/bert&lt;/code&gt;) is translated into its path on disk (e.g. &lt;code&gt;a/a8/e2/95/mojombo/bert.git&lt;/code&gt;). On our old setup that had no proxies, we had to use a modified daemon that could convert the user/repo into the correct filepath. By doing this step in the proxy, we can now use an unmodified daemon, allowing for a much easier upgrade path.&lt;/p&gt;
&lt;p&gt;Next, the Git proxy establishes a transparent proxy with the proper file server and sends the modified request (with the converted repository path). Each file server runs two Git Daemon processes behind HAProxy. The daemon speaks the pack file protocol and streams data back through the Git proxy and directly to your Git client.&lt;/p&gt;
&lt;p&gt;Once your client has all the data, you&amp;#8217;ve cloned the repository and can get to work!&lt;/p&gt;
&lt;h3&gt;Sub- and Side-Systems&lt;/h3&gt;
&lt;p&gt;In addition to the primary web application and Git hosting systems, we also run a variety of other sub-systems and side-systems. Sub-systems include the job queue, archive downloads, billing, mirroring, and the svn importer. Side-systems include GitHub Pages, Gist, gem server, and a bunch of internal tools. You can look forward to explanations of how some of these work within the new architecture, and what new technologies we&amp;#8217;ve created to help our application run more smoothly.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The architecture outlined here has allowed us to properly scale the site and resulted in massive performance increases across the entire site. Our average Rails response time on our previous setup was anywhere from 500ms to several seconds depending on how loaded the slices were. Moving to bare metal and federated storage on Rackspace has brought our average Rails response time to consistently under 100ms. In addition, the job queue now has no problem keeping up with the 280,000 background jobs we process every day. We still have plenty of headroom to grow with the current set of hardware, and when the time comes to add more machines, we can add new servers on any tier with ease. I&amp;#8217;m very pleased with how well everything is working, and if you&amp;#8217;re like me, you&amp;#8217;re enjoying the new and improved GitHub every day!&lt;/p&gt;</content>
    <author>
      <name>mojombo</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/529</id>
    <published>2009-10-19T09:37:58-07:00</published>
    <updated>2009-10-19T10:04:52-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/529-ryan-tomayko-is-a-githubber" />
    <title>Ryan Tomayko is a GitHubber</title>
    <content type="html">&lt;p&gt;Today marks &lt;a href="http://github.com/rtomayko"&gt;Ryan Tomayko&amp;#8217;s&lt;/a&gt; first day as a GitHubber. He&amp;#8217;ll be helping make GitHub more stable, reliable, and awesome.&lt;/p&gt;
&lt;p&gt;Ryan has consistently impressed all of us with his work on &lt;a href="http://github.com/sinatra/sinatra"&gt;Sinatra&lt;/a&gt; and &lt;a href="http://github.com/rack/rack"&gt;Rack&lt;/a&gt;, the awesomeness of &lt;a href="http://github.com/rtomayko/shotgun"&gt;shotgun&lt;/a&gt; and &lt;a href="http://github.com/rtomayko/git-sh"&gt;git-sh&lt;/a&gt;, his prolific &lt;a href="http://tomayko.com/"&gt;writing and linking&lt;/a&gt;, and his various other projects.&lt;/p&gt;
&lt;div align="center"&gt;&lt;a href="http://github.com/rtomayko"&gt;&lt;img src="http://img.skitch.com/20091019-rxbm5925t37sjtxik2u7m4wj5a.jpg"/&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div align="center" xmlns:cc="http://creativecommons.org/ns#" about="http://www.flickr.com/photos/mojombo/3625905407/in/set-72157619744233018/"&gt;&lt;a rel="cc:attributionURL" href="http://www.flickr.com/photos/mojombo/"&gt;http://www.flickr.com/photos/mojombo/&lt;/a&gt; / &lt;a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/2.0/"&gt;CC BY-NC-SA 2.0&lt;/a&gt;&lt;/div&gt;
&lt;p&gt;You can follow &lt;a href="http://tomayko.com/"&gt;his blog&lt;/a&gt;, &lt;a href="http://twitter.com/rtomayko"&gt;his twitter&lt;/a&gt;, or &lt;a href="http://github.com/rtomayko"&gt;his GitHub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Welcome to the team, Ryan!&lt;/p&gt;</content>
    <author>
      <name>defunkt</name>
    </author>
  </entry>
  <entry>
    <id>tag:github.com,2008:Post/528</id>
    <published>2009-10-18T18:51:27-07:00</published>
    <updated>2009-10-19T00:16:07-07:00</updated>
    <link type="text/html" rel="alternate" href="http://github.com/blog/528-scheduled-maintenance-tonight-at-23-00-pdt" />
    <title>Scheduled Maintenance Tonight at 23:00 PDT</title>
    <content type="html">&lt;p&gt;We will be having a maintenance window tonight from &lt;a href="http://www.timeanddate.com/worldclock/fixedtime.html?month=10&amp;amp;day=18&amp;amp;year=2009&amp;amp;hour=23&amp;amp;min=0&amp;amp;sec=0&amp;amp;p1=224"&gt;23:00 to 23:59 &lt;span class="caps"&gt;PDT&lt;/span&gt;&lt;/a&gt;. A very small amount of web unavailability will be required during this period.&lt;/p&gt;
&lt;p&gt;We will be upgrading some core libraries to versions that are not compatible with what is currently running, so all daemons must be restarted simultaneously. For this to go smoothly, we will be disabling the web app for perhaps 30 seconds.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;UPDATE&lt;/span&gt;: Maintenance was completed successfully. Total web unavailability was a tad more than estimated at one minute and 40 seconds. Some job runners did not restart cleanly and as a result some jobs failed, but all job runners are operating normally now. If you experienced any problems during the maintenance window, don&amp;#8217;t hesitate to contact us at &lt;a href="http://support.github.com"&gt;http://support.github.com&lt;/a&gt;.&lt;/p&gt;</content>
    <author>
      <name>mojombo</name>
    </author>
  </entry>
</feed>
