<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Erlang-China &#187; comet</title>
	<atom:link href="http://erlang-china.org/tag/comet/feed" rel="self" type="application/rss+xml" />
	<link>http://erlang-china.org</link>
	<description>erlang 中文社区</description>
	<lastBuildDate>Tue, 24 Apr 2012 05:39:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>&#8220;Comet &amp; Erlang&#8221; 为 beijing open party 准备的 Slide</title>
		<link>http://erlang-china.org/misc/slide_for_beijing-open-party.html</link>
		<comments>http://erlang-china.org/misc/slide_for_beijing-open-party.html#comments</comments>
		<pubDate>Sat, 15 Nov 2008 04:22:41 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[misc]]></category>
		<category><![CDATA[beijing-open-party]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[erlang]]></category>
		<category><![CDATA[slide]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=259</guid>
		<description><![CDATA[为 Beijing open party 准备了一个 Slide ，主要讨论在 Comet 和 Erlang 领域的最新进展。这也是我准备要在 CN Erlouge III 上讲到的内容(当然，在 Erlouge 上讲的时候，侧重点和深度会有很大的不同)，也算是我对 topic 的一次 preview 吧。有兴趣的同学可以看看。]]></description>
			<content:encoded><![CDATA[<p><iframe src='http://docs.google.com/EmbedSlideshow?docid=df2m2zgw_22cq99rhfr' frameborder='0' width='410' height='342'></iframe></p>
<p>为 <a href="http://www.beijing-open-party.org/" target=_blank>Beijing open party</a> 准备了一个 Slide ，主要讨论在 Comet 和 Erlang 领域的最新进展。这也是我准备要在 CN Erlouge III 上讲到的内容(当然，在 Erlouge 上讲的时候，侧重点和深度会有很大的不同)，也算是我对 topic 的一次 preview 吧。有兴趣的同学可以看看。</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/misc/slide_for_beijing-open-party.html/feed</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Comet and Erlang, A perfect match</title>
		<link>http://erlang-china.org/misc/comet-and-erlang-a-perfect-match.html</link>
		<comments>http://erlang-china.org/misc/comet-and-erlang-a-perfect-match.html#comments</comments>
		<pubDate>Tue, 21 Oct 2008 04:00:16 +0000</pubDate>
		<dc:creator>jackyz</dc:creator>
				<category><![CDATA[misc]]></category>
		<category><![CDATA[comet]]></category>
		<category><![CDATA[http]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[mochiweb]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[tcp]]></category>
		<category><![CDATA[turing]]></category>

		<guid isPermaLink="false">http://erlang-china.org/?p=245</guid>
		<description><![CDATA[家住 London 的 Richard Jones 同学(原来是 Last.fm 的 co-founded 之一)开始了关于 Comet 和 Erlang 的一个文章系列 —— 《A Million-user Comet Application with Mochiweb》。这个系列的第一篇在 [这里] 可以看到原文。 update: 第二篇的原文在[这里]。 update: 第三篇的原文在[这里]。 整个系列已经结束。翻译的同学，趁热。 update: oscar 同学目前提供了第一篇，第二篇的中文译版，辛苦了 oscar ！ idisc 同学已经提供了完整三篇的中文译版，分别是：第一篇，第二篇，第三篇，辛苦了 idisc ！ 在并不算长的时间里， oscar 和 idisc 同学就给我们提供了这篇极具参考价值文章的高质量翻译，非常难得，严重感谢！有了你们这样热心的成员，我们小而温馨的 Erlang 中文社区一定会变得越来越好。 干货如下： 作为这个系列的开篇， Richard Jones 首先在 mochiweb 上实现了一个原型的 comet 程序。用 Erlang 在 [...]]]></description>
			<content:encoded><![CDATA[<p>家住 London 的 Richard Jones 同学(原来是 Last.fm 的 co-founded 之一)开始了关于 Comet 和 Erlang 的一个文章系列 —— 《A Million-user Comet Application with Mochiweb》。这个系列的第一篇在 [<a href="http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-1/" target=_blank>这里</a>] 可以看到原文。</p>
<p>update: 第二篇的原文在[<a href="http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-2/" target=_blank>这里</a>]。</p>
<p>update: 第三篇的原文在[<a href="http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-3/" target=_blank>这里</a>]。</p>
<p>整个系列已经结束。<del datetime="2008-11-30T12:46:20+00:00">翻译的同学，趁热。</del> <img src='http://erlang-china.org/wordpress/wp-includes/images/smilies/icon_biggrin.gif' alt=':D' class='wp-smiley' /> </p>
<p>update:</p>
<p><a href="http://ro4tub.blogspot.com/" target=_blank>oscar</a> 同学目前提供了<a href="http://ro4tub.blogspot.com/2008/10/mochiwebcomet.html" target=_blank>第一篇</a>，<a href="http://ro4tub.blogspot.com/2008/10/mochiwebcomet_29.html" target=_blank>第二篇</a>的中文译版，辛苦了 oscar ！</p>
<p><a href="http://idisc.javaeye.com/blog" target=_blank>idisc</a> 同学已经提供了完整三篇的中文译版，分别是：<a href="http://idisc.javaeye.com/blog/267028" target=_blank>第一篇</a>，<a href="http://idisc.javaeye.com/blog/270076" target=_blank>第二篇</a>，<a href="http://idisc.javaeye.com/blog/273074" target=_blank>第三篇</a>，辛苦了 idisc ！</p>
<p>在并不算长的时间里， oscar 和 idisc 同学就给我们提供了这篇极具参考价值文章的高质量翻译，非常难得，严重感谢！有了你们这样热心的成员，我们小而温馨的 Erlang 中文社区一定会变得越来越好。</p>
<p>干货如下：</p>
<p><span id="more-245"></span></p>
<p>作为这个系列的开篇， Richard Jones 首先在 mochiweb 上实现了一个原型的 comet 程序。用 Erlang 在 mochiweb 下做这件事已经变得超级简单，可以与[<a href="http://erlang-china.org/misc/facebook_comet_in_mochiweb.html" target=_blank>这篇</a>]中的代码对照起来看。</p>
<p>在验证这个程序能正常工作之后 Richard 同学立即对其进行调优。首先是环境，也就是对 Linux Kernel 的 TCP 配置进行优化。其次是工具，他写了一个 Erlang 的小程序，从文件中加载 URL 然后发起连结。通过实测，他得出了自己对性能的结论：</p>
<blockquote><p>The resident size of the mochiweb beam process with 10,000 active connections was 450MB &#8211; that’s 45KB per connection. CPU utilization on the machine was practically nothing, as expected.</p></blockquote>
<p>应该说 45KB per connection 并不能算是特别好的结果。作者认为，如果用 libevent 的 c 程序，可能能够达到 4.5KB per connection 的水平。comment 中 Bob Ippolito (mochiweb的作者)提到，通过修改 spawn 的 heap_size 属性，可以获得更低的资源消耗水平。</p>
<p>update: 第二篇已经通过让进程 hibernate 的方式调优到了 8k per connection 的水平。</p>
<p>update: 第三篇作者通过利用打了 patch 的 libevent 做了一个 cnode 达到了不可思议的 C1024K 并发负载量。</p>
<p>关于 mochiweb 和 comet ，也是本站一直以来的关注重点，除了“放狗”和“wikipedia”之外，也可以比较便利的参考本站的[<a href="http://erlang-china.org/misc/facebook_comet_in_mochiweb.html">这篇</a>]以及[<a href="http://erlang-china.org/misc/server-push-the-google-way.html">这篇</a>]。</p>
<p>为方便阅读，全文 paste 如下：</p>
<p><strong>A Million-user Comet Application with Mochiweb, Part 1</strong></p>
<p>In this series I will detail what I found out empirically about how mochiweb performs with lots of open connections, and show how to build a comet application using mochiweb, where each mochiweb connection is registered with a router which dispatches messages to various users. We end up with a working application that can cope with a million concurrent connections, and crucially, knowing how much RAM we need to make it work.</p>
<p>In part one:</p>
<ul>
<li>Build a basic comet mochiweb app that sends clients a message every 10 seconds.</li>
<li>Tune the Linux kernel to handle lots of TCP connections</li>
<li>Build a flood-testing tool to open lots of connections (ye olde C10k test)</li>
<li>Examine how much memory this requires per connection.</li>
</ul>
<p>Future posts in this series will cover how to build a real message routing system, additional tricks to reduce memory usage, and more testing with 100k and 1m concurrent connections.</p>
<p>I assume you know your way around the Linux command line, and know a bit of Erlang.</p>
<p><strong>Building a Mochiweb test application</strong></p>
<p>In brief:</p>
<ul>
<ol>Install and build Mochiweb</ol>
<ol>Run: /your-mochiweb-path/scripts/new_mochiweb.erl mochiconntest</ol>
<ol>cd mochiconntest and edit src/mochiconntest_web.erl</ol>
</ul>
<p>This code (mochiconntest_web.erl) just accepts connections and uses chunked transfer to send an initial welcome message, and one message every 10 seconds to every client.</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=mochiconntest_web.erl">mochiconntest_web.erl</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">mochiconntest_web</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">stop</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">loop</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% External API</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">DocRoot</span><span style="color: Gray;">, </span><span style="color: Blue;">Options1</span><span style="color: Gray;">} = </span><span style="color: Blue;">get_option</span><span style="color: Olive;">(</span><span style="color: Blue;">docroot</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Loop</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">:</span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Gray;">, </span><span style="color: Blue;">DocRoot</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% we’ll set our maximum to 1 million connections. (default: 2048)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mochiweb_http</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">([</span><span style="color: Gray;">{</span><span style="color: Blue;">max</span><span style="color: Gray;">, </span><span style="color: Maroon;">1000000</span><span style="color: Gray;">}, {</span><span style="color: Blue;">name</span><span style="color: Gray;">, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">}, {</span><span style="color: Blue;">loop</span><span style="color: Gray;">, </span><span style="color: Blue;">Loop</span><span style="color: Gray;">} | </span><span style="color: Blue;">Options1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">stop</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mochiweb_http</span><span style="color: Gray;">:</span><span style="color: Blue;">stop</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Gray;">, </span><span style="color: Blue;">DocRoot</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">Path</span><span style="color: Gray;"> = </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">get</span><span style="color: Olive;">(</span><span style="color: Blue;">path</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">get</span><span style="color: Olive;">(</span><span style="color: Blue;">method</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Method</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">Method</span><span style="color: Gray;"> =:= ‘</span><span style="color: Blue;">GET</span><span style="color: Gray;">’; </span><span style="color: Blue;">Method</span><span style="color: Gray;"> =:= ‘</span><span style="color: Blue;">HEAD</span><span style="color: Gray;">’ -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Path</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">test/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">Id</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Response</span><span style="color: Gray;"> = </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">ok</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">text/html; charset=utf-8</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">{</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Server</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Mochiweb-Test</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">}</span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">chunked</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Response</span><span style="color: Gray;">:</span><span style="color: Blue;">write_chunk</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Mochiconntest welcomes you! Your Id: </span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">Id</span><span style="color: Gray;"> ++ </span><span style="color: #8b0000;">&quot;</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% router:login(list_to_atom(Id), self()),</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">feed</span><span style="color: Olive;">(</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">not_found</span><span style="color: Olive;">()</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ‘</span><span style="color: Blue;">POST</span><span style="color: Gray;">’ -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Path</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">not_found</span><span style="color: Olive;">()</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">respond</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Maroon;">501</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">feed</span><span style="color: Olive;">(</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Path</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%{router_msg, Msg} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%&nbsp; &nbsp; Html = io_lib:format(&quot;Recvd msg #~w: ‘~s’&lt;br/&gt;&quot;, [N, Msg]),</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%&nbsp; &nbsp; Response:write_chunk(Html);</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">after</span><span style="color: Gray;">&nbsp;</span><span style="color: Maroon;">10000</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Msg</span><span style="color: Gray;"> = </span><span style="color: Blue;">io_lib</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Chunk ~w for id ~s</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">Path</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Response</span><span style="color: Gray;">:</span><span style="color: Blue;">write_chunk</span><span style="color: Olive;">(</span><span style="color: Blue;">Msg</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">feed</span><span style="color: Olive;">(</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Path</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% Internal API</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">get_option</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">proplists</span><span style="color: Gray;">:</span><span style="color: Blue;">get_value</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: Blue;">proplists</span><span style="color: Gray;">:</span><span style="color: Blue;">delete</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">}.</span></li></ol></div>
<p><strong>Start your mochiweb app</strong></p>
<div class="hl-surround"><div class="hl-main">make &amp;&amp; ./start-dev.sh</div></div>
<p>By default mochiweb listens on port 8000, on all interfaces. If you are doing this on the desktop, you can test with any web browser. Just navigate to http://localhost:8000/test/foo.</p>
<p>Here’s the command-line test:</p>
<div class="hl-surround"><div class="hl-main">$ lynx --source &quot;http://localhost:8000/test/foo&quot;<br />Mochiconntest welcomes you! Your Id: foo&lt;br/&gt;<br />Chunk 1 for id foo&lt;br/&gt;<br />Chunk 2 for id foo&lt;br/&gt;<br />Chunk 3 for id foo&lt;br/&gt;<br />^C</div></div>
<p>Yep, it works. Now let’s make it suffer.</p>
<p><strong>Tuning the Linux Kernel for many tcp connections</strong></p>
<p>Save yourself some time and tune the kernel tcp settings before testing with lots of connections, or your test will fail and you’ll see lots of Out of socket memory messages (and if you are masquerading, nf_conntrack: table full, dropping packet.)</p>
<p>Here are the sysctl settings I ended up with &#8211; YMMV, but these will probably do:</p>
<div class="hl-surround"><div class="hl-main"># General gigabit tuning:<br />net.core.rmem_max = 16777216<br />net.core.wmem_max = 16777216<br />net.ipv4.tcp_rmem = 4096 87380 16777216<br />net.ipv4.tcp_wmem = 4096 65536 16777216<br />net.ipv4.tcp_syncookies = 1<br /># this gives the kernel more memory for tcp<br /># which you need with many (100k+) open socket connections<br />net.ipv4.tcp_mem = 50576&nbsp; &nbsp;64768&nbsp; &nbsp;98152<br />net.core.netdev_max_backlog = 2500<br /># I was also masquerading the port comet was on, you might not need this<br />net.ipv4.netfilter.ip_conntrack_max = 1048576</div></div>
<p>Put these in /etc/sysctl.conf then run sysctl -p to apply them. No need to reboot, now your kernel should be able to handle a lot more open connections, yay.<br />
Creating a lot of connections</p>
<p>There are many ways to do this. Tsung is quite sexy, and there and plenty of other less-sexy ways to spam an httpd with lots of requests (ab, httperf, httpload etc). None of them are ideally suited for testing a comet application, and I’d been looking for an excuse to try the Erlang http client, so I wrote a basic test to make lots of connections.<br />
Just because you can, doesn’t mean you should.. one process per connection would definitely be a waste here. I’m using one process to load urls from a file, and another process to establish and receive messages from all http connections (and one process as a timer to print a report every 10 seconds). All data received from the server is discarded, but it does increment a counter so we can keep track of how many HTTP chunks were delivered.</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=floodtest.erl">floodtest.erl</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">floodtest</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">timer</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">recv</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Filename</span><span style="color: Gray;">, </span><span style="color: Blue;">Wait</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">inets</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">spawn</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Blue;">timer</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Maroon;">10000</span><span style="color: Gray;">, </span><span style="color: Blue;">self</span><span style="color: Olive;">()])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">This</span><span style="color: Gray;"> = </span><span style="color: Blue;">self</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">spawn</span><span style="color: Olive;">(</span><span style="color: Green;">fun</span><span style="color: Olive;">()</span><span style="color: Gray;">-&gt; </span><span style="color: Blue;">loadurls</span><span style="color: Olive;">(</span><span style="color: Blue;">Filename</span><span style="color: Gray;">, </span><span style="color: Green;">fun</span><span style="color: Olive;">(</span><span style="color: Blue;">U</span><span style="color: Olive;">)</span><span style="color: Gray;">-&gt; </span><span style="color: Blue;">This</span><span style="color: Gray;"> ! {</span><span style="color: Blue;">loadurl</span><span style="color: Gray;">, </span><span style="color: Blue;">U</span><span style="color: Gray;">} </span><span style="color: Green;">end</span><span style="color: Gray;">, </span><span style="color: Blue;">Wait</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">end</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Blue;">Stats</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">Active</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">} = </span><span style="color: Blue;">Stats</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">stats</span><span style="color: Gray;">} -&gt; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Stats: ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">Stats</span><span style="color: Olive;">])</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">after</span><span style="color: Gray;">&nbsp;</span><span style="color: Maroon;">0</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">noop</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">http</span><span style="color: Gray;">,{</span><span style="color: Blue;">_Ref</span><span style="color: Gray;">,</span><span style="color: Blue;">stream_start</span><span style="color: Gray;">,</span><span style="color: Blue;">_X</span><span style="color: Gray;">}} -&gt;&nbsp; </span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Active</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span><span style="color: Blue;">Closed</span><span style="color: Gray;">,</span><span style="color: Blue;">Chunks</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">http</span><span style="color: Gray;">,{</span><span style="color: Blue;">_Ref</span><span style="color: Gray;">,</span><span style="color: Blue;">stream</span><span style="color: Gray;">,</span><span style="color: Blue;">_X</span><span style="color: Gray;">}} -&gt;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Active</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">http</span><span style="color: Gray;">,{</span><span style="color: Blue;">_Ref</span><span style="color: Gray;">,</span><span style="color: Blue;">stream_end</span><span style="color: Gray;">,</span><span style="color: Blue;">_X</span><span style="color: Gray;">}} -&gt;&nbsp; </span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Active</span><span style="color: Gray;">-</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">http</span><span style="color: Gray;">,{</span><span style="color: Blue;">_Ref</span><span style="color: Gray;">,{</span><span style="color: Blue;">error</span><span style="color: Gray;">,</span><span style="color: Blue;">Why</span><span style="color: Gray;">}}} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Closed: ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">Why</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Active</span><span style="color: Gray;">-</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">loadurl</span><span style="color: Gray;">, </span><span style="color: Blue;">Url</span><span style="color: Gray;">} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">http</span><span style="color: Gray;">:</span><span style="color: Blue;">request</span><span style="color: Olive;">(</span><span style="color: Blue;">get</span><span style="color: Gray;">, {</span><span style="color: Blue;">Url</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">}, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Gray;">{</span><span style="color: Blue;">sync</span><span style="color: Gray;">, </span><span style="color: Blue;">false</span><span style="color: Gray;">}, {</span><span style="color: Blue;">stream</span><span style="color: Gray;">, </span><span style="color: Blue;">self</span><span style="color: Gray;">}, {</span><span style="color: Blue;">version</span><span style="color: Gray;">, </span><span style="color: Maroon;">1.1</span><span style="color: Gray;">}, {</span><span style="color: Blue;">body_format</span><span style="color: Gray;">, </span><span style="color: Blue;">binary</span><span style="color: Gray;">}</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Blue;">Stats</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">timer</span><span style="color: Olive;">(</span><span style="color: Blue;">T</span><span style="color: Gray;">, </span><span style="color: Blue;">Who</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">after</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">T</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Who</span><span style="color: Gray;"> ! {</span><span style="color: Blue;">stats</span><span style="color: Gray;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">timer</span><span style="color: Olive;">(</span><span style="color: Blue;">T</span><span style="color: Gray;">, </span><span style="color: Blue;">Who</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% Read lines from a file with a specified delay between lines:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line_in_file</span><span style="color: Olive;">(</span><span style="color: Blue;">Name</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">Mode</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum0</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">Device</span><span style="color: Gray;">} = </span><span style="color: Blue;">file</span><span style="color: Gray;">:</span><span style="color: Blue;">open</span><span style="color: Olive;">(</span><span style="color: Blue;">Name</span><span style="color: Gray;">, </span><span style="color: Blue;">Mode</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum0</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">get_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">eof</span><span style="color: Gray;">&nbsp; -&gt; </span><span style="color: Blue;">file</span><span style="color: Gray;">:</span><span style="color: Blue;">close</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Line</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">NewAccum</span><span style="color: Gray;"> = </span><span style="color: Blue;">Proc</span><span style="color: Olive;">(</span><span style="color: Blue;">Line</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">NewAccum</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">loadurls</span><span style="color: Olive;">(</span><span style="color: Blue;">Filename</span><span style="color: Gray;">, </span><span style="color: Blue;">Callback</span><span style="color: Gray;">, </span><span style="color: Blue;">Wait</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line_in_file</span><span style="color: Olive;">(</span><span style="color: Blue;">Filename</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">fun</span><span style="color: Olive;">(</span><span style="color: Blue;">Line</span><span style="color: Gray;">, </span><span style="color: Blue;">List</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Callback</span><span style="color: Olive;">(</span><span style="color: Blue;">string</span><span style="color: Gray;">:</span><span style="color: Blue;">strip</span><span style="color: Olive;">(</span><span style="color: Blue;">Line</span><span style="color: Gray;">, </span><span style="color: Blue;">right</span><span style="color: Gray;">, $\</span><span style="color: Blue;">n</span><span style="color: Olive;">))</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">after</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Wait</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">noop</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">List</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Blue;">read</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">.</span></li></ol></div>
<p>Each connection we make requires an ephemeral port, and thus a file descriptor, and by default this is limited to 1024. To avoid the Too many open files problem you’ll need to modify the ulimit for your shell. This can be changed in /etc/security/limits.conf, but requires a logout/login. For now you can just sudo and modify the current shell (su back to your non-priv’ed user after calling ulimit if you don’t want to run as root):</p>
<div class="hl-surround"><div class="hl-main">$ sudo bash<br /># ulimit -n 999999<br /># erl</div></div>
<p>You might as well increase the ephemeral port range to the maximum too:</p>
<div class="hl-surround"><div class="hl-main"># echo &quot;1024 65535&quot; &gt; /proc/sys/net/ipv4/ip_local_port_range</div></div>
<p>Generate a file of URLs to feed to the floodtest program:</p>
<div class="hl-surround"><div class="hl-main">( for i in `seq 1 10000`; do echo &quot;http://localhost:8000/test/$i&quot; ; done ) &gt; /tmp/mochi-urls.txt</div></div>
<p>From the erlang prompt you can now compile and launch floodtest.erl:</p>
<div class="hl-surround"><div class="hl-main">erl&gt; c(floodtest).<br />erl&gt; floodtest:start(&quot;/tmp/mochi-urls.txt&quot;, 100).</div></div>
<p>This will establish 10 new connections per second (ie, 1 connection every 100ms).</p>
<p>It will output stats in the form {Active, Closed, Chunks} where Active is the number of connections currently established, Closed is the number that were terminated for some reason, and Chunks is the number of chunks served by chunked transfer from mochiweb. Closed should stay on 0, and Chunks should be more than Active, because each active connection will receive multiple chunks (1 every 10 seconds).</p>
<p>The resident size of the mochiweb beam process with 10,000 active connections was 450MB &#8211; that’s 45KB per connection. CPU utilization on the machine was practically nothing, as expected.</p>
<p><strong>Assessment so far</strong></p>
<p>That was a reasonable first attempt. 45KB per-connection seems a bit high &#8211; I could probably cook something up in C using libevent that could do this with closer to 4.5KB per connection (just a guess, if anyone has experience please leave a comment). If you factor in the amount of code and time it took to do this in Erlang compared with C, I think the increased memory usage is more excusable.</p>
<p>In future posts I’ll cover building a message router (so we can uncomment lines 25 and 41-43 in mochiconntest_web.erl) and talk about some ways to reduce the overall memory usage. I’ll also share the results of testing with 100k and 1M connections.</p>
<p>update: 第二篇：</p>
<p><strong>A Million-user Comet Application with Mochiweb, Part 2</strong></p>
<p>In Part 1, we built a (somewhat useless) mochiweb comet application that sent clients a message every 10 seconds. We tuned the Linux kernel, and built a tool to establish a lot of connections in order to test performance and memory usage. We found that it took around 45KB per connection.</p>
<p>Part 2 is about turning the application into something useful, and saving memory:</p>
<ul>
<li> Implement a message router with a login/logout/send API</li>
<li> Update the mochiweb app to receive messages from the router</li>
<li> Setup a distributed erlang system so we can run the router on a different node/host to mochiweb</li>
<li> Write a tool to spam the router with lots of messages</li>
<li> Graph memory usage over 24hrs, and optimise the mochiweb app to save memory.</li>
</ul>
<p>This means we are decoupling the message sending logic from the mochiweb app. In tandem with the floodtest tool from part 1, we can benchmark a setup closer to a production scenario.</p>
<p><strong>Implementing the message router</strong></p>
<p>The router API is just 3 functions:</p>
<ul>
<li> login(Id, Pid) register a process (of pid Pid) to receive messages for Id</li>
<li> logout(Pid) to stop receiving messages</li>
<li> send(Id, Msg) sends the message Msg to any client logged in as Id</li>
</ul>
<p>Note that, by design, it is possible for one process to login with multiple different Ids.</p>
<p>This example router module uses 2 ets tables to store bidirectional mappings between Pids and Ids. (pid2id and id2pid in the #state record below.)</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=router.erl">router.erl</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">router</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">behaviour</span><span style="color: Olive;">(</span><span style="color: Blue;">gen_server</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start_link</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">init</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_call</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_cast</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_info</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">terminate</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">code_change</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">send</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">login</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">logout</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">define</span><span style="color: Olive;">(</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, </span><span style="color: Blue;">global</span><span style="color: Gray;">:</span><span style="color: Blue;">whereis_name</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Olive;">))</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% will hold bidirectional mapping between id &lt;–&gt; pid</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">state</span><span style="color: Gray;">, {</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, </span><span style="color: Blue;">id2pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start_link</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">start_link</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">global</span><span style="color: Gray;">, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">}, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% sends Msg to anyone logged in as Id</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">send</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">send</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">login</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">login</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">logout</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">logout</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%%</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">init</span><span style="color: Olive;">([])</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% set this so we can catch death of logged in pids:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">process_flag</span><span style="color: Olive;">(</span><span style="color: Blue;">trap_exit</span><span style="color: Gray;">, </span><span style="color: Blue;">true</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% use ets for routing tables</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, #</span><span style="color: Blue;">state</span><span style="color: Gray;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">pid2id</span><span style="color: Gray;"> = </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">new</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">bag</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">id2pid</span><span style="color: Gray;"> = </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">new</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">bag</span><span style="color: Olive;">])</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; }</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">login</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">insert</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, {</span><span style="color: Blue;">Pid</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">insert</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">id2pid</span><span style="color: Gray;">, {</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">link</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: #ffa500;">% tell us if they exit, so we can log them out</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">~w logged in as ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">Pid</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">reply</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">};</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">logout</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">unlink</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">PidRows</span><span style="color: Gray;"> = </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">lookup</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">PidRows</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[]</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">IdRows</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Gray;"> {</span><span style="color: Blue;">I</span><span style="color: Gray;">,</span><span style="color: Blue;">P</span><span style="color: Gray;">} || {</span><span style="color: Blue;">P</span><span style="color: Gray;">,</span><span style="color: Blue;">I</span><span style="color: Gray;">} &lt;- </span><span style="color: Blue;">PidRows</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: #ffa500;">% invert tuples</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% delete all pid-&gt;id entries</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">delete</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% and all id-&gt;pid</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">delete_object</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">id2pid</span><span style="color: Gray;">, </span><span style="color: Blue;">Obj</span><span style="color: Olive;">)</span><span style="color: Gray;"> || </span><span style="color: Blue;">Obj</span><span style="color: Gray;"> &lt;- </span><span style="color: Blue;">IdRows</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">pid ~w logged out</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">Pid</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">reply</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">};</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">send</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% get pids who are logged in as this Id</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Pids</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">P</span><span style="color: Gray;"> || { </span><span style="color: Blue;">_Id</span><span style="color: Gray;">, </span><span style="color: Blue;">P</span><span style="color: Gray;"> } &lt;- </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">lookup</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">id2pid</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% send Msg to them all</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">M</span><span style="color: Gray;"> = {</span><span style="color: Blue;">router_msg</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Pid</span><span style="color: Gray;"> ! </span><span style="color: Blue;">M</span><span style="color: Gray;"> || </span><span style="color: Blue;">Pid</span><span style="color: Gray;"> &lt;- </span><span style="color: Blue;">Pids</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">reply</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% handle death and cleanup of logged in processes</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_info</span><span style="color: Olive;">(</span><span style="color: Blue;">Info</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Info</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {‘</span><span style="color: Blue;">EXIT</span><span style="color: Gray;">’, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">, </span><span style="color: Blue;">_Why</span><span style="color: Gray;">} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% force logout:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">logout</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}, </span><span style="color: Blue;">blah</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Wtf</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Caught unhandled message: ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Wtf</span><span style="color: Olive;">])</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_cast</span><span style="color: Olive;">(</span><span style="color: Blue;">_Msg</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">terminate</span><span style="color: Olive;">(</span><span style="color: Blue;">_Reason</span><span style="color: Gray;">, </span><span style="color: Blue;">_State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">code_change</span><span style="color: Olive;">(</span><span style="color: Blue;">_OldVsn</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">, </span><span style="color: Blue;">_Extra</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li></ol></div>
<p><strong>Updating the mochiweb application</strong></p>
<p>Let’s assume a user is represented by an integer Id based on the URL they connect to mochiweb with, and use that id to register with the message router. Instead of blocking for 10 seconds then sending something, the mochiweb loop will block on receiving messages from the router, and send an HTTP chunk to the client for every message the router sends it:</p>
<ul>
<li> Client connects to mochiweb at http://localhost:8000/test/123</li>
<li> Mochiweb app registers the pid for that connection against the id ‘123′ with the message router</li>
<li> If you send a message to the router addressed to id ‘123′, it will be relayed to the correct mochiweb process, and appear in the browser for that user</li>
</ul>
<p>Here’s the updated version of mochiconntest_web.erl:</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=mochiconntest_web.erl.2">mochiconntest_web.erl.2</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">mochiconntest_web</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">stop</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">loop</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% External API</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">DocRoot</span><span style="color: Gray;">, </span><span style="color: Blue;">Options1</span><span style="color: Gray;">} = </span><span style="color: Blue;">get_option</span><span style="color: Olive;">(</span><span style="color: Blue;">docroot</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Loop</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">:</span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Gray;">, </span><span style="color: Blue;">DocRoot</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% we’ll set our maximum to 1 million connections. (default: 2048)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mochiweb_http</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">([</span><span style="color: Gray;">{</span><span style="color: Blue;">max</span><span style="color: Gray;">, </span><span style="color: Maroon;">1000000</span><span style="color: Gray;">}, {</span><span style="color: Blue;">name</span><span style="color: Gray;">, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">}, {</span><span style="color: Blue;">loop</span><span style="color: Gray;">, </span><span style="color: Blue;">Loop</span><span style="color: Gray;">} | </span><span style="color: Blue;">Options1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">stop</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mochiweb_http</span><span style="color: Gray;">:</span><span style="color: Blue;">stop</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Gray;">, </span><span style="color: Blue;">DocRoot</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">Path</span><span style="color: Gray;"> = </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">get</span><span style="color: Olive;">(</span><span style="color: Blue;">path</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">get</span><span style="color: Olive;">(</span><span style="color: Blue;">method</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Method</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">Method</span><span style="color: Gray;"> =:= ‘</span><span style="color: Blue;">GET</span><span style="color: Gray;">’; </span><span style="color: Blue;">Method</span><span style="color: Gray;"> =:= ‘</span><span style="color: Blue;">HEAD</span><span style="color: Gray;">’ -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Path</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">test/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">Id</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Response</span><span style="color: Gray;"> = </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">ok</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">text/html; charset=utf-8</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">{</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Server</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Mochiweb-Test</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">}</span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">chunked</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% login using an integer rather than a string</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">IdInt</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">} = </span><span style="color: Blue;">string</span><span style="color: Gray;">:</span><span style="color: Blue;">to_integer</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">router</span><span style="color: Gray;">:</span><span style="color: Blue;">login</span><span style="color: Olive;">(</span><span style="color: Blue;">IdInt</span><span style="color: Gray;">, </span><span style="color: Blue;">self</span><span style="color: Olive;">())</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">feed</span><span style="color: Olive;">(</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">IdInt</span><span style="color: Gray;">, </span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">not_found</span><span style="color: Olive;">()</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ‘</span><span style="color: Blue;">POST</span><span style="color: Gray;">’ -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Path</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">not_found</span><span style="color: Olive;">()</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">respond</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Maroon;">501</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">feed</span><span style="color: Olive;">(</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">router_msg</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Html</span><span style="color: Gray;"> = </span><span style="color: Blue;">io_lib</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Recvd msg #~w: ‘~s’</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Response</span><span style="color: Gray;">:</span><span style="color: Blue;">write_chunk</span><span style="color: Olive;">(</span><span style="color: Blue;">Html</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">feed</span><span style="color: Olive;">(</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% Internal API</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">get_option</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">proplists</span><span style="color: Gray;">:</span><span style="color: Blue;">get_value</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: Blue;">proplists</span><span style="color: Gray;">:</span><span style="color: Blue;">delete</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">}.</span></li></ol></div>
<p><strong>It’s Alive!</strong></p>
<p>Now let’s bring it to life &#8211; we’ll use 2 erlang shells, one for mochiweb and one for the router. Edit start-dev.sh, used to start mochiweb, and add the following additional parameters to erl:</p>
<ul>
<li> -sname n1 to name the erlang node ‘n1′</li>
<li> +K true to enable kernel-poll. Seems daft not to when dealing with lots of connections</li>
<li> +P 134217727 the default maximum number of processes you can spawn is 32768. Considering we need one process per connection (and I don’t know of any good reason not to) I suggest just setting this to the maximum possible value. 134,217,727 is the max according to “man erl”.</li>
</ul>
<p>Now run <code> make &#038;&#038; ./start-dev.sh </code> and you should see a prompt like this: <code> (n1@localhost)1> </code> &#8211; your mochiweb app is now running and the erlang node has a name.</p>
<p>Now run another erlang shell like so:</p>
<div class="hl-surround"><div class="hl-main">erl -sname n2</div></div>
<p>Currently those two erlang instances don’t know about each other, fix that:</p>
<div class="hl-surround"><div class="hl-main">(n2@localhost)1&gt; nodes().<br />[]<br />(n2@localhost)2&gt; net_adm:ping(n1@localhost).<br />pong<br />(n2@localhost)3&gt; nodes().<br />[n1@localhost]</div></div>
<p>Now compile and start the router from this shell:</p>
<div class="hl-surround"><div class="hl-main">(n2@localhost)4&gt; c(router).<br />{ok,router}<br />(n2@localhost)5&gt; router:start_link().<br />{ok,&lt;0.38.0&gt;}</div></div>
<p>Now for the fun bit, go to http://localhost:8000/test/123 in your browser (or use lynx &#8211;source &#8220;http://localhost:8000/test/123&#8243; from the console). Check the shell you launched the router in, you should see it logged in one user.</p>
<p>You can now send messages to the router and watch them appear in your browser. Only send strings for now, because we are using ~s to format them with io_lib:format in the feed function, and atoms will crash it:</p>
<p>Just borrow the shell you used to launch the router:</p>
<div class="hl-surround"><div class="hl-main">(n2@localhost)6&gt; router:send(123, &quot;Hello World&quot;).<br />(n2@localhost)7&gt; router:send(123, &quot;Why not open another browser window too?&quot;).<br />(n2@localhost)8&gt; router:send(456, &quot;This message will go into the void unless you are connected as /test/456 too&quot;).</div></div>
<p>Check your browser, you’ve got comet <img src='http://erlang-china.org/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p><strong>Running in a distributed erlang system</strong></p>
<p>It makes sense to run the router and mochiweb front-end(s) on different machines. Assuming you have a couple of spare machines to test this on, you should start the erlang shells as distributed nodes, i.e. use -name n1@host1.example.com instead of -sname n1 (and the same for n2). Make sure they can see each other by using net_adm:ping(&#8230;) as above.</p>
<p>Note that on line 16 of router.erl, the name of the router process (’router’) is registered globally, and that because we are using the following macro to identify/locate the router in calls to gen_server, it will already work fine in a distributed system:</p>
<div class="hl-surround"><div class="hl-main">-define(SERVER, global:whereis_name(?MODULE)).</div></div>
<p>A global name registry for processes in a distributed system is just one of the things you get for free with Erlang.</p>
<p><strong>Generating lots of messages</strong></p>
<p>In a real environment we might see a long-tail like usage pattern, with some very active users and many infrequent users. However for this test we’ll just indiscriminately spam random users with fake messages.</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=msggen.erl">msggen.erl</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">msggen</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">ok</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Num</span><span style="color: Gray;">, </span><span style="color: Blue;">Interval</span><span style="color: Gray;">, </span><span style="color: Blue;">Max</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Id</span><span style="color: Gray;"> = </span><span style="color: Blue;">random</span><span style="color: Gray;">:</span><span style="color: Blue;">uniform</span><span style="color: Olive;">(</span><span style="color: Blue;">Max</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">router</span><span style="color: Gray;">:</span><span style="color: Blue;">send</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Fake message Num = </span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">Num</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">after</span><span style="color: Gray;"> </span><span style="color: Blue;">Interval</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Num</span><span style="color: Gray;"> -</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Interval</span><span style="color: Gray;">, </span><span style="color: Blue;">Max</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li></ol></div>
<p>This will send Num messages to random user Ids between 1 and Max, waiting Interval ms between each send.</p>
<p>You can see this in action if you run the router and the mochiweb app, connect with your browser to http://localhost:8000/test/3 then run:</p>
<div class="hl-surround"><div class="hl-main">erl -sname test<br />(test@localhost)1&gt; net_adm:ping(n1@localhost).<br />pong<br />(test@localhost)2&gt; c(msggen).<br />{ok,msggen}<br />(test@localhost)3&gt; msggen:start(20, 10, 5).<br />ok</div></div>
<p>This will send 20 messages to random Ids between 1-5, with a 10ms wait between messages. Chances are Id 3 will receive a message or four.</p>
<p>We can even run a few of these in parallel to simulate multiple sources for messages. Here’s an example of spawning 10 processes that each send 20 messages to ids 1-5 with a 100ms delay between each message:</p>
<div class="hl-surround"><div class="hl-main">[ spawn(fun() -&gt; msggen:start(20, 100, 5), io:format(&quot;~w finished.\n&quot;, [self()]) end) || _ &lt;- lists:seq(1,10) ].<br />[&lt;0.97.0&gt;,&lt;0.98.0&gt;,&lt;0.99.0&gt;,&lt;0.100.0&gt;,&lt;0.101.0&gt;,&lt;0.102.0&gt;,<br />&lt;0.103.0&gt;,&lt;0.104.0&gt;,&lt;0.105.0&gt;,&lt;0.106.0&gt;]<br />&lt;0.101.0&gt; finished.<br />&lt;0.105.0&gt; finished.<br />&lt;0.106.0&gt; finished.<br />&lt;0.104.0&gt; finished.<br />&lt;0.102.0&gt; finished.<br />&lt;0.98.0&gt; finished.<br />&lt;0.99.0&gt; finished.<br />&lt;0.100.0&gt; finished.<br />&lt;0.103.0&gt; finished.<br />&lt;0.97.0&gt; finished.</div></div>
<p><strong>C10K again, with feeling</strong></p>
<p>We have the pieces we need to run another larger-scale test now; clients connect to our mochiweb app, which registers them with the message router. We can generate a high volume of fake messages to fire at the router, which will send them to any registered clients. Let’s run the 10,000 concurrent-user test again from Part 1, but this time we’ll leave all the clients connected for a while while we blast lots of messages through the system.</p>
<p>Assuming you followed the instructions in Part 1 to tune your kernel and increase your max files ulimit etc, this should be easy. You already have the mochiweb app and router running, so let’s dump more traffic on it.</p>
<p>Without any clients connected, the mochiweb beam process uses around 40MB (resident):</p>
<div class="hl-surround"><div class="hl-main">$ ps -o rss= -p `pgrep -f 'sname n1'`<br />40156</div></div>
<p>This greps for the process ID of the command with ’sname n1′ in it, which is our mochiweb erlang process, then uses some formatting options to ps to print the RSS value &#8211; the resident memory size (KB)</p>
<p>I concocted this hideous one-liner to print the timestamp (human readable and a unixtime in case we need it later), current memory usage of mochiweb (resident KB), and the number of currently established connections every 60 seconds &#8211; leave this running on the mochiweb machine in a spare terminal:</p>
<div class="hl-surround"><div class="hl-main">$ MOCHIPID=`pgrep -f 'name n1'`; while [ 1 ] ; do NUMCON=`netstat -n | awk ‘/ESTABLISHED/ &amp;&amp; $4==”127.0.0.1:8000″‘ | wc -l`; MEM=`ps -o rss= -p $MOCHIPID`; echo -e “`date`\t`date +%s`\t$MEM\t$NUMCON”; sleep 60; done | tee -a mochimem.log</div></div>
<p>If anyone knows a better way to plot memory usage for a single process over time please leave a comment..<br />
Now launch the floodtest tool from Part 1 in a new erl shell:</p>
<div class="hl-surround"><div class="hl-main">erl&gt; floodtest:start(&quot;/tmp/mochi-urls.txt&quot;, 10).</div></div>
<p>This will establish 100 new connections per second until all 10,000 clients are connected.<br />
You’ll see it quickly reaches 10k connections:</p>
<div class="hl-surround"><div class="hl-main">erl&gt; floodtest:start(&quot;/tmp/mochi-urls.txt&quot;, 10).<br />Stats: {825,0,0}<br />Stats: {1629,0,0}<br />Stats: {2397,0,0}<br />Stats: {3218,0,0}<br />Stats: {4057,0,0}<br />Stats: {4837,0,0}<br />Stats: {5565,0,0}<br />Stats: {6295,0,0}<br />Stats: {7022,0,0}<br />Stats: {7727,0,0}<br />Stats: {8415,0,0}<br />Stats: {9116,0,0}<br />Stats: {9792,0,0}<br />Stats: {10000,0,0}<br />...</div></div>
<p>Check the hideous memory usage one-liner output:</p>
<div class="hl-surround"><div class="hl-main">Mon Oct 20 16:57:24 BST 2008 1224518244 40388 1<br />Mon Oct 20 16:58:25 BST 2008 1224518305 41120 263<br />Mon Oct 20 16:59:27 BST 2008 1224518367 65252 5267<br />Mon Oct 20 17:00:32 BST 2008 1224518432 89008 9836<br />Mon Oct 20 17:01:37 BST 2008 1224518497 90748 10001<br />Mon Oct 20 17:02:41 BST 2008 1224518561 90964 10001<br />Mon Oct 20 17:03:46 BST 2008 1224518626 90964 10001<br />Mon Oct 20 17:04:51 BST 2008 1224518691 90964 10001</div></div>
<p>It reached 10k concurrent connections (plus one I had open in firefox) and the resident memory size of mochiweb is around 90MB (90964KB).</p>
<p>Now unleash some messages:</p>
<div class="hl-surround"><div class="hl-main">erl&gt; [ spawn(fun() -&gt; msggen:start(1000000, 100, 10000) end) || _ &lt;- lists:seq(1,100) ].<br />[&lt;0.65.0&gt;,&lt;0.66.0&gt;,&lt;0.67.0&gt;,&lt;0.68.0&gt;,&lt;0.69.0&gt;,&lt;0.70.0&gt;,<br />&lt;0.71.0&gt;,&lt;0.72.0&gt;,&lt;0.73.0&gt;,&lt;0.74.0&gt;,&lt;0.75.0&gt;,&lt;0.76.0&gt;,<br />&lt;0.77.0&gt;,&lt;0.78.0&gt;,&lt;0.79.0&gt;,&lt;0.80.0&gt;,&lt;0.81.0&gt;,&lt;0.82.0&gt;,<br />&lt;0.83.0&gt;,&lt;0.84.0&gt;,&lt;0.85.0&gt;,&lt;0.86.0&gt;,&lt;0.87.0&gt;,&lt;0.88.0&gt;,<br />&lt;0.89.0&gt;,&lt;0.90.0&gt;,&lt;0.91.0&gt;,&lt;0.92.0&gt;,&lt;0.93.0&gt;|...]</div></div>
<p>That’s 100 processes each sending a million messages at a rate of 10 messages a second to random Ids from 1 to 10,000. That means the router is seeing 1000 messages per second, and on average each of our 10k clients will get one message every 10 seconds.</p>
<p>Check the output in the floodtest shell, and you’ll see clients are receiving http chunks (remember it was {NumConnected, NumClosed, NumChunksRecvd}):</p>
<div class="hl-surround"><div class="hl-main">...<br />Stats: {10000,0,5912}<br />Stats: {10000,0,15496}<br />Stats: {10000,0,25145}<br />Stats: {10000,0,34755}<br />Stats: {10000,0,44342}<br />...</div></div>
<p>A million messages at a rate of 10 per second per process will take 27 hours to complete. Here’s how the memory usage looks after just 10 mins:</p>
<div class="hl-surround"><div class="hl-main">Mon Oct 20 16:57:24 BST 2008 1224518244 40388 1<br />Mon Oct 20 16:58:25 BST 2008 1224518305 41120 263<br />Mon Oct 20 16:59:27 BST 2008 1224518367 65252 5267<br />Mon Oct 20 17:00:32 BST 2008 1224518432 89008 9836<br />Mon Oct 20 17:01:37 BST 2008 1224518497 90748 10001<br />Mon Oct 20 17:02:41 BST 2008 1224518561 90964 10001<br />Mon Oct 20 17:03:46 BST 2008 1224518626 90964 10001<br />Mon Oct 20 17:04:51 BST 2008 1224518691 90964 10001<br />Mon Oct 20 17:05:55 BST 2008 1224518755 90980 10001<br />Mon Oct 20 17:07:00 BST 2008 1224518820 91120 10001<br />Mon Oct 20 17:08:05 BST 2008 1224518885 98664 10001<br />Mon Oct 20 17:09:10 BST 2008 1224518950 106752 10001<br />Mon Oct 20 17:10:15 BST 2008 1224519015 114044 10001<br />Mon Oct 20 17:11:20 BST 2008 1224519080 119468 10001<br />Mon Oct 20 17:12:25 BST 2008 1224519145 125360 10001</div></div>
<p>You can see the size already crept up from 40MB to 90MB when all 10k clients were connected, and to 125MB after running a bit longer.</p>
<p>It’s worth pointing out that the floodtest shell is almost CPU-bound, the msggen shell is using 2% CPU and the router and mochiweb less than 1%. (ie, only simulating lots of clients is using much CPU &#8211; the server app itself is very light on the CPU). It helps to have multiple machines, or a multicore CPU for testing.</p>
<p><strong>Results after running for 24 hours</strong></p>
<p>I ran this for 24 hours, whilst logging memory usage of the mochiweb process to mochimem.log. This is with 10,000 connected clients, and 1000 messages per second being sent to random clients.</p>
<p>The following bit of bash/awk was used to trick gnuplot into turning the mochimem.log file into a graph:</p>
<div class="hl-surround"><div class="hl-main">(echo -e &quot;set terminal png size 500,300\nset xlabel \&quot;Minutes Elapsed\&quot;\nset ylabel \&quot;Mem (KB)\&quot;\nset title \&quot;Mem usage with 10k active connections, 1000 msg/sec\&quot;\nplot \&quot;-\&quot; using 1:2 with lines notitle&quot; ; awk 'BEGIN{FS=&quot;\t&quot;;} NR%10==0 {if(!t){t=$2} mins=($2-t)/60; printf(&quot;%d %d\n&quot;,mins,$3)}' mochimem.log ; echo -e &quot;end&quot; ) | gnuplot &gt; mochimem.png</div></div>
<p><img src="http://www.metabrew.com/wp-content/uploads/2008/10/mochimem.png" alt="Graph of memory usage with c10k, 1000msg/sec, 24hrs" /><br />
Memory usage with c10k, 1000msg/sec, 24hrs</p>
<p>This graph shows the memory usage (with 10k active connections and 1000 msgs/sec) levels off at around 250MB over a 24 hour period. The two big drops, once near the start and once at the end of the test, are when I ran this in the mochiweb erlang process, just out of curiosity:</p>
<div class="hl-surround"><div class="hl-main">erl&gt; [erlang:garbage_collect(P) || P &lt;- erlang:processes()].</div></div>
<p>This forces all processes to garbage collect, and reclaimed around 100MB of memory &#8211; next up we investigate ways to save memory without resorting to manually forcing garbage collection.</p>
<p><strong>Reducing memory usage in mochiweb</strong></p>
<p>Seeing as the mochiweb app is just sending messages and then immediately forgetting them, the memory usage shouldn’t need to increase with the number of messages sent.</p>
<p>I’m a novice when it comes to Erlang memory management, but I’m going to assume that if I can force it to garbage collect more often, it will allow us to reclaim much of that memory, and ultimately let us serve more users with less overall system memory. We might burn a bit more CPU in the process, but that’s an acceptable trade-off.</p>
<p>Digging around in the erlang docs yields this option:</p>
<p>erlang:system_flag(fullsweep_after, Number)</p>
<blockquote><p>
Number is a non-negative integer which indicates how many times generational garbages collections can be done without forcing a fullsweep collection. The value applies to new processes; processes already running are not affected.<br />
In low-memory systems (especially without virtual memory), setting the value to 0 can help to conserve memory.<br />
An alternative way to set this value is through the (operating system) environment variable ERL_FULLSWEEP_AFTER.
</p></blockquote>
<p>Sounds intriguing, but it only applies to new processes and would affect all processes in the VM, not just our mochiweb processes.</p>
<p>Next up is this:</p>
<p>erlang:system_flag(min_heap_size, MinHeapSize)</p>
<blockquote><p>
Sets the default minimum heap size for processes. The size is given in words. The new min_heap_size only effects processes spawned after the change of min_heap_size has been made. The min_heap_size can be set for individual processes by use of spawn_opt/N or process_flag/2.
</p></blockquote>
<p>Could be useful, but I’m pretty sure our mochiweb processes need a bigger heap than the default value anyway. I’d like to avoid needing to patch the mochiweb source to add spawn options if possible.</p>
<p>Next to catch my eye was this:</p>
<p>erlang:hibernate(Module, Function, Args)</p>
<blockquote><p>
Puts the calling process into a wait state where its memory allocation has been reduced as much as possible, which is useful if the process does not expect to receive any messages in the near future.</p>
<p>The process will be awaken when a message is sent to it, and control will resume in Module:Function with the arguments given by Args with the call stack emptied, meaning that the process will terminate when that function returns. Thus erlang:hibernate/3 will never return to its caller.</p>
<p>If the process has any message in its message queue, the process will be awaken immediately in the same way as described above.</p>
<p>In more technical terms, what erlang:hibernate/3 does is the following. It discards the call stack for the process. Then it garbage collects the process. After the garbage collection, all live data is in one continuous heap. The heap is then shrunken to the exact same size as the live data which it holds (even if that size is less than the minimum heap size for the process).</p>
<p>If the size of the live data in the process is less than the minimum heap size, the first garbage collection occurring after the process has been awaken will ensure that the heap size is changed to a size not smaller than the minimum heap size.</p>
<p>Note that emptying the call stack means that any surrounding catch is removed and has to be re-inserted after hibernation. One effect of this is that processes started using proc_lib (also indirectly, such as gen_server processes), should use proc_lib:hibernate/3 instead to ensure that the exception handler continues to work when the process wakes up.
</p></blockquote>
<p>This sounds reasonable &#8211; let’s try hibernating after every message and see what happens.</p>
<p>Edit mochiconntest_web.erl and change the following:</p>
<ul>
<li> Make the last line of the feed(Response, Id, N) function call hibernate instead of calling itself</li>
<li> Call hibernate immediately after logging into the router, rather than calling feed and blocking on receive</li>
<li> Remember to export feed/3 so hibernate can call back into the function on wake-up</li>
</ul>
<p>Updated mochiconntest_web.erl with hibernation between messages:</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=mochiconntest_web.erl.3">mochiconntest_web.erl.3</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">mochiconntest_web</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">stop</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Gray;">, </span><span style="color: Blue;">loop</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">feed</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% External API</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">DocRoot</span><span style="color: Gray;">, </span><span style="color: Blue;">Options1</span><span style="color: Gray;">} = </span><span style="color: Blue;">get_option</span><span style="color: Olive;">(</span><span style="color: Blue;">docroot</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Loop</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">:</span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Gray;">, </span><span style="color: Blue;">DocRoot</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% we’ll set our maximum to 1 million connections. (default: 2048)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mochiweb_http</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">([</span><span style="color: Gray;">{</span><span style="color: Blue;">max</span><span style="color: Gray;">, </span><span style="color: Maroon;">1000000</span><span style="color: Gray;">}, {</span><span style="color: Blue;">name</span><span style="color: Gray;">, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">}, {</span><span style="color: Blue;">loop</span><span style="color: Gray;">, </span><span style="color: Blue;">Loop</span><span style="color: Gray;">} | </span><span style="color: Blue;">Options1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">stop</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mochiweb_http</span><span style="color: Gray;">:</span><span style="color: Blue;">stop</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">loop</span><span style="color: Olive;">(</span><span style="color: Blue;">Req</span><span style="color: Gray;">, </span><span style="color: Blue;">DocRoot</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">Path</span><span style="color: Gray;"> = </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">get</span><span style="color: Olive;">(</span><span style="color: Blue;">path</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">get</span><span style="color: Olive;">(</span><span style="color: Blue;">method</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Method</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">Method</span><span style="color: Gray;"> =:= ‘</span><span style="color: Blue;">GET</span><span style="color: Gray;">’; </span><span style="color: Blue;">Method</span><span style="color: Gray;"> =:= ‘</span><span style="color: Blue;">HEAD</span><span style="color: Gray;">’ -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Path</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">test/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> ++ </span><span style="color: Blue;">IdStr</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Response</span><span style="color: Gray;"> = </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">ok</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">text/html; charset=utf-8</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">{</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Server</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Mochiweb-Test</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">}</span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">chunked</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">} = </span><span style="color: Blue;">string</span><span style="color: Gray;">:</span><span style="color: Blue;">to_integer</span><span style="color: Olive;">(</span><span style="color: Blue;">IdStr</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">router</span><span style="color: Gray;">:</span><span style="color: Blue;">login</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">self</span><span style="color: Olive;">())</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% Hibernate this process until it receives a message:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">proc_lib</span><span style="color: Gray;">:</span><span style="color: Blue;">hibernate</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Blue;">feed</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Maroon;">1</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">not_found</span><span style="color: Olive;">()</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ‘</span><span style="color: Blue;">POST</span><span style="color: Gray;">’ -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Path</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">not_found</span><span style="color: Olive;">()</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;">:</span><span style="color: Blue;">respond</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Maroon;">501</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">feed</span><span style="color: Olive;">(</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">router_msg</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Html</span><span style="color: Gray;"> = </span><span style="color: Blue;">io_lib</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Recvd msg #~w: ‘~w’&lt;br/&gt;</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">N</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Response</span><span style="color: Gray;">:</span><span style="color: Blue;">write_chunk</span><span style="color: Olive;">(</span><span style="color: Blue;">Html</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% Hibernate this process until it receives a message:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">proc_lib</span><span style="color: Gray;">:</span><span style="color: Blue;">hibernate</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Blue;">feed</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Response</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">N</span><span style="color: Gray;">+</span><span style="color: Maroon;">1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%% Internal API</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">get_option</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">proplists</span><span style="color: Gray;">:</span><span style="color: Blue;">get_value</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: Blue;">proplists</span><span style="color: Gray;">:</span><span style="color: Blue;">delete</span><span style="color: Olive;">(</span><span style="color: Blue;">Option</span><span style="color: Gray;">, </span><span style="color: Blue;">Options</span><span style="color: Olive;">)</span><span style="color: Gray;">}.</span></li></ol></div>
<p>I made these changes, ran make to rebuild mochiweb, then redid the same c10k test (1000msgs/sec for 24hrs).</p>
<p><strong>Results after running for 24 hours w/ proc_lib:hibernate()</strong></p>
<p><img src="http://www.metabrew.com/wp-content/uploads/2008/10/mochimem5.png" alt="Graph of memory usage with c10k, 1000msg/sec, 24hrs, using hibernate()" /><br />
Memory usage with c10k, 1000msg/sec, 24hrs, using hibernate()</p>
<p>Judicious use of hibernate means the mochiweb application memory levels out at 78MB Resident with 10k connections, much better than the 450MB we saw in Part 1. There was no significant increase in CPU usage.</p>
<p><strong>Summary</strong></p>
<p>We made a comet application on Mochiweb that lets us push arbitrary messages to users identified by an integer ID. After pumping 1000 msgs/sec through it for 24 hours, with 10,000 connected users, we observed it using 80MB, or 8KB per user. We even made pretty graphs.</p>
<p>This is quite an improvement from the 45KB per used we saw in Part 1. The savings are attributed to making the application behave in a more realistic way, and use of hibernate for mochiweb processes between messages.</p>
<p><strong>Next Steps</strong></p>
<p>In Part 3 (coming soon), I’ll <strong>turn it up to 1 million</strong> connected clients. I will be deploying the test app on a multi-cpu 64-bit server with plenty of RAM. This will show what difference, if any, running on a 64-bit VM makes. I’ll also detail some additional tricks and tuning needed in order to simulate 1 million client connections.</p>
<p>The application will evolve into a sort of pub-sub system, where subscriptions are associated to user Ids and stored by the app, rather than provided by clients when they connect. We’ll load in a typical social-network dataset: friends. This will allow a user to login with their user Id and automatically receive any event generated by one of their friends.</p>
<p><strong>A Million-user Comet Application with Mochiweb, Part 3</strong></p>
<p>Part 1 and Part 2 in this series showed how to build a comet application using mochiweb, and how to route messages to connected users. We managed to squeeze application memory down to 8KB per connection. We did ye olde c10k test, and observed what happened with 10,000 connected users. We made graphs. It was fun, but now it’s time to make good on the claims made in the title, and turn it up to 1 million connections.</p>
<p>This post covers the following:</p>
<ul>
<li>Add a pubsub-like subscription database using Mnesia</li>
<li>Generate a realistic friends dataset for a million users</li>
<li>Tune mnesia and bulk load in our friends data</li>
<li>Opening a million connections from one machine</li>
<li>Benchmark with 1 Million connected users</li>
<li>Libevent + C for connection handling</li>
<li>Final thoughts</li>
</ul>
<p>One of the challenging parts of this test was actually being able to open 1M connections from a single test machine. Writing a server to accept 1M connections is easier than actually creating 1M connections to test it with, so a fair amount of this article is about the techniques used to open 1M connections from a single machine.<br />
Getting our pubsub on</p>
<p>In Part 2 we used the router to send messages to specific users. This is fine for a chat/IM system, but that there are sexier things we could do instead. Before we launch into a large-scale test, let’s add one more module &#8211; a subscription database. We want the application store who your friends are, so it can push you all events generated by people on your friends list.</p>
<p>My intention is to use this for Last.fm so I can get a realtime feed of songs my friends are currently listening to. It could equally apply to other events generated on social networks. Flickr photo uploads, Facebook newsfeed items, Twitter messages etc. FriendFeed even have a realtime API in beta, so this kind of thing is definitely topical. (Although I’ve not heard of anyone except Facebook using Erlang for this kind of thing).</p>
<p><strong>Implementing the subscription-manager</strong></p>
<p>We’re implementing a general subscription manager, but we’ll be subscribing people to everyone on their friends list automatically &#8211; so you could also think of this as a friends database for now.</p>
<p>The subsmanager API:</p>
<ul>
<li>add_subscriptions([{Subscriber, Subscribee},...])</li>
<li>remove_subscriptions([{Subscriber, Subscribee},...])</li>
<li>get_subscribers(User)</li>
</ul>
<p>subsmanager.erl</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=submanager.erl">submanager.erl</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">subsmanager</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">behaviour</span><span style="color: Olive;">(</span><span style="color: Blue;">gen_server</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">include</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">/usr/local/lib/erlang/lib/stdlib-1.15.4/include/qlc.hrl</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">init</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_call</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_cast</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_info</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">terminate</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">code_change</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">add_subscriptions</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">remove_subscriptions</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">get_subscribers</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">first_run</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">stop</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">start_link</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">subscription</span><span style="color: Gray;">, {</span><span style="color: Blue;">subscriber</span><span style="color: Gray;">, </span><span style="color: Blue;">subscribee</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">state</span><span style="color: Gray;">, {}</span><span style="color: Olive;">)</span><span style="color: Gray;">. </span><span style="color: #ffa500;">% state is all in mnesia</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">define</span><span style="color: Olive;">(</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, </span><span style="color: Blue;">global</span><span style="color: Gray;">:</span><span style="color: Blue;">whereis_name</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Olive;">))</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start_link</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">start_link</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">global</span><span style="color: Gray;">, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">}, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">stop</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">stop</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">add_subscriptions</span><span style="color: Olive;">(</span><span style="color: Blue;">SubsList</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">add_subscriptions</span><span style="color: Gray;">, </span><span style="color: Blue;">SubsList</span><span style="color: Gray;">}, </span><span style="color: Blue;">infinity</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">remove_subscriptions</span><span style="color: Olive;">(</span><span style="color: Blue;">SubsList</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">remove_subscriptions</span><span style="color: Gray;">, </span><span style="color: Blue;">SubsList</span><span style="color: Gray;">}, </span><span style="color: Blue;">infinity</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">get_subscribers</span><span style="color: Olive;">(</span><span style="color: Blue;">User</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">get_subscribers</span><span style="color: Gray;">, </span><span style="color: Blue;">User</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%%</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">init</span><span style="color: Olive;">([])</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;"> = </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Waiting on mnesia tables..</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">wait_for_tables</span><span style="color: Olive;">([</span><span style="color: Blue;">subscription</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Maroon;">30000</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Info</span><span style="color: Gray;"> = </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">table_info</span><span style="color: Olive;">(</span><span style="color: Blue;">subscription</span><span style="color: Gray;">, </span><span style="color: Blue;">all</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">OK. Subscription table info: </span><span style="color: Navy;">\n</span><span style="color: Red;">~w</span><span style="color: Navy;">\n\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">Info</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, #</span><span style="color: Blue;">state</span><span style="color: Gray;">{}}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">stop</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">stop</span><span style="color: Gray;">, </span><span style="color: Blue;">stop</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">};</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">add_subscriptions</span><span style="color: Gray;">, </span><span style="color: Blue;">SubsList</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% Transactionally is slower:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% F = fun() -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; [ ok = mnesia:write(S) || S &lt;- SubsList ]</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%&nbsp; &nbsp;&nbsp; end,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% mnesia:transaction(F),</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">dirty_write</span><span style="color: Olive;">(</span><span style="color: Blue;">S</span><span style="color: Olive;">)</span><span style="color: Gray;"> || </span><span style="color: Blue;">S</span><span style="color: Gray;"> &lt;- </span><span style="color: Blue;">SubsList</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">reply</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">};</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">remove_subscriptions</span><span style="color: Gray;">, </span><span style="color: Blue;">SubsList</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">F</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">ok</span><span style="color: Gray;"> = </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">delete_object</span><span style="color: Olive;">(</span><span style="color: Blue;">S</span><span style="color: Olive;">)</span><span style="color: Gray;"> || </span><span style="color: Blue;">S</span><span style="color: Gray;"> &lt;- </span><span style="color: Blue;">SubsList</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">transaction</span><span style="color: Olive;">(</span><span style="color: Blue;">F</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">reply</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">};</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">get_subscribers</span><span style="color: Gray;">, </span><span style="color: Blue;">User</span><span style="color: Gray;">}, </span><span style="color: Blue;">From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">F</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Subs</span><span style="color: Gray;"> = </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">dirty_match_object</span><span style="color: Olive;">(</span><span style="color: Gray;">#</span><span style="color: Blue;">subscription</span><span style="color: Gray;">{</span><span style="color: Blue;">subscriber</span><span style="color: Gray;">=‘</span><span style="color: Blue;">_</span><span style="color: Gray;">’, </span><span style="color: Blue;">subscribee</span><span style="color: Gray;">=</span><span style="color: Blue;">User</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Users</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Blue;">Dude</span><span style="color: Gray;"> || #</span><span style="color: Blue;">subscription</span><span style="color: Gray;">{</span><span style="color: Blue;">subscriber</span><span style="color: Gray;">=</span><span style="color: Blue;">Dude</span><span style="color: Gray;">, </span><span style="color: Blue;">subscribee</span><span style="color: Gray;">=</span><span style="color: Blue;">_</span><span style="color: Gray;">} &lt;- </span><span style="color: Blue;">Subs</span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">reply</span><span style="color: Olive;">(</span><span style="color: Blue;">From</span><span style="color: Gray;">, </span><span style="color: Blue;">Users</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">spawn</span><span style="color: Olive;">(</span><span style="color: Blue;">F</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_cast</span><span style="color: Olive;">(</span><span style="color: Blue;">_Msg</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_info</span><span style="color: Olive;">(</span><span style="color: Blue;">_Msg</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">terminate</span><span style="color: Olive;">(</span><span style="color: Blue;">_Reason</span><span style="color: Gray;">, </span><span style="color: Blue;">_State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">stop</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">code_change</span><span style="color: Olive;">(</span><span style="color: Blue;">_OldVersion</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">, </span><span style="color: Blue;">_Extra</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Reloading code for ?MODULE</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%%</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">first_run</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">create_schema</span><span style="color: Olive;">([</span><span style="color: Blue;">node</span><span style="color: Olive;">()])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;"> = </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">start</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Ret</span><span style="color: Gray;"> = </span><span style="color: Blue;">mnesia</span><span style="color: Gray;">:</span><span style="color: Blue;">create_table</span><span style="color: Olive;">(</span><span style="color: Blue;">subscription</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; {</span><span style="color: Blue;">disc_copies</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">node</span><span style="color: Olive;">()]</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; {</span><span style="color: Blue;">attributes</span><span style="color: Gray;">, </span><span style="color: Blue;">record_info</span><span style="color: Olive;">(</span><span style="color: Blue;">fields</span><span style="color: Gray;">, </span><span style="color: Blue;">subscription</span><span style="color: Olive;">)</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; {</span><span style="color: Blue;">index</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">subscribee</span><span style="color: Olive;">]</span><span style="color: Gray;">}, </span><span style="color: #ffa500;">%index subscribee too</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; {</span><span style="color: Blue;">type</span><span style="color: Gray;">, </span><span style="color: Blue;">bag</span><span style="color: Gray;">}</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Ret</span><span style="color: Gray;">.</span></li></ol></div>
<p>Noteworthy points:</p>
<ul>
<li>I’ve included qlc.hrl, needed for mnesia queries using list comprehension, using an absolute path. That can’t be best practice, it wasn’t finding it otherwise though.</li>
<li>get_subscribers spawns another process and delegates the job of replying to that process, using gen_server:reply. This means the gen_server loop won’t block on that call if we throw lots of lookups at it and mnesia slows down.</li>
<li>rr(”subsmanager.erl”). in the example below allows you to use record definitions in the erl shell. Putting your record definitions into a records.hrl file and including that in your modules is considered better style. I inlined it for brevity.</li>
</ul>
<p>Now to test it. first_run() creates the mnesia schema, so it’s important to run that first. Another potential gotcha with mnesia is that (by default) the database can only be accessed by the node that created it, so give the erl shell a name, and stick with it.</p>
<div class="hl-surround"><div class="hl-main">$ mkdir /var/mnesia<br />$ erl -boot start_sasl -mnesia dir '&quot;/var/mnesia_data&quot;' -sname subsman<br />(subsman@localhost)1&gt; c(subsmanager).<br />{ok,subsmanager}<br />(subsman@localhost)2&gt; subsmanager:first_run().<br />...<br />{atomic,ok}<br />(subsman@localhost)3&gt; subsmanager:start_link().<br />Waiting on mnesia tables..<br />OK. Subscription table info:<br />[{access_mode,read_write},{active_replicas,[subsman@localhost]},{arity,3},{attributes,[subscriber,subscribee]},{checkpoints,[]},{commit_work,[{index,bag,[{3,{ram,57378}}]}]},{cookie,{{1224,800064,900003},subsman@localhost}},{cstruct,{cstruct,subscription,bag,[],[subsman@localhost],[],0,read_write,[3],[],false,subscription,[subscriber,subscribee],[],[],{{1224,863164,904753},subsman@localhost},{{2,0},[]}}},{disc_copies,[subsman@localhost]},{disc_only_copies,[]},{frag_properties,[]},{index,[3]},{load_by_force,false},{load_node,subsman@localhost},{load_order,0},{load_reason,{dumper,create_table}},{local_content,false},{master_nodes,[]},{memory,288},{ram_copies,[]},{record_name,subscription},{record_validation,{subscription,3,bag}},{type,bag},{size,0},{snmp,[]},{storage_type,disc_copies},{subscribers,[]},{user_properties,[]},{version,{{2,0},[]}},{where_to_commit,[{subsman@localhost,disc_copies}]},{where_to_read,subsman@localhost},{where_to_write,[subsman@localhost]},{wild_pattern,{subscription,’_',’_'}},{{index,3},57378}]<br /><br />{ok,&lt;0.105.0&gt;}<br />(subsman@localhost)4&gt; rr(&quot;subsmanager.erl&quot;).<br />[state,subscription]<br />(subsman@localhost)5&gt; subsmanager:add_subscriptions([ #subscription{subscriber=alice, subscribee=rj} ]).<br />ok<br />(subsman@localhost)6&gt; subsmanager:add_subscriptions([ #subscription{subscriber=bob, subscribee=rj} ]).<br />ok<br />(subsman@localhost)7&gt; subsmanager:get_subscribers(rj).<br />[bob,alice]<br />(subsman@localhost)8&gt; subsmanager:remove_subscriptions([ #subscription{subscriber=bob, subscribee=rj} ]).<br />ok<br />(subsman@localhost)8&gt; subsmanager:get_subscribers(rj).<br />[alice]<br />(subsman@localhost)10&gt; subsmanager:get_subscribers(charlie).<br />[]</div></div>
<p>We’ll use integer Ids to represent users for the benchmark &#8211; but for this test I used atoms (rj, alice, bob) and assumed that alice and bob are both on rj’s friends list. It’s nice that mnesia (and ets/dets) doesn’t care what values you use &#8211; any Erlang term is valid. This means it’s a simple upgrade to support multiple types of resource. You could start using {user, 123} or {photo, 789} to represent different things people might subscribe to, without changing anything in the subsmanager module.</p>
<p><strong>Modifying the router to use subscriptions</strong></p>
<p>Instead of addressing messages to specific users, ie router:send(123, &#8220;Hello user 123&#8243;), we’ll mark messages with a subject &#8211; that is, the person who generated the message (who played the song, who uploaded the photo etc) &#8211; and have the router deliver the message to every user who has subscribed to the subject user. In other words, the API will work like this: router:send(123, &#8220;Hello everyone subscribed to user 123&#8243;)</p>
<p>Updated router.erl:</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=router.erl.2">router.erl.2</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">router</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">behaviour</span><span style="color: Olive;">(</span><span style="color: Blue;">gen_server</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">start_link</span><span style="color: Gray;">/</span><span style="color: Maroon;">0</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">init</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_call</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_cast</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">handle_info</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: Blue;">terminate</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">code_change</span><span style="color: Gray;">/</span><span style="color: Maroon;">3</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">send</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">login</span><span style="color: Gray;">/</span><span style="color: Maroon;">2</span><span style="color: Gray;">, </span><span style="color: Blue;">logout</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">define</span><span style="color: Olive;">(</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, </span><span style="color: Blue;">global</span><span style="color: Gray;">:</span><span style="color: Blue;">whereis_name</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Olive;">))</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% will hold bidirectional mapping between id &lt;–&gt; pid</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">state</span><span style="color: Gray;">, {</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, </span><span style="color: Blue;">id2pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start_link</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">start_link</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">global</span><span style="color: Gray;">, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">}, ?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Olive;">[]</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% sends Msg to anyone subscribed to Id</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">send</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">send</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">login</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">login</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">logout</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">call</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVER</span><span style="color: Gray;">, {</span><span style="color: Blue;">logout</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%%</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">init</span><span style="color: Olive;">([])</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% set this so we can catch death of logged in pids:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">process_flag</span><span style="color: Olive;">(</span><span style="color: Blue;">trap_exit</span><span style="color: Gray;">, </span><span style="color: Blue;">true</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% use ets for routing tables</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, #</span><span style="color: Blue;">state</span><span style="color: Gray;">{</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">pid2id</span><span style="color: Gray;"> = </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">new</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">bag</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">id2pid</span><span style="color: Gray;"> = </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">new</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">bag</span><span style="color: Olive;">])</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; }</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">login</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">insert</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, {</span><span style="color: Blue;">Pid</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">insert</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">id2pid</span><span style="color: Gray;">, {</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">link</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: #ffa500;">% tell us if they exit, so we can log them out</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%io:format(&quot;~w logged in as ~w\n&quot;,[Pid, Id]),</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">reply</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">};</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">logout</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}, </span><span style="color: Blue;">_From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">is_pid</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">unlink</span><span style="color: Olive;">(</span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">PidRows</span><span style="color: Gray;"> = </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">lookup</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">PidRows</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[]</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">_</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">IdRows</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Gray;"> {</span><span style="color: Blue;">I</span><span style="color: Gray;">,</span><span style="color: Blue;">P</span><span style="color: Gray;">} || {</span><span style="color: Blue;">P</span><span style="color: Gray;">,</span><span style="color: Blue;">I</span><span style="color: Gray;">} &lt;- </span><span style="color: Blue;">PidRows</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: #ffa500;">% invert tuples</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">delete</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">pid2id</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Olive;">)</span><span style="color: Gray;">,&nbsp;&nbsp; </span><span style="color: #ffa500;">% delete all pid-&gt;id entries</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">delete_object</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">id2pid</span><span style="color: Gray;">, </span><span style="color: Blue;">Obj</span><span style="color: Olive;">)</span><span style="color: Gray;"> || </span><span style="color: Blue;">Obj</span><span style="color: Gray;"> &lt;- </span><span style="color: Blue;">IdRows</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span><span style="color: Gray;"> </span><span style="color: #ffa500;">% and all id-&gt;pid</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">%io:format(&quot;pid ~w logged out\n&quot;,[Pid]),</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">reply</span><span style="color: Gray;">, </span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">};</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">send</span><span style="color: Gray;">, </span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">}, </span><span style="color: Blue;">From</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">F</span><span style="color: Gray;"> = </span><span style="color: Green;">fun</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% get users who are subscribed to Id:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Users</span><span style="color: Gray;"> = </span><span style="color: Blue;">subsmanager</span><span style="color: Gray;">:</span><span style="color: Blue;">get_subscribers</span><span style="color: Olive;">(</span><span style="color: Blue;">Id</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Subscribers of ~w = ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">Id</span><span style="color: Gray;">, </span><span style="color: Blue;">Users</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% get pids of anyone logged in from Users list:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Pids0</span><span style="color: Gray;"> = </span><span style="color: Blue;">lists</span><span style="color: Gray;">:</span><span style="color: Blue;">map</span><span style="color: Olive;">(</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">fun</span><span style="color: Olive;">(</span><span style="color: Blue;">U</span><span style="color: Olive;">)</span><span style="color: Gray;">-&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">P</span><span style="color: Gray;"> || { </span><span style="color: Blue;">_I</span><span style="color: Gray;">, </span><span style="color: Blue;">P</span><span style="color: Gray;"> } &lt;- </span><span style="color: Blue;">ets</span><span style="color: Gray;">:</span><span style="color: Blue;">lookup</span><span style="color: Olive;">(</span><span style="color: Blue;">State</span><span style="color: Gray;">#</span><span style="color: Blue;">state</span><span style="color: Gray;">.</span><span style="color: Blue;">id2pid</span><span style="color: Gray;">, </span><span style="color: Blue;">U</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Id</span><span style="color: Gray;"> | </span><span style="color: Blue;">Users</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span><span style="color: Gray;"> </span><span style="color: #ffa500;">% we are always subscribed to ourselves</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Pids</span><span style="color: Gray;"> = </span><span style="color: Blue;">lists</span><span style="color: Gray;">:</span><span style="color: Blue;">flatten</span><span style="color: Olive;">(</span><span style="color: Blue;">Pids0</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Pids: ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Pids</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% send Msg to them all</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">M</span><span style="color: Gray;"> = {</span><span style="color: Blue;">router_msg</span><span style="color: Gray;">, </span><span style="color: Blue;">Msg</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Pid</span><span style="color: Gray;"> ! </span><span style="color: Blue;">M</span><span style="color: Gray;"> || </span><span style="color: Blue;">Pid</span><span style="color: Gray;"> &lt;- </span><span style="color: Blue;">Pids</span><span style="color: Gray;"> </span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% respond with how many users saw the message</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">gen_server</span><span style="color: Gray;">:</span><span style="color: Blue;">reply</span><span style="color: Olive;">(</span><span style="color: Blue;">From</span><span style="color: Gray;">, {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">length</span><span style="color: Olive;">(</span><span style="color: Blue;">Pids</span><span style="color: Olive;">)</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">spawn</span><span style="color: Olive;">(</span><span style="color: Blue;">F</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% handle death and cleanup of logged in processes</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_info</span><span style="color: Olive;">(</span><span style="color: Blue;">Info</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">Info</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {‘</span><span style="color: Blue;">EXIT</span><span style="color: Gray;">’, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">, </span><span style="color: Blue;">_Why</span><span style="color: Gray;">} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_call</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">logout</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">}, </span><span style="color: Blue;">blah</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Wtf</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Caught unhandled message: ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Wtf</span><span style="color: Olive;">])</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">handle_cast</span><span style="color: Olive;">(</span><span style="color: Blue;">_Msg</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">noreply</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">terminate</span><span style="color: Olive;">(</span><span style="color: Blue;">_Reason</span><span style="color: Gray;">, </span><span style="color: Blue;">_State</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">code_change</span><span style="color: Olive;">(</span><span style="color: Blue;">_OldVsn</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">, </span><span style="color: Blue;">_Extra</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">State</span><span style="color: Gray;">}.</span></li></ol></div>
<p>And here’s a quick test that doesn’t require mochiweb &#8211; I’ve used atoms instead of user ids, and omitted some output for clarity:</p>
<div class="hl-surround"><div class="hl-main">(subsman@localhost)1&gt; c(subsmanager), c(router), rr(&quot;subsmanager.erl&quot;).<br />(subsman@localhost)2&gt; subsmanager:start_link().<br />(subsman@localhost)3&gt; router:start_link().<br />(subsman@localhost)4&gt; Subs = [#subscription{subscriber=alice, subscribee=rj}, #subscription{subscriber=bob, subscribee=rj}].<br />[#subscription{subscriber = alice,subscribee = rj},<br />#subscription{subscriber = bob,subscribee = rj}]<br />(subsman@localhost)5&gt; subsmanager:add_subscriptions(Subs).<br />ok<br />(subsman@localhost)6&gt; router:send(rj, “RJ did something”).<br />Subscribers of rj = [bob,alice]<br />Pids: []<br />{ok,0}<br />(subsman@localhost)7&gt; router:login(alice, self()).<br />ok<br />(subsman@localhost)8&gt; router:send(rj, “RJ did something”).<br />Subscribers of rj = [bob,alice]<br />Pids: [&lt;0.46.0&gt;]<br />{ok,1}<br />(subsman@localhost)9&gt; receive {router_msg, M} -&gt; io:format(”~s\n”,[M]) end.<br />RJ did something<br />ok</div></div>
<p>This shows how alice can a receive a message when the subject is someone she is subscribed to (rj), even though the message wasn’t sent directly to alice. The output shows that the router identified possible targets as [alice,bob] but only delivered the message to one person, alice, because bob was not logged in.</p>
<p><strong>Generating a typical social-network friends dataset</strong></p>
<p>We could generate lots of friend relationships at random, but that’s not particularly realistic. Social networks tend to exhibit a power law distribution. Social networks usually have a few super-popular users (<a href="http://twitter.com/barackobama" target=_blank>some Twitter users have over 100,000 followers</a>) and plenty of people with just a handful of friends. The Last.fm friends data is typical &#8211; it fits a <a href="http://en.wikipedia.org/wiki/Barab%C3%A1si-Albert_model" target=_blank>Barabási–Albert graph model</a>, so that’s what I’ll use.</p>
<p>To generate the dataset I’m using the python module from the excellent <a href="http://cneurocvs.rmki.kfki.hu/igraph/" target=_blank>igraph library</a>:</p>
<p>fakefriends.py:</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=fakefriends.py">fakefriends.py</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Green;">import</span><span style="color: Gray;"> </span><span style="color: Blue;">igraph</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">g</span><span style="color: Gray;"> = </span><span style="color: Blue;">igraph</span><span style="color: Gray;">.</span><span style="color: Blue;">Graph</span><span style="color: Gray;">.</span><span style="color: Blue;">Barabasi</span><span style="color: Olive;">(</span><span style="color: Maroon;">1000000</span><span style="color: Gray;">, </span><span style="color: Maroon;">15</span><span style="color: Gray;">, </span><span style="color: Blue;">directed</span><span style="color: Gray;">=</span><span style="color: Green;">False</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Green;">print</span><span style="color: Gray;">&nbsp;</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Edges: </span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> + </span><span style="color: Teal;">str</span><span style="color: Olive;">(</span><span style="color: Blue;">g</span><span style="color: Gray;">.</span><span style="color: Blue;">ecount</span><span style="color: Olive;">())</span><span style="color: Gray;"> + </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;"> Verticies: </span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;"> + </span><span style="color: Teal;">str</span><span style="color: Olive;">(</span><span style="color: Blue;">g</span><span style="color: Gray;">.</span><span style="color: Blue;">vcount</span><span style="color: Olive;">())</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">g</span><span style="color: Gray;">.</span><span style="color: Blue;">write_edgelist</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">fakefriends.txt</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span></li></ol></div>
<p>This will generate with 2 user ids per line, space separated. These are the friend relationships we’ll load into our subsmanager. User ids range from 1 to a million.</p>
<p><strong>Bulk loading friends data into mnesia</strong></p>
<p>This small module will read the fakefriends.txt file and create a list of subscription records.</p>
<p>readfriends.erl &#8211; to read the fakefriends.txt and create subscription records:</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=readfriends.erl">readfriends.erl</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">readfriends</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">export</span><span style="color: Olive;">([</span><span style="color: Blue;">load</span><span style="color: Gray;">/</span><span style="color: Maroon;">1</span><span style="color: Olive;">])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">record</span><span style="color: Olive;">(</span><span style="color: Blue;">subscription</span><span style="color: Gray;">, {</span><span style="color: Blue;">subscriber</span><span style="color: Gray;">, </span><span style="color: Blue;">subscribee</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">load</span><span style="color: Olive;">(</span><span style="color: Blue;">Filename</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line_in_file</span><span style="color: Olive;">(</span><span style="color: Blue;">Filename</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">fun</span><span style="color: Olive;">(</span><span style="color: Blue;">Line</span><span style="color: Gray;">, </span><span style="color: Blue;">Acc</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Blue;">As</span><span style="color: Gray;">, </span><span style="color: Blue;">Bs</span><span style="color: Olive;">]</span><span style="color: Gray;"> = </span><span style="color: Blue;">string</span><span style="color: Gray;">:</span><span style="color: Blue;">tokens</span><span style="color: Olive;">(</span><span style="color: Blue;">string</span><span style="color: Gray;">:</span><span style="color: Blue;">strip</span><span style="color: Olive;">(</span><span style="color: Blue;">Line</span><span style="color: Gray;">, </span><span style="color: Blue;">right</span><span style="color: Gray;">, $\</span><span style="color: Blue;">n</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">&nbsp;</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">A</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">} = </span><span style="color: Blue;">string</span><span style="color: Gray;">:</span><span style="color: Blue;">to_integer</span><span style="color: Olive;">(</span><span style="color: Blue;">As</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">B</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">} = </span><span style="color: Blue;">string</span><span style="color: Gray;">:</span><span style="color: Blue;">to_integer</span><span style="color: Olive;">(</span><span style="color: Blue;">Bs</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;"> #</span><span style="color: Blue;">subscription</span><span style="color: Gray;">{</span><span style="color: Blue;">subscriber</span><span style="color: Gray;">=</span><span style="color: Blue;">A</span><span style="color: Gray;">, </span><span style="color: Blue;">subscribee</span><span style="color: Gray;">=</span><span style="color: Blue;">B</span><span style="color: Gray;">} | </span><span style="color: Blue;">Acc</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">]</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">read</span><span style="color: Olive;">]</span><span style="color: Gray;">, </span><span style="color: Olive;">[])</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% via: http://www.trapexit.org/Reading_Lines_from_a_File</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line_in_file</span><span style="color: Olive;">(</span><span style="color: Blue;">Name</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">Mode</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum0</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">Device</span><span style="color: Gray;">} = </span><span style="color: Blue;">file</span><span style="color: Gray;">:</span><span style="color: Blue;">open</span><span style="color: Olive;">(</span><span style="color: Blue;">Name</span><span style="color: Gray;">, </span><span style="color: Blue;">Mode</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum0</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">get_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">eof</span><span style="color: Gray;">&nbsp; -&gt; </span><span style="color: Blue;">file</span><span style="color: Gray;">:</span><span style="color: Blue;">close</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Olive;">)</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Line</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">NewAccum</span><span style="color: Gray;"> = </span><span style="color: Blue;">Proc</span><span style="color: Olive;">(</span><span style="color: Blue;">Line</span><span style="color: Gray;">, </span><span style="color: Blue;">Accum</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">for_each_line</span><span style="color: Olive;">(</span><span style="color: Blue;">Device</span><span style="color: Gray;">, </span><span style="color: Blue;">Proc</span><span style="color: Gray;">, </span><span style="color: Blue;">NewAccum</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li></ol></div>
<p>Now in the subsmanager shell, you can read from the text file and add the subscriptions:</p>
<div class="hl-surround"><div class="hl-main">$ erl -name router@minifeeds4.gs2 +K true +A 128 -setcookie secretcookie -mnesia dump_log_write_threshold 50000 -mnesia dc_dump_limit 40<br />erl&gt; c(readfriends), c(subsmanager).<br />erl&gt; subsmanager:first_run().<br />erl&gt; subsmanager:start_link().<br />erl&gt; subsmanager:add_subscriptions( readfriends:load(&quot;fakefriends.txt&quot;) ).</div></div>
<p>Note the additional mnesia parameters &#8211; these are to avoid the ** WARNING ** Mnesia is overloaded messages you would (probably) otherwise see. Refer to my previous post: <a href="http://www.metabrew.com/article/on-bulk-loading-data-into-mnesia/" target=_blank>On bulk loading data into Mnesia</a> for alternative ways to load in lots of data. The best solution seems to be (as pointed out in the comments, thanks Jacob!) to set those options. The <a href="http://www.erlang.org/doc/apps/mnesia/" target=_blank>Mnesia reference manual</a> contains many other settings under Configuration Parameters, and is worth a look.</p>
<p><strong>Turning it up to 1 Million</strong></p>
<p>Creating a million tcp connections from one host is non-trivial. I’ve a feeling that people who do this regularly have small clusters dedicated to simulating lots of client connections, probably running a real tool like Tsung. Even with the tuning from Part 1 to increase kernel tcp memory, increase the file descriptor ulimits and set the local port range to the maximum, we will still hit a hard limit on ephemeral ports. When making a tcp connection, the client end is allocated (or you can specify) a port from the range in /proc/sys/net/ipv4/ip_local_port_range. It doesn’t matter if you specify it manually, or use an ephemeral port, you’re still going to run out. In Part 1, we set the range to “1024 65535″ &#8211; meaning there are 65535-1024 = 64511 unprivileged ports available. Some of them will be used by other processes, but we’ll never get over 64511 client connections, because we’ll run out of ports.</p>
<p>The local port range is assigned per-IP, so if we make our outgoing connections specifically from a range of different local IP addresses, we’ll be able to open more than 64511 outgoing connections in total.</p>
<p>So let’s bring up 17 new IP addresses, with the intention of making 62,000 connections from each &#8211; giving us a total of 1,054,000 connections. Safely over the 2^32 mark:</p>
<div class="hl-surround"><div class="hl-main">$ for i in `seq 1 17`; do echo sudo ifconfig eth0:$i 10.0.0.$i up ; done</div></div>
<p>If you run ifconfig now you should see your virtual interfaces: eth0:1, eth0:2 … eth0:17, each with a different IP address. Obviously you should chose a sensible part of whatever address space you are using.</p>
<p>All that remains now is to modify the floodtest tool from Part 1 to specify the local IP it should connect from… Unfortunately the erlang http client doesn’t let you specify the source IP. Neither does ibrowse, the alternative http client library. Damn.</p>
<p>[crazy idea]<br />
At this point I considered another option: bringing up 17 pairs of IPs &#8211; one on the server and one on the client &#8211; each pair in their own isolated /30 subnet. I think that if I then made the client connect to any given server IP, it would force the local address to be other half of the pair on that subnet, because only one of the local IPs would actually be able to reach the server IP. In theory, this would mean declaring the local source IP on the client machine would not be necessary (although the range of server IPs would need to be specified). I don’t know if this would really work &#8211; it sounded plausible at the time. In the end I decided it was too perverted and didn’t try it.<br />
[/crazy idea]</p>
<p>I also poked around in OTP’s http_transport code and considered adding support for specifying the local IP. It’s not really a feature you usually need in an HTTP client though, and it would certainly have been more work.</p>
<p>gen_tcp lets you specify the source address, so I ended up writing a rather crude client using gen_tcp specifically for this test:</p>
<p>floodtest2.erl</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=floodtest2.erl">floodtest2.erl</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline"><span style="color: Gray;">-</span><span style="color: Blue;">module</span><span style="color: Olive;">(</span><span style="color: Blue;">floodtest2</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">compile</span><span style="color: Olive;">(</span><span style="color: Blue;">export_all</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">define</span><span style="color: Olive;">(</span><span style="color: Blue;">SERVERADDR</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">10.1.2.3</span><span style="color: #8b0000;">&quot;</span><span style="color: Olive;">)</span><span style="color: Gray;">. </span><span style="color: #ffa500;">% where mochiweb is running</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; -</span><span style="color: Blue;">define</span><span style="color: Olive;">(</span><span style="color: Blue;">SERVERPORT</span><span style="color: Gray;">, </span><span style="color: Maroon;">8000</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% Generate the config in bash like so (chose some available address space):</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% EACH=62000; for i in `seq 1 17`; do echo &quot;{{10,0,0,$i}, $((($i-1)*$EACH+1)), $(($i*$EACH))}, &quot;; done</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">run</span><span style="color: Olive;">(</span><span style="color: Blue;">Interval</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Config</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">1</span><span style="color: Gray;">}, </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Maroon;">62000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">2</span><span style="color: Gray;">}, </span><span style="color: Maroon;">62001</span><span style="color: Gray;">, </span><span style="color: Maroon;">124000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">3</span><span style="color: Gray;">}, </span><span style="color: Maroon;">124001</span><span style="color: Gray;">, </span><span style="color: Maroon;">186000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">4</span><span style="color: Gray;">}, </span><span style="color: Maroon;">186001</span><span style="color: Gray;">, </span><span style="color: Maroon;">248000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">5</span><span style="color: Gray;">}, </span><span style="color: Maroon;">248001</span><span style="color: Gray;">, </span><span style="color: Maroon;">310000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">6</span><span style="color: Gray;">}, </span><span style="color: Maroon;">310001</span><span style="color: Gray;">, </span><span style="color: Maroon;">372000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">7</span><span style="color: Gray;">}, </span><span style="color: Maroon;">372001</span><span style="color: Gray;">, </span><span style="color: Maroon;">434000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">8</span><span style="color: Gray;">}, </span><span style="color: Maroon;">434001</span><span style="color: Gray;">, </span><span style="color: Maroon;">496000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">9</span><span style="color: Gray;">}, </span><span style="color: Maroon;">496001</span><span style="color: Gray;">, </span><span style="color: Maroon;">558000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">10</span><span style="color: Gray;">}, </span><span style="color: Maroon;">558001</span><span style="color: Gray;">, </span><span style="color: Maroon;">620000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">11</span><span style="color: Gray;">}, </span><span style="color: Maroon;">620001</span><span style="color: Gray;">, </span><span style="color: Maroon;">682000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">12</span><span style="color: Gray;">}, </span><span style="color: Maroon;">682001</span><span style="color: Gray;">, </span><span style="color: Maroon;">744000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">13</span><span style="color: Gray;">}, </span><span style="color: Maroon;">744001</span><span style="color: Gray;">, </span><span style="color: Maroon;">806000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">14</span><span style="color: Gray;">}, </span><span style="color: Maroon;">806001</span><span style="color: Gray;">, </span><span style="color: Maroon;">868000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">15</span><span style="color: Gray;">}, </span><span style="color: Maroon;">868001</span><span style="color: Gray;">, </span><span style="color: Maroon;">930000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">16</span><span style="color: Gray;">}, </span><span style="color: Maroon;">930001</span><span style="color: Gray;">, </span><span style="color: Maroon;">992000</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; {{</span><span style="color: Maroon;">10</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">17</span><span style="color: Gray;">}, </span><span style="color: Maroon;">992001</span><span style="color: Gray;">, </span><span style="color: Maroon;">1054000</span><span style="color: Gray;">}</span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Config</span><span style="color: Gray;">, </span><span style="color: Blue;">Interval</span><span style="color: Olive;">)</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">Config</span><span style="color: Gray;">, </span><span style="color: Blue;">Interval</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Monitor</span><span style="color: Gray;"> = </span><span style="color: Blue;">monitor</span><span style="color: Olive;">()</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">AdjustedInterval</span><span style="color: Gray;"> = </span><span style="color: Blue;">Interval</span><span style="color: Gray;"> / </span><span style="color: Blue;">length</span><span style="color: Olive;">(</span><span style="color: Blue;">Config</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">spawn</span><span style="color: Olive;">(</span><span style="color: Green;">fun</span><span style="color: Gray;"> </span><span style="color: Blue;">start</span><span style="color: Gray;">/</span><span style="color: Maroon;">5</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Lower</span><span style="color: Gray;">, </span><span style="color: Blue;">Upper</span><span style="color: Gray;">, </span><span style="color: Blue;">Ip</span><span style="color: Gray;">, </span><span style="color: Blue;">AdjustedInterval</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">])</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; || {</span><span style="color: Blue;">Ip</span><span style="color: Gray;">, </span><span style="color: Blue;">Lower</span><span style="color: Gray;">, </span><span style="color: Blue;">Upper</span><span style="color: Gray;">}&nbsp; &lt;- </span><span style="color: Blue;">Config</span><span style="color: Gray;">&nbsp;</span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">LowerID</span><span style="color: Gray;">, </span><span style="color: Blue;">UpperID</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Gray;">, </span><span style="color: Blue;">_</span><span style="color: Olive;">)</span><span style="color: Gray;">&nbsp;</span><span style="color: Green;">when</span><span style="color: Gray;"> </span><span style="color: Blue;">LowerID</span><span style="color: Gray;"> == </span><span style="color: Blue;">UpperID</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">done</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">LowerID</span><span style="color: Gray;">, </span><span style="color: Blue;">UpperID</span><span style="color: Gray;">, </span><span style="color: Blue;">LocalIP</span><span style="color: Gray;">, </span><span style="color: Blue;">Interval</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">spawn</span><span style="color: Olive;">(</span><span style="color: Green;">fun</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">connect</span><span style="color: Gray;">/</span><span style="color: Maroon;">5</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Gray;">?</span><span style="color: Blue;">SERVERADDR</span><span style="color: Gray;">, ?</span><span style="color: Blue;">SERVERPORT</span><span style="color: Gray;">, </span><span style="color: Blue;">LocalIP</span><span style="color: Gray;">, </span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">/test/</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">++</span><span style="color: Blue;">LowerID</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">after</span><span style="color: Gray;"> </span><span style="color: Blue;">Interval</span><span style="color: Gray;"> -&gt; </span><span style="color: Blue;">start</span><span style="color: Olive;">(</span><span style="color: Blue;">LowerID</span><span style="color: Gray;"> + </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">UpperID</span><span style="color: Gray;">, </span><span style="color: Blue;">LocalIP</span><span style="color: Gray;">, </span><span style="color: Blue;">Interval</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">connect</span><span style="color: Olive;">(</span><span style="color: Blue;">ServerAddr</span><span style="color: Gray;">, </span><span style="color: Blue;">ServerPort</span><span style="color: Gray;">, </span><span style="color: Blue;">ClientIP</span><span style="color: Gray;">, </span><span style="color: Blue;">Path</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Opts</span><span style="color: Gray;"> = </span><span style="color: Olive;">[</span><span style="color: Blue;">binary</span><span style="color: Gray;">, {</span><span style="color: Blue;">packet</span><span style="color: Gray;">, </span><span style="color: Maroon;">0</span><span style="color: Gray;">}, {</span><span style="color: Blue;">ip</span><span style="color: Gray;">, </span><span style="color: Blue;">ClientIP</span><span style="color: Gray;">}, {</span><span style="color: Blue;">reuseaddr</span><span style="color: Gray;">, </span><span style="color: Blue;">true</span><span style="color: Gray;">}, {</span><span style="color: Blue;">active</span><span style="color: Gray;">, </span><span style="color: Blue;">false</span><span style="color: Gray;">}</span><span style="color: Olive;">]</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">Sock</span><span style="color: Gray;">} = </span><span style="color: Blue;">gen_tcp</span><span style="color: Gray;">:</span><span style="color: Blue;">connect</span><span style="color: Olive;">(</span><span style="color: Blue;">ServerAddr</span><span style="color: Gray;">, </span><span style="color: Blue;">ServerPort</span><span style="color: Gray;">, </span><span style="color: Blue;">Opts</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Monitor</span><span style="color: Gray;"> ! </span><span style="color: Blue;">open</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ReqL</span><span style="color: Gray;"> = </span><span style="color: Blue;">io_lib</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">GET ~s</span><span style="color: Navy;">\r\n</span><span style="color: Red;">Host: ~s</span><span style="color: Navy;">\r\n\r\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Path</span><span style="color: Gray;">, </span><span style="color: Blue;">ServerAddr</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Req</span><span style="color: Gray;"> = </span><span style="color: Blue;">list_to_binary</span><span style="color: Olive;">(</span><span style="color: Blue;">ReqL</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;"> = </span><span style="color: Blue;">gen_tcp</span><span style="color: Gray;">:</span><span style="color: Blue;">send</span><span style="color: Olive;">(</span><span style="color: Blue;">Sock</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">Req</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">do_recv</span><span style="color: Olive;">(</span><span style="color: Blue;">Sock</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Olive;">(</span><span style="color: Green;">catch</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">gen_tcp</span><span style="color: Gray;">:</span><span style="color: Blue;">close</span><span style="color: Olive;">(</span><span style="color: Blue;">Sock</span><span style="color: Olive;">))</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">ok</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">do_recv</span><span style="color: Olive;">(</span><span style="color: Blue;">Sock</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">)</span><span style="color: Gray;">-&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">case</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">gen_tcp</span><span style="color: Gray;">:</span><span style="color: Blue;">recv</span><span style="color: Olive;">(</span><span style="color: Blue;">Sock</span><span style="color: Gray;">, </span><span style="color: Maroon;">0</span><span style="color: Olive;">)</span><span style="color: Gray;"> </span><span style="color: Green;">of</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">ok</span><span style="color: Gray;">, </span><span style="color: Blue;">B</span><span style="color: Gray;">} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Monitor</span><span style="color: Gray;"> ! {</span><span style="color: Blue;">bytes</span><span style="color: Gray;">, </span><span style="color: Blue;">size</span><span style="color: Olive;">(</span><span style="color: Blue;">B</span><span style="color: Olive;">)</span><span style="color: Gray;">},</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Recvd ~s</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Gray;">&nbsp;</span><span style="color: Blue;">binary_to_list</span><span style="color: Olive;">(</span><span style="color: Blue;">B</span><span style="color: Olive;">)])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Recvd ~w bytes</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Blue;">size</span><span style="color: Olive;">(</span><span style="color: Blue;">B</span><span style="color: Olive;">)])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">do_recv</span><span style="color: Olive;">(</span><span style="color: Blue;">Sock</span><span style="color: Gray;">, </span><span style="color: Blue;">Monitor</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">error</span><span style="color: Gray;">, </span><span style="color: Blue;">closed</span><span style="color: Gray;">} -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Monitor</span><span style="color: Gray;"> ! </span><span style="color: Blue;">closed</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">closed</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Other</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Monitor</span><span style="color: Gray;"> ! </span><span style="color: Blue;">closed</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">Other:~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">Other</span><span style="color: Olive;">])</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: #ffa500;">% Monitor process receives stats and reports how much data we received etc:</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">monitor</span><span style="color: Olive;">()</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Pid</span><span style="color: Gray;"> = </span><span style="color: Blue;">spawn</span><span style="color: Olive;">(</span><span style="color: Gray;">?</span><span style="color: Blue;">MODULE</span><span style="color: Gray;">, </span><span style="color: Blue;">monitor0</span><span style="color: Gray;">, </span><span style="color: Olive;">[</span><span style="color: Gray;">{</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">,</span><span style="color: Maroon;">0</span><span style="color: Gray;">}</span><span style="color: Olive;">])</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">timer</span><span style="color: Gray;">:</span><span style="color: Blue;">send_interval</span><span style="color: Olive;">(</span><span style="color: Maroon;">10000</span><span style="color: Gray;">, </span><span style="color: Blue;">Pid</span><span style="color: Gray;">, </span><span style="color: Blue;">report</span><span style="color: Olive;">)</span><span style="color: Gray;">,</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">Pid</span><span style="color: Gray;">.</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp;&nbsp; </span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">monitor0</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Open</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">, </span><span style="color: Blue;">Bytes</span><span style="color: Gray;">}=</span><span style="color: Blue;">S</span><span style="color: Olive;">)</span><span style="color: Gray;"> -&gt;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">receive</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">report</span><span style="color: Gray;">&nbsp; -&gt; </span><span style="color: Blue;">io</span><span style="color: Gray;">:</span><span style="color: Blue;">format</span><span style="color: Olive;">(</span><span style="color: #8b0000;">&quot;</span><span style="color: Red;">{Open, Closed, Chunks, Bytes} = ~w</span><span style="color: Navy;">\n</span><span style="color: #8b0000;">&quot;</span><span style="color: Gray;">,</span><span style="color: Olive;">[</span><span style="color: Blue;">S</span><span style="color: Olive;">])</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">open</span><span style="color: Gray;">&nbsp; &nbsp; -&gt; </span><span style="color: Blue;">monitor0</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Open</span><span style="color: Gray;"> + </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">, </span><span style="color: Blue;">Bytes</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">closed</span><span style="color: Gray;">&nbsp; -&gt; </span><span style="color: Blue;">monitor0</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Open</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;"> + </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">, </span><span style="color: Blue;">Bytes</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Blue;">chunk</span><span style="color: Gray;">&nbsp;&nbsp; -&gt; </span><span style="color: Blue;">monitor0</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Open</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;"> + </span><span style="color: Maroon;">1</span><span style="color: Gray;">, </span><span style="color: Blue;">Bytes</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span><span style="color: Gray;">;</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {</span><span style="color: Blue;">bytes</span><span style="color: Gray;">, </span><span style="color: Blue;">B</span><span style="color: Gray;">} -&gt; </span><span style="color: Blue;">monitor0</span><span style="color: Olive;">(</span><span style="color: Gray;">{</span><span style="color: Blue;">Open</span><span style="color: Gray;">, </span><span style="color: Blue;">Closed</span><span style="color: Gray;">, </span><span style="color: Blue;">Chunks</span><span style="color: Gray;">, </span><span style="color: Blue;">Bytes</span><span style="color: Gray;"> + </span><span style="color: Blue;">B</span><span style="color: Gray;">}</span><span style="color: Olive;">)</span></li>
<li><span style="color: Gray;">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span style="color: Green;">end</span><span style="color: Gray;">.</span></li></ol></div>
<p>As an initial test I was connecting to the mochiweb app from Part 1 &#8211; it simply sends one message to every client every 10 seconds.</p>
<div class="hl-surround"><div class="hl-main">erl&gt; c(floodtest2), floodtest2:run(20).</div></div>
<p><strong>This quickly ate all my memory.</strong></p>
<p>Turns out opening lots of connections with gen_tcp like that eats a lot of ram. I think it’d need ~36GB to make it work without any additional tuning. I’m not interested in trying to optimise my quick-hack erlang http client (in the real world, this would be 1M actual web browsers), and the only machine I could get my hands on that has more than 32GB of RAM is one of our production databases, and I can’t find a good excuse to take Last.fm offline whilst I test this <img src='http://erlang-china.org/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' />  Additionally, it seems like it still only managed to open around 64,500 ports. Hmm.</p>
<p>At this point I decided to break out the trusty <a href="http://monkey.org/~provos/libevent/" target=_blank>libevent</a>, which I was pleased to discover has an HTTP API. Newer versions also have a evhttp_connection_set_local_address function in the http API. This sounds promising.</p>
<p>Here’s the http client in C using libevent:</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=httpclient.c">httpclient.c</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">#include &lt;sys/types.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;sys/time.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;sys/queue.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;stdlib.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;err.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;event.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;evhttp.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;unistd.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;stdio.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;sys/socket.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;netinet/in.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;time.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;pthread.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#define BUFSIZE 4096</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#define NUMCONNS 62000</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#define SERVERADDR &quot;10.103.1.43&quot;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#define SERVERPORT 8000</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#define SLEEP_MS 10</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;char buf[BUFSIZE];</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;int bytes_recvd = 0;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;int chunks_recvd = 0;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;int closed = 0;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;int connected = 0;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// called per chunk received</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;void chunkcb(struct evhttp_request * req, void * arg)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int s = evbuffer_remove( req-&gt;input_buffer, &amp;buf, BUFSIZE );</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;//printf(&quot;Read %d bytes: %s\n&quot;, s, &amp;buf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;bytes_recvd += s;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;chunks_recvd++;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(connected &gt;= NUMCONNS &amp;&amp; chunks_recvd%10000==0)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printf(&quot;&gt;Chunks: %d\tBytes: %d\tClosed: %d\n&quot;, chunks_recvd, bytes_recvd, closed);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// gets called when request completes</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;void reqcb(struct evhttp_request * req, void * arg)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;closed++;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;int main(int argc, char **argv)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;event_init();</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct evhttp *evhttp_connection;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct evhttp_request *evhttp_request;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;char addr[16];</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;char path[32]; // eg: &quot;/test/123&quot;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int i,octet;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(octet=1; octet&lt;=17; octet++){</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sprintf(&amp;addr, &quot;10.224.0.%d&quot;, octet);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i=1;i&lt;=NUMCONNS;i++) {</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_connection = evhttp_connection_new(SERVERADDR, SERVERPORT);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_connection_set_local_address(evhttp_connection, &amp;addr);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_set_timeout(evhttp_connection, 864000); // 10 day timeout</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_request = evhttp_request_new(reqcb, NULL);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_request-&gt;chunk_cb = chunkcb;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;sprintf(&amp;path, &quot;/test/%d&quot;, ++connected);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(i%100==0)&nbsp; printf(&quot;Req: %s\t-&gt;\t%s\n&quot;, addr, &amp;path);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_make_request( evhttp_connection, evhttp_request, EVHTTP_REQ_GET, path );</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_connection_set_timeout(evhttp_request-&gt;evcon, 864000);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;event_loop( EVLOOP_NONBLOCK );</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if( connected % 200 == 0 )</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;printf(&quot;\nChunks: %d\tBytes: %d\tClosed: %d\n&quot;, chunks_recvd, bytes_recvd, closed);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;usleep(SLEEP_MS*1000);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;event_dispatch();</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return 0;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;}</li></ol></div>
<p>Most parameters are hardcoded as #define’s so you configure it by editing the source and recompiling.</p>
<p>Compile and run:</p>
<div class="hl-surround"><div class="hl-main">$ gcc -o httpclient httpclient.c -levent<br />$ ./httpclient</div></div>
<p><strong>This still failed to open more than 64,500 ports</strong>. Although it used less RAM doing it.</p>
<p>It turns out that although I was specifying the local addresses, the ephemeral port allocation somewhere in the kernel or tcp stack didn’t care, and still ran out after 2^16. So in order to open more than 64,500 connections, you need to specify the local address and local port yourself, and manage them accordingly.</p>
<p>Unfortunately the libevent HTTP API doesn’t have an option to specify the local port. <a href="http://monkeymail.org/archives/libevent-users/2008-November/001415.html" target=_blank>I patched libevent</a> to add a suitable function:</p>
<div class="hl-surround"><div class="hl-main">void evhttp_connection_set_local_port(struct evhttp_connection *evcon, u_short port);.</div></div>
<p>This was a surprisingly pleasant experience; libevent seems well written, and the documentation is pretty decent too.</p>
<p>With my modified libevent installed, I was able to add the following under the set_local_address line in the above code:</p>
<div class="hl-surround"><div class="hl-main">evhttp_connection_set_local_port(evhttp_connection, 1024+i);</div></div>
<p>With that in place, multiple connections from different addresses were able to use the same local port number, specific to the the local address. I recompiled the client and let it run for a bit to confirm it would break the 2^16 barrier.</p>
<p>Netstat confirms it:</p>
<div class="hl-surround"><div class="hl-main"># netstat -n | awk '/^tcp/ {t[$NF]++}END{for(state in t){print state, t[state]}}’<br />TIME_WAIT 8<br />ESTABLISHED 118222</div></div>
<p>This shows how many ports are open in various states. We’re finally able to open more than 2^16 connections, phew.</p>
<p>Now we have a tool capable of opening a million http connections from a single box. It seems to consume around 2KB per connection, plus whatever the kernel needs. It’s time to use it for the “million connected user” test against our mochiweb comet server.</p>
<p><strong>C1024K Test &#8211; 1 million comet connections</strong></p>
<p>For this test I used 4 different servers of varying specs. These specs may be overpowered for the experiment, but they were available and waiting to go into production, and this made a good burn-in test. All four servers are on the same gigabit LAN, with up to 3 switches and a router in the middle somewhere.</p>
<p>The 1 million test I ran is similar to the 10k test from parts 1 and 2, the main difference being the modified client, now written in C using libevent, and that I’m running in a proper distributed-erlang setup with more than one machine.</p>
<p>On server 1 &#8211; Quad-core 2GHz CPU, 16GB of RAM</p>
<ul>
<li>Start subsmanager</li>
<li>Load in the friends data</li>
<li>Start the router</li>
</ul>
<p>On server 2 &#8211; Dual Quad-core 2.8GHz CPU, 32GB of RAM</p>
<ul>
<li>Start mochiweb app</li>
</ul>
<p>On server 3 &#8211; Quad-core 2GHz CPU, 16GB of RAM</p>
<ul>
<li>Create 17 virtual IPs as above</li>
<li>Install patched libevent</li>
<li>Run client: ./httpclient to create 100 connections per second, up to 1M</li>
</ul>
<p>On server 4 &#8211; Dual-core 2GHz, 2GB RAM</p>
<ul>
<li>Run msggen program, to send lots of messages to the router</li>
</ul>
<p>I measured the memory usage of mochiweb during the ramp-up to a million connections, and for the rest of the day:</p>
<p><img src="http://www.metabrew.com/wp-content/uploads/2008/11/mochimem-c1000k.png" alt="mochiweb Memory, 1M connections" /></p>
<p>The httpclient has a built in delay of 10ms between connections, so it took nearly 3 hours to open a million connections. The resident memory used by the mochiweb process with 1M open connections was around 25GB. Here’s the server this was running on as seen by Ganglia, which measures CPU, network and memory usage and produces nice graphs:</p>
<p><img src="http://www.metabrew.com/wp-content/uploads/2008/11/server21.png" alt="server running mochiweb, 1M connections" /></p>
<p>You can see it needs around 38GB and has started to swap. I suspect the difference is mostly consumed by the kernel to keep those connections open. The uplift at the end is when I started sending messages.</p>
<p>Messages were generated using 1,000 processes, with an average time between messages of 60ms per process, giving around 16,666 messages per second overall:</p>
<p>erl> [ spawn( fun()->msggen:start(1000000, 10+random:uniform(100), 1000000) end) || I <- lists:seq(1,1000) ].</p>
<p>The machine (server-4) generating messages looked like this on Ganglia:</p>
<p><img src="http://www.metabrew.com/wp-content/uploads/2008/11/msggen.png" alt="16,666 messages/s" /></p>
<p>That’s 10 MB per second of messages it’s pumping out &#8211; 16,666 messages a second. Typically these messages would come from a message bus, app servers, or part of an existing infrastructure.</p>
<p>When I started sending messages, the load on server 1 (hosting subsmanager and router) stayed below 1, and CPU utilization increased from 0 to 5%.</p>
<p>CPU on server 2 (hosting mochiweb app, with 1M connections) increased more dramatically:</p>
<p><img src="http://www.metabrew.com/wp-content/uploads/2008/11/server2.png" alt="mochiweb server" /></p>
<p>Naturally as processes have to leave their hibernate state to handle messages, memory usage will increase slightly. Having all connections open with no messages is a best-case for memory usage &#8211; unsurprisingly, actually doing stuff requires more memory.</p>
<p>So where does this leave us? To be on the safe side, the mochiweb machine would need 40GB of RAM to hold open 1M active comet connections. Under load, up to 30GB of the memory would be used by the mochiweb app, and the remaining 10GB by the kernel. In other words, you need to allow 40KB per connection.</p>
<p>During various test with lots of connections, I ended up making some additional changes to my sysctl.conf. This was part trial-and-error, I don’t really know enough about the internals to make especially informed decisions about which values to change. My policy was to wait for things to break, check /var/log/kern.log and see what mysterious error was reported, then increase stuff that sounded sensible after a spot of googling. Here are the settings in place during the above test:</p>
<div class="hl-surround"><div class="hl-main">net.core.rmem_max = 33554432<br />net.core.wmem_max = 33554432<br />net.ipv4.tcp_rmem = 4096 16384 33554432<br />net.ipv4.tcp_wmem = 4096 16384 33554432<br />net.ipv4.tcp_mem = 786432 1048576 26777216<br />net.ipv4.tcp_max_tw_buckets = 360000<br />net.core.netdev_max_backlog = 2500<br />vm.min_free_kbytes = 65536<br />vm.swappiness = 0<br />net.ipv4.ip_local_port_range = 1024 65535</div></div>
<p>I would like to learn more about Linux tcp tuning so I can make a more informed decision about these settings. These are almost certainly not optimal, but at least they were enough to get to 1M connections. These changes, along with the fact this is running on a 64bit Erlang VM, and thus has a wordsize of 8bytes instead of 4, might explain why the memory usage is much higher than I observed during the C10k test of part 2.</p>
<p><strong>An Erlang C-Node using Libevent</strong></p>
<p>After dabbling with the HTTP api for libevent, it seemed entirely sensible to try the 1M connection test against a libevent HTTPd written in C so we have a basis for comparison.</p>
<p>I’m guessing that enabling kernel poll means the erlang VM is able to use epoll (or similar), but even so there’s clearly some overhead involved which we might be able to mitigate by delegating the connection handling to a C program using libevent. I want to reuse most of the Erlang code so far, so let’s do the bare minimum in C &#8211; just the connection handling and HTTP stuff.</p>
<p>Libevent has an asynchronous HTTP API, which makes implementing http servers trivial &#8211; well, trivial for C, but still less trivial than mochiweb IMO <img src='http://erlang-china.org/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' />  I’d also been looking for an excuse to try the Erlang C interface, so the following program combines the two. It’s a comet http server in C using libevent which identifies users using an integer Id (like our mochiweb app), and also acts as an Erlang C-Node.</p>
<p>It connects to a designated erlang node, listens for messages like {123, <<"Hello user 123">>} then dispatches “Hello user 123″ to user 123, if connected. Messages for users that are not connected are discarded, just like previous examples.</p>
<p>httpdcnode.c</p>
<div class="hl-title">&#19979;&#36733;: <a href="http://erlang-china.org/wordpress/wp-content/plugins/coolcode/coolcode.php?p=245&amp;download=httpdcnode.c">httpdcnode.c</a></div><div class="hl-surround"><ol class="hl-main ln-show" title="Double click to hide line number." ondblclick = "linenumber(this)"><li class="hl-firstline">#include &lt;sys/types.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;sys/time.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;sys/queue.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;stdlib.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;err.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;event.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;evhttp.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;stdio.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;sys/socket.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;netinet/in.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &quot;erl_interface.h&quot;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &quot;ei.h&quot;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#include &lt;pthread.h&gt;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#define BUFSIZE 1024</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;#define MAXUSERS (17*65536) // C1024K</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// List of current http requests by uid:</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;struct evhttp_request * clients[MAXUSERS+1];</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// Memory to store uids passed to the cleanup callback:</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;int slots[MAXUSERS+1];</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// called when user disconnects</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;void cleanup(struct evhttp_connection *evcon, void *arg)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int *uidp = (int *) arg;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fprintf(stderr, &quot;disconnected uid %d\n&quot;, *uidp);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;clients[*uidp] = NULL;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// handles http connections, sets them up for chunked transfer,</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// extracts the user id and registers in the global connection table,</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// also sends a welcome chunk.</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;void request_handler(struct evhttp_request *req, void *arg)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct evbuffer *buf;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;buf = evbuffer_new();</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (buf == NULL){</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;err(1, &quot;failed to create response buffer&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_add_header(req-&gt;output_headers, &quot;Content-Type&quot;, &quot;text/html; charset=utf-8&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int uid = -1;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(strncmp(evhttp_request_uri(req), &quot;/test/&quot;, 6) == 0){</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;uid = atoi( 6+evhttp_request_uri(req) );</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(uid &lt;= 0){</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_add_printf(buf, &quot;User id not found, try /test/123 instead&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_send_reply(req, HTTP_NOTFOUND, &quot;Not Found&quot;, buf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_free(buf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(uid &gt; MAXUSERS){</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_add_printf(buf, &quot;Max uid allowed is %d&quot;, MAXUSERS);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_send_reply(req, HTTP_SERVUNAVAIL, &quot;We ran out of numbers&quot;, buf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_free(buf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_send_reply_start(req, HTTP_OK, &quot;OK&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Send welcome chunk:</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_add_printf(buf, &quot;Welcome, Url: ‘%s’ Id: %d\n&quot;, evhttp_request_uri(req), uid);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_send_reply_chunk(req, buf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_free(buf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// put reference into global uid-&gt;connection table:</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;clients[uid] = req;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// set close callback</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_connection_set_closecb( req-&gt;evcon, cleanup, &amp;slots[uid] );</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// runs in a thread - the erlang c-node stuff</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;// expects msgs like {uid, msg} and sends a a ‘msg’ chunk to uid if connected</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;void cnode_run()</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int fd;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* fd to Erlang node */</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int got;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Result of receive */</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;unsigned char buf[BUFSIZE];&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Buffer for incoming message */</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ErlMessage emsg;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;/* Incoming message */</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;ETERM *uid, *msg;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;erl_init(NULL, 0);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (erl_connect_init(1, &quot;secretcookie&quot;, 0) == -1)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;erl_err_quit(&quot;erl_connect_init&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if ((fd = erl_connect(&quot;httpdmaster@localhost&quot;)) &lt; 0)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;erl_err_quit(&quot;erl_connect&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fprintf(stderr, &quot;Connected to httpdmaster@localhost\n\r&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct evbuffer *evbuf;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;while (1) {</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;got = erl_receive_msg(fd, buf, BUFSIZE, &amp;emsg);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (got == ERL_TICK) {</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;continue;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} else if (got == ERL_ERROR) {</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fprintf(stderr, &quot;ERL_ERROR from erl_receive_msg.\n&quot;);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;break;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;} else {</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if (emsg.type == ERL_REG_SEND) {</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// get uid and body data from eg: {123, &lt;&lt;&quot;Hello&quot;&gt;&gt;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;uid = erl_element(1, emsg.msg);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;msg = erl_element(2, emsg.msg);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int userid = ERL_INT_VALUE(uid);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;char *body = (char *) ERL_BIN_PTR(msg);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int body_len = ERL_BIN_SIZE(msg);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Is this userid connected?</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;if(clients[userid]){</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fprintf(stderr, &quot;Sending %d bytes to uid %d\n&quot;, body_len, userid);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuf = evbuffer_new();</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_add(evbuf, (const void*)body, (size_t) body_len);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_send_reply_chunk(clients[userid], evbuf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evbuffer_free(evbuf);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}else{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fprintf(stderr, &quot;Discarding %d bytes to uid %d - user not connected\n&quot;,</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;body_len, userid);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// noop</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;erl_free_term(emsg.msg);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;erl_free_term(uid);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;erl_free_term(msg);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// if we got here, erlang connection died.</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// this thread is supposed to run forever</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// TODO - gracefully handle failure / reconnect / etc</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pthread_exit(0);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;}</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;int main(int argc, char **argv)</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;{</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Launch the thread that runs the cnode:</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pthread_attr_t tattr;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pthread_t helper;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int status;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;pthread_create(&amp;helper, NULL, cnode_run, NULL);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; </li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;int i;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;for(i=0;i&lt;=MAXUSERS;i++) slots[i]=i;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Launch libevent httpd:</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;struct evhttp *httpd;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;event_init();</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;httpd = evhttp_start(&quot;0.0.0.0&quot;, 8000);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_set_gencb(httpd, request_handler, NULL);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;event_dispatch();</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;// Not reached, event_dispatch() shouldn’t return</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;evhttp_free(httpd);</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return 0;</li>
<li>&nbsp;&nbsp; &nbsp; &nbsp;}</li></ol></div>
<p>The maximum number of users is #defined, and similarly to the mochiweb server, it listens on port 8000 and expects users to connect with a path like so: /test/<userid>. Also hardcoded is the name of the erlang node it will connect to in order to receive messages, httpdmaster@localhost, and the erlang cookie, “secretcookie”. Change these accordingly.</p>
<p>Run the erlang node it will connect to first:</p>
<div class="hl-surround"><div class="hl-main">$ erl -setcookie secretcookie -sname httpdmaster@localhost</div></div>
<p>Compile and run like so:</p>
<div class="hl-surround"><div class="hl-main">$ gcc -o httpdcnode httpdcnode.c -lerl_interface -lei -levent<br />$ ./httpdcnode</div></div>
<p>In the erlang shell, check you can see the hidden c-node:</p>
<div class="hl-surround"><div class="hl-main">erl&gt; nodes(hidden).<br />[c1@localhost]</div></div>
<p>Now connect in your browser to http://localhost:8000/test/123. You should see the welcome message.</p>
<p>Now back to the erlang shell &#8211; send a message to the C node:</p>
<div class="hl-surround"><div class="hl-main">erl&gt; {any, c1@localhost} ! {123, &lt;&lt;&quot;Hello Libevent World&quot;&gt;&gt;}.</div></div>
<p>Note that we don’t have a Pid to use, so we use the alternate representation of {procname, node}. We use ‘any’ as the process name, which is ignored by the C-node.</p>
<p><strong>Now you’re able to deliver comet messages via Erlang, but all the http connections are managed by a libevent C program which acts as an Erlang node.</strong></p>
<p>After removing the debug print statements, I connected 1M clients to the httpdcnode server using the same client as above, the machine showed a total of just under 10GB or memory used. The resident memory of the server process was stable at under 2GB:</p>
<p><img src="http://www.metabrew.com/wp-content/uploads/2008/11/mochimem-libevent.png" alt="memory of libevent based server process, 1M connection"></p>
<p>So big savings compared to mochiweb when handling lots of connections &#8211; the resident memory per connection for the server process with libevent is just under 2KB. With everything connected, the server machine claims:<br />
Mem: 32968672k total, 9636488k used, 23332184k free, 180k buffers<br />
So the kernel/tcp stack is consuming an additional 8KB per connection, which seems a little high, but I have no basis for comparison.</p>
<p>This libevent-cnode server needs a bit more work. It doesn’t sensibly handle multiple connections from the same user yet, and there’s no locking so a race condition exists if you disconnect at just when a message was going to be dispatched.</p>
<p>Even so, I think this could be generalized in such a way that would allow you to<strong> use Erlang for all the interesting stuff, and have a C+libevent process act as a dumb connection-pool</strong>. With a bit more wrapper code and callbacks into Erlang, you’d hardly need to know this was going on &#8211; the C program could be run as a driver or a C-node, and an Erlang wrapper could give you a decent api built on top of libevent. (see <a href="http://www.metabrew.com/article/erlang-libketama-driver-consistent-hashing/" target=_blank>this post</a> for an example Erlang C driver). I would like to experiment further with this.</p>
<p><strong>Final Thoughts</strong></p>
<p>I have enough data now to judge how much hardware would be needed if we deploy a large scale comet system for Last.fm. Even a worst case of 40KB per connection isn’t unreasonable &#8211; memory is pretty cheap at the moment, and 40GB to support a million users is not unreasonable. 10GB is even better. I will finish up the app I’m building and deploy it somewhere people can try it out. Along the way I’ll tidy up the erlang memcached client I’m using and release that (from jungerl, with modifications for consistent hashing and some bug fixes), and some other things. Stay tuned <img src='http://erlang-china.org/wordpress/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>update: 全文转完，关于 erlang / linux / tcp tuning 这是一个绝佳的系列文章，极具参考价值。</p>
<p>thanks you Richard Jones!</p>
]]></content:encoded>
			<wfw:commentRss>http://erlang-china.org/misc/comet-and-erlang-a-perfect-match.html/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
	</channel>
</rss>

