
<?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/"
	
	xmlns:georss="http://www.georss.org/georss"
	xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
	>

<channel>
	<title>Infrastructure | monolog</title>
	<atom:link href="https://blog.monora.me/category/infrastructure/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.monora.me</link>
	<description>monora log #=&#62; ものろーぐ</description>
	<lastBuildDate>Tue, 26 Jul 2022 18:54:42 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.0.1</generator>
<site xmlns="com-wordpress:feed-additions:1">21279848</site>	<item>
		<title>ISUCON12 予選に参加しました (最終スコア15532点)</title>
		<link>https://blog.monora.me/2022/07/participated-in-isucon12-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=participated-in-isucon12-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Tue, 26 Jul 2022 18:01:43 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=2405</guid>

					<description><![CDATA[<p>2022年7月23日 (土) に開催された ISUCON12 の予選に「DJ起床失敗とMC布団 w/o MC布団」として id:h-otter と参加しました。 言語は Go、最終スコアは15532点、参考スコアを上から [&#8230;]</p>
The post <a href="https://blog.monora.me/2022/07/participated-in-isucon12-qual/">ISUCON12 予選に参加しました (最終スコア15532点)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>2022年7月23日 (土) に開催された ISUCON12 の予選に「DJ起床失敗とMC布団 w/o MC布団」として <a href="https://h-otter.hatenablog.jp/">id:h-otter</a> と参加しました。</p>



<p>言語は Go、最終スコアは<strong>15532点</strong>、<a href="https://isucon.net/archives/56838276.html">参考スコア</a>を上から数えると<strong>45位</strong>だったようです。悔しい。<br />具体的な取り組みは下の方で述べますが、MySQL移行はバグなく完遂し、さてここからチューニングしていくぞ！という感じのところで終わりました。エンジンが掛かるまでの速度が足りなかった。</p>



<figure class="wp-block-image size-large"><img width="640" height="342" src="https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-640x342.jpg" alt="" class="wp-image-2412" srcset="https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-640x342.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-320x171.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-200x107.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-768x411.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a-1536x822.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/821f8740d91c148254ae8f29eb6f836a.jpg 1686w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>毎回、運営の皆様にはいくら感謝しても足りませんが、今回も取り組みがいのある問題で楽しかったです。ベンチマーカーも最後まで待ち時間がほぼなく、スコアも安定していたのでとてもストレスフリーでした。ありがとうございました。</p>



<p>マルチテナントで大量の SQLite3 データベースがあることが分かったとき、ISUCON本を読んだだけの人間には解かせないってことね!と思いながらニコニコしました。</p>



<p>ところで知り合いがたくさん著者に名を連ねている<a href="https://amzn.to/3J29GVW">ISUCON本</a>ですが、予選の2週間前に購入し、予選開始1時間前に部屋から発掘されました。<br />30分ぐらいで流し読みしたのですが、大変実利的な内容に溢れているなあと感じました。nginx の upstream で keep-alive を有効にする方法は知らなかった……</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="ja" dir="ltr">今日までに読もうと思って積んでいた本です。今日発見しました <a href="https://t.co/RSsbxMkoFD">pic.twitter.com/RSsbxMkoFD</a></p>&mdash; kyontan (@sukukyon) <a href="https://twitter.com/sukukyon/status/1550642844624617473?ref_src=twsrc%5Etfw">July 23, 2022</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<span id="more-2405"></span>



<h3>9:00 起床</h3>



<p>前日も早く寝るぞと自分に言い聞かせながら4時半まで起きてしまい、念には念で8時に掛けた目覚ましが1時間鳴っていました。すでにこの時点で心も体も終わっています。</p>



<p>部屋の隅にISUCON本が積まれているのを発見しました。<a href="https://amzn.to/3PxJipt">ちいとぽ</a>も積まれています。<br />h-otterと合流するために移動しつつ、パラパラと眺めます。</p>



<h3>10:00</h3>



<p>まだ合流のため移動中ですが予選が始まっているようです</p>



<h3>10:05</h3>



<p>合流しました。 CloudFormation テンプレートを流します</p>



<h3>10:22 初回スコア 2732</h3>



<p>起動したのでベンチを回しました。この時点で分担も何も決まっていません。</p>



<p>とりあえず kataribe を入れたり pt-query-digest を入れたりします。<br />「そういえば先日の社内ISUCONで Cloud Profiler 便利だったな……」みたいなことを思いながら、入れ方を調べます。<br />GCPプロジェクトが必要らしいので作ったり、サービスアカウントキーを発行したりします。予選始まってからやることではない。</p>



<h3>11:30ごろ</h3>



<p>Cloud Profiler を入れたので眺めました</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="251" src="https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-640x251.jpg" alt="" class="wp-image-2406" srcset="https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-640x251.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-320x126.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-200x79.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-768x302.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-1536x603.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/3aa8c1532fe9417aa4141a1860fd5623-2048x804.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /><figcaption>SQLite だね〜という感想。</figcaption></figure>



<h3>12:00</h3>



<p>h-otter が MySQL 対応の実装を終わらせて、「Uber eatsでも呼ぶか〜」と言いながら、なぜか歩いてマクドナルドに飯を買いに行きます。なんで??</p>



<h3>13:03 MySQL移行 3023点</h3>



<p>MySQL移行が一段落します。今思うと速かった。</p>



<p>sqlite から SQL をダンプしてゴニョゴニョやり始めて十分程度経ったあと、 <code>sqlite3-to-sql</code> って名前のスクリプトあるけど?? と気付いて笑ってました。先に気付こうね。</p>



<p>とりあえず MySQL に流し込むこと数分、INSERT が一向に終わらないことに気が付きます。このままでは <code>POST /initialize</code> がタイムアウトしてしまうため、バルクインサートをするクエリに書き換えることにしました。</p>



<p>sed で気合でバルクインサートに書き換えましたが遅い。ここで1台目のインスタンスがメモリを食いつぶして死にます。160万件のINSERTを一発でやると死ぬことが分かる。<br />先日の社内ISUCONでもインスタンスのメモリを食いつぶしたんだよな……と思いながら1台目を捨てます。</p>



<p>これが答えです。</p>



<pre class="wp-block-code"><code>for i in `seq 1 100`; do echo $i; mv $i.sql $i.sql.bak; sed -z -e "s/);\n/);\n\n/" -e "s/NULL\n);/NULL\n);\n\n/g" -e "s/);\nINSERT INTO &#91;a-z_]* VALUES/)\n,/g" $i.sql.bak &gt; $i.sql; done</code></pre>



<figure class="wp-block-image size-large is-resized"><img loading="lazy" src="https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-640x302.jpg" alt="" class="wp-image-2408" width="640" height="302" srcset="https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-640x302.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-320x151.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-200x95.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-768x363.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-1536x726.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/7a8c7f354c775e1cf36854c39890c9ae-2048x968.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>それなりに早くなりましたが、まだ遅いので tenant の player_score テーブルにおいて、 updated_at が一定以上のレコードを DELETE する作戦に切り替えます。これで10秒程度で POST /initialize が通るようになりました。</p>



<pre class="wp-block-code"><code>DELETE FROM tenant_X.player_score WHERE updated_at &gt; 1654041599;
DROP TABLE tenant_X.competition;
DROP TABLE tenant_X.player;</code></pre>



<p>他のチームの参加記を読んだら 「<code>/var/lib/mysql</code> をコピーする」「毎回 mysqldump を実行する」みたいな筋肉実装が多くて震えました……</p>



<p>確かここらへんで h-otter がなぜか flock を倒す実装を書くもベンチがコケました。<br />「そこはボトルネックじゃないっぽいし一旦revertしよ?」と、人の競技中の努力を無に帰すような心無い発言をしました。ごめんなさい。</p>



<p>なぜかここからしばらく無の時間が続きます。なぜ……</p>



<h3>15:20 3758点</h3>



<p>h-otter が competitionRankingHandler の N+1 を潰したようです。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="323" src="https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-640x323.png" alt="" class="wp-image-2410" srcset="https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-640x323.png 640w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-320x161.png 320w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-200x101.png 200w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-768x388.png 768w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-1536x775.png 1536w, https://blog.monora.me/wp-content/uploads/2022/07/e8db1bd829ae516c4856e01202912365-2048x1033.png 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>15:50 6336点</h3>



<p>グッとクエリを睨んで indexを追加。<code>playerAddHandler</code> がかなり速くなりました。</p>



<pre class="wp-block-code"><code>ALTER TABLE visit_history ADD INDEX (competition_id, player_id, created_at);
ALTER TABLE visit_history ADD INDEX (created_at);
ALTER TABLE tenant_X.player_score ADD INDEX (competition_id, player_id, row_num DESC);</code></pre>



<p>マルチテナントのDBをそのまま持ってきたので、tenant_id は無視するようにしました。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="225" src="https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-640x225.jpg" alt="" class="wp-image-2411" srcset="https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-640x225.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-320x112.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-200x70.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-768x270.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-1536x539.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/972569bfa063fe01a93c6e5a51327b27-2048x719.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>16:08 7923点</h3>



<p>h-otter が <code>playerHandler</code> の N+1 を潰したようです。</p>



<p>そして <code>player_score</code> に index を追加。<br /><code>ALTER TABLE player_score ADD INDEX (player_id, competition_id);</code></p>



<p>バルクインサートと、JSONシリアライザの変更(encoding/json → <a href="https://github.com/goccy/go-json">goccy/go-json</a>)をした結果、スコアがやや増加しました。(8269点)</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="175" src="https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-640x175.jpg" alt="" class="wp-image-2415" srcset="https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-640x175.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-320x88.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-200x55.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-768x210.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-1536x420.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/d402be907bf0ee74f9251569549ca330-2048x560.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>16:36 10253点</h3>



<p>なんかヤバそうな実装の dispenseId を倒しました。1万点突破。<br />よくわからんけど順序保証されてたほうが良さそうな気がしたので、 time.Now().UnixNano() を文字列にしてそのまま突っ込みました。爆速。</p>



<p>たしかこのあたりで、 tenant の <code>player_score</code> は <code>(tenant_id, competition_id, player_id)</code> ごとに最新の1行だけあればいいことに h-otter が気付きましたが、あまり速くならず。<br />この時点で row_num に関する index を落とすべきでした。</p>



<p>既存の <code>tenant_{1..100}</code> に対してもそれを適用しましたが、スコアとしては特に変化なしでした。</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="188" src="https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-640x188.jpg" alt="" class="wp-image-2414" srcset="https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-640x188.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-320x94.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-200x59.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-768x226.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-1536x452.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/69e135768348aefdc430576563a0b8fb-2048x602.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<p>このあたりでベンチマーカのログから、タイムアウトでユーザーが減ったという表示がなくなり、ようやくISUCON始まったな! という気持ちになります。すでに手遅れ。</p>



<h3>17:03 12505点</h3>



<p>h-otter が jwt のパース結果をキャッシュします。神</p>



<figure class="wp-block-image size-large"><img loading="lazy" width="640" height="236" src="https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-640x236.jpg" alt="" class="wp-image-2417" srcset="https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-640x236.jpg 640w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-320x118.jpg 320w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-200x74.jpg 200w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-768x283.jpg 768w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-1536x566.jpg 1536w, https://blog.monora.me/wp-content/uploads/2022/07/8b40f5fa7a5b915e094f0c19106aaaf3-2048x754.jpg 2048w" sizes="(max-width: 640px) 100vw, 640px" /></figure>



<h3>17:45 14363点</h3>



<p>app + DB の2台構成にした気がします。</p>



<h3>17:50 15962点</h3>



<p>流石にやや諦めムード。ログを切ったりできることをしました。<br />忘れずDEBUGログを切ったりスロークエリーを切ったりしました。偉い。</p>



<p>「再起動試験はしなくていいでしょ！」で終了</p>



<h2>感想</h2>



<ol><li>MySQL 移行をバグらせずに完遂できた俺達は偉い (本当に偉いと思っている)</li><li>毎回意味不明なバグを仕込んで後半暗澹たる感じにあるので、今回はほぼ最後までノーバグで駆け抜けられたのは良かった。良くも悪くも我々は大人になった</li><li>プロファイラ / スロークエリ / アクセスログの3本柱をちゃんと見ながら走れたのは本当に良かった。常に事実は正しい。fact based / metrics-driven</li><li>後半のスコアのブチ上がり方が楽しかった。というかここに来るまでを自分は第一関門を突破した段階だと思っている。やれる改善はたくさん残っていたし、あと1時間あれば更に2倍, 3倍のスコアは出ていたんだろうなと思うと悔しい</li></ol>



<p>そのほか</p>



<ol><li>午前中からの競技は本当に心も体も終了していて何も捗らなかった。ISUCONに必要なのは健康な心と身体</li><li>デカいテレビで h-otter がリゼ・ヘルエスタと名取さなの原神ガチャ配信をずっと流していた。「縁起がいいと思ったんだけどなあ」って何?</li><li>その後はリゼがパワプロしてた。リゼ・ヘルエスタについて私が知っているのは第一第二第三皇女のいずれかであるということぐらいです。</li><li>最後1時間ぐらいローテンションお嬢様 (壱百満天原サロメ)流したら集中力が0になった。何?</li></ol>



<p></p>The post <a href="https://blog.monora.me/2022/07/participated-in-isucon12-qual/">ISUCON12 予選に参加しました (最終スコア15532点)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2405</post-id>	</item>
		<item>
		<title>そろそろ Kubernetes 入門する (1)</title>
		<link>https://blog.monora.me/2021/06/sorosoro-kubernetes-1/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=sorosoro-kubernetes-1</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Mon, 21 Jun 2021 14:15:47 +0000</pubDate>
				<category><![CDATA[Cloud Native]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[n0stack]]></category>
		<category><![CDATA[Server]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=2296</guid>

					<description><![CDATA[<p>いい加減クラウドネイティブっぽいことをやりたいと言い出して早数年、世の中の流れには完全に乗り遅れた感がありますが、今更入門することにしました。 この記事を書いている時点で、すでにこのブログが構築したクラスタ上で動いている [&#8230;]</p>
The post <a href="https://blog.monora.me/2021/06/sorosoro-kubernetes-1/">そろそろ Kubernetes 入門する (1)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>いい加減クラウドネイティブっぽいことをやりたいと言い出して早数年、世の中の流れには完全に乗り遅れた感がありますが、今更入門することにしました。</p>



<p>この記事を書いている時点で、すでにこのブログが構築したクラスタ上で動いているところまでは来ていますが、ゆっくり備忘録がてらまとめていくことにします。</p>



<p>ただkubeadmでシングルノードで立てても面白くないよね、ということで、色々と試してみることにしました。</p>



<ol><li>実験のしやすさを考慮して<strong>VMの上に建てる</strong><ol><li>VM基盤は n0stack を使う</li></ol></li><li>可能な範囲でちゃんと<strong>冗長化する</strong></li><li>ちゃんと<strong>アプリケーションを乗っける</strong></li><li>完全な<strong>お遊び用のクラスタは別に作る</strong></li></ol>



<p>あたりを基本方針にしました。</p>



<h3>ホストについて</h3>



<p>さて、まずサーバはどうするかという問題がありました。現代なので冗長化するなら3台欲しいので、お手軽かつ高速なマシンが3台必要でした。</p>



<p>また、過去にも同じことをやろうとして、<a href="https://akiba-pc.watch.impress.co.jp/docs/wakiba/find/1088686.html">秋葉原で安く売っていたサーバ</a>(通称赤鯖)を3台買ってはいましたが、CPUもRAMも足りない &amp;&amp; ファンの音がうるさいということで放置されて早3年が経過したので、次は静かなマシンが良かったわけです。</p>



<p>というわけで安くて速くて静かでRAMが積めるマシンを検討した結果、 <a href="https://kakaku.com/item/K0001307634/?cid=shop_google_dsa_00010001_direct&amp;gclid=CjwKCAjw8cCGBhB6EiwAgOReyxZcWi0C0wSqHRzfkyFRluRvWuDv91OxBaqiQAZwCQ9ZlUKHZtgU9BoCqs4QAvD_BwE">Lenovo の M75q Tiny Gen2</a> を購入しました。定番ですね。Ryzen 7はコアが多くて速い。<br />ただ、予算の都合でまだ2台しか買えてません。</p>



<p>購入後の感想ですが、静かで小さいので自室の足元に置いても気にならずかなり満足しています。CPU使うと流石にファン回って気になりますけどね。</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="ja" dir="ltr">LenovoのUEFI、レガシーな見た目のままマウスカーソルが出てくるの面白いな <a href="https://t.co/8gnOWiTasF">pic.twitter.com/8gnOWiTasF</a></p>&mdash; kyontan (@sukukyon) <a href="https://twitter.com/sukukyon/status/1382987513598382081?ref_src=twsrc%5Etfw">April 16, 2021</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p>一方で、色々構築をすすめるにつれ、ストレージが256GBだと足りないか? と思うことがあり、SATAのSSDを追加することを検討しています。<br />ストレージ足すなら別に小さい必要はなかったのでは……という気持ちがあり、 <a href="https://kakaku.com/item/K0001314866/">V55t Mini-Tower</a> とかでも良かったのでは……という気持ちに。計画性がない。</p>



<p>ストレージをどうするか問題は常に付きまといますね。後述するかもしれませんが、現在は、このクラスタとは別に以前から運用していた FreeBSDサーバに刺さっている雑なディスクをミラーリングしてNFS共有しています。RDBMSとかやろうとするとiSCSIの方が良いかもしれない……</p>



<p>OSは雑に Ubuntu 20.04 Server を選択。</p>



<h3>n0stack</h3>



<p>今回のVM基盤です。別にlibvirtでもOpenStackでもなんでも良いのですが、構築が楽 &amp; 動作が軽くて、コードはなんとなく分かるので気になったら自分で直せるし、ぐらいの気持ちで選択しました。</p>



<p>n0tsack は 友人の @h-otter が主となって開発していて、過去には ICTトラブルシューティングという大会で数百VM規模で動いた実績があります。紹介記事は本人が書いてるので読んでください。</p>



<blockquote class="wp-block-quote"><p>n0stackの紹介 &#8211; h-otterの備忘録</p><cite>https://h-otter.hatenablog.jp/entry/2019/09/22/164251</cite></blockquote>



<p><a href="https://github.com//n0stack/n0stack">https://github.com//n0stack/n0stack</a> を眺めて、 n0core と n0cli があれば動くことが分かったので適当にやります。</p>



<p>VMを起動する/管理する本体である n0core は、全体の管理をする api とQEMU等を制御する agent からなります。<br />データストアは api にいて、デフォルトでは設定不要の LevelDB を使用します。LevelDB は特にデーモン等が不要のDBで、api が動くホストの <code>/var/lib/n0core</code> あたりに勝手に保存されます。<br />冗長化したければ etcd も使えます、が構築時点では<br />etcd or LevelDB を使っていて、デフォルトだと LevelDB を使うので、特にDBの設定は不要です。雑に <a href="https://github.com//n0stack/n0stack#deploy-all-in-one">GitHub の README</a> を見てデプロイします。</p>



<p>VMのセットアップはあまり考えずに<a href="https://docs.n0st.ac/en/master/user/usecases/boot_vm_from_iso.html" title="https://docs.n0st.ac/en/master/user/usecases/boot_vm_from_iso.html">ドキュメント</a>を参照すれば良い、と思いきやハマりました。QEMUの仕様が変わったらしい? <a href="https://github.com/n0stack/n0stack/pull/239">https://github.com/n0stack/n0stack/pull/239</a> で解決。そのうちマージします。</p>



<p>適当な Ubuntu が起動することを確認したところで一旦ここまで。(ホスト名は k8s-0X だが別に Kubernetes は動いていない)</p>



<figure class="wp-block-embed is-type-rich is-provider-twitter wp-block-embed-twitter"><div class="wp-block-embed__wrapper">
<blockquote class="twitter-tweet" data-width="550" data-dnt="true"><p lang="ja" dir="ltr">GW1日目の成果です <a href="https://t.co/8NY30hSQ4e">pic.twitter.com/8NY30hSQ4e</a></p>&mdash; kyontan (@sukukyon) <a href="https://twitter.com/sukukyon/status/1390780779911802884?ref_src=twsrc%5Etfw">May 7, 2021</a></blockquote><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
</div></figure>



<p><br /></p>The post <a href="https://blog.monora.me/2021/06/sorosoro-kubernetes-1/">そろそろ Kubernetes 入門する (1)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2296</post-id>	</item>
		<item>
		<title>Cisco IOS で tftp を使ったアップロードが Permission denied で怒られる件</title>
		<link>https://blog.monora.me/2020/05/permission-denied-during-tftp-upload-from-cisco-ios/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=permission-denied-during-tftp-upload-from-cisco-ios</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Wed, 13 May 2020 07:52:24 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Cisco IOS]]></category>
		<category><![CDATA[Network]]></category>
		<category><![CDATA[tftpd]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=2021</guid>

					<description><![CDATA[<p>家の回線をv6プラスにしたところ、外側から特定のポートへアクセスさせたいような用途、つまりこのブログを自宅サーバーから提供することができないことに変更してから気が付いた。 しばらくは FreeBSD で PPPoE を終 [&#8230;]</p>
The post <a href="https://blog.monora.me/2020/05/permission-denied-during-tftp-upload-from-cisco-ios/">Cisco IOS で tftp を使ったアップロードが Permission denied で怒られる件</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>家の回線をv6プラスにしたところ、外側から特定のポートへアクセスさせたいような用途、つまりこのブログを自宅サーバーから提供することができないことに変更してから気が付いた。<br />
しばらくは FreeBSD で PPPoE を終端して遊んでいたが、うっかりご家庭用のルータであるところの Cisco C891FJを買ってしまった。</p>
<p>とりあえずIOSのバックアップをすべく <code>copy</code> コマンドで自宅のサーバへ IOS をアップロードしようとした。しかし、Permission denied と怒られてアップロードに成功しなかった。</p>
<p>tftp (具体的には tftpd-hpa) サーバでの <code>tftp 127.0.0.1</code> によるアップロード/ダウンロードはできる。何かがおかしい……</p>
<p><span id="more-2021"></span></p>
<h3>状況を整理</h3>
<p>tftpd は <code>0.0.0.0:69/udp</code> で listen している。 (<code>systemctl start</code> で動かない問題もあったが、それはまた別の問題)</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false"># sudo lsof -i:69
COMMAND    PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
in.tftpd 29780 root    4u  IPv4 xxxxxxx      0t0  UDP *:tftp
in.tftpd 29780 root    5u  IPv6 xxxxxxx      0t0  UDP *:tftp
</pre>
<p>tftpd root は <code>/srv/tftpboot</code>。こういう挙動をする。</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false"># tftp 127.0.0.1
tftp&gt; get something
Error code 2: Only absolute filenames allowed
tftp&gt; get /something
Error code 2: Forbidden directory
tftp&gt; get /srv/tftpboot/something
Received 7 bytes in 0.0 seconds
</pre>
<p>IOSでのエラーメッセージはこんな感じ。tftpd は verbose フラグを付けてもだんまり。</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">#copy flash:c800-universalk9-mz.SPA.153-3.M3.bin tftp://10.0.0.1/srv/tftpboot/ios/
Address or name of remote host [10.0.0.1]?
Destination filename [srv/tftpboot/ios/c800-universalk9-mz.SPA.153-3.M3.bin]?
%Error opening tftp://10.0.0.1/srv/tftpboot/ios/c800-universalk9-mz.SPA.153-3.M3.bin (Permission denied)
</pre>
<p>なるほど……?</p>
<h3>解決方法</h3>
<p>ホスト名とパスの間にもう1つ <code>/</code> を足せばよい。つまり <code></code><code>tftp://[ホスト名]</code><strong>/</strong><code>/パス</code> とすればよい。</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-linenumbers="false">#copy flash:c800-universalk9-mz.SPA.153-3.M3.bin tftp://10.0.0.1//srv/tftpboot/ios/
Address or name of remote host [10.0.0.1]?
Destination filename [/srv/tftpboot/ios/c800-universalk9-mz.SPA.153-3.M3.bin]?
!!!!!!!!!!!!!!(snip)!!
68176296 bytes copied in 129.832 secs (525112 bytes/sec)
</pre>
<p>気付いたきっかけは Destination filename の確認プロンプトだが、まさかこんなところでハマるとは思わなかった。<br />
自宅インフラはトラブルシューティングが99%</p>
<hr />
<p>最近はご家庭用の Wi-Fi AP であるところの Meraki Go も導入したが、こちらはコンソールに入る必要がないどころかそもそもコンソールポートが存在しない。<br />
なんならインターネットに接続しないと初期セットアップすらできないし、Web設定画面はおまけでメインの設定は iOS / Android アプリから行うハイテク仕様。これがクラウドネイティブアクセスポイントってやつか〜</p>
<p>必要十分に高速で、かつ最高に安定している。おすすめです。</p>
<p>&nbsp;</p>
<p><iframe style="width: 120px; height: 240px;" src="https://rcm-fe.amazon-adsystem.com/e/cm?ref=tf_til&amp;t=monora09-22&amp;m=amazon&amp;o=9&amp;p=8&amp;l=as1&amp;IS1=1&amp;detail=1&amp;asins=B07SGXPBGJ&amp;linkId=1819d3006f307907ac651c2d495cac8e&amp;bc1=ffffff&amp;lt1=_top&amp;fc1=333333&amp;lc1=0066c0&amp;bg1=ffffff&amp;f=ifr" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"><br />
</iframe></p>The post <a href="https://blog.monora.me/2020/05/permission-denied-during-tftp-upload-from-cisco-ios/">Cisco IOS で tftp を使ったアップロードが Permission denied で怒られる件</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2021</post-id>	</item>
		<item>
		<title>ISUCON9 予選の参加ログ (チーム: 再起動非対応)</title>
		<link>https://blog.monora.me/2019/09/reboot-not-supoprted-at-isucon9-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=reboot-not-supoprted-at-isucon9-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 08 Sep 2019 13:44:34 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1998</guid>

					<description><![CDATA[<p>こんばんは、kyontanです。 前回再起動試験で落ちたのでチーム「再起動非対応」で参加しました。ベストスコアは4410点でした。再起動試験までたどり着けなかった……悔しい…… チーム「再起動非対応」は同期3人 (自分  [&#8230;]</p>
The post <a href="https://blog.monora.me/2019/09/reboot-not-supoprted-at-isucon9-qual/">ISUCON9 予選の参加ログ (チーム: 再起動非対応)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんばんは、kyontanです。</p>
<p><a href="https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/">前回</a>再起動試験で落ちたのでチーム「再起動非対応」で参加しました。ベストスコアは<strong>4410点</strong>でした。再起動試験までたどり着けなかった……悔しい……</p>
<p>チーム「再起動非対応」は同期3人 (自分 @kyontan, <a href="https://hogashi.hatenablog.com/">@hogashi</a>, <a href="https://h-otter.hatenablog.jp/">@h-otter</a>) での参加でした。学生は2人いたはずですがエントリーをミスったので学生は1人ということになっています。</p>
<p><span id="more-1998"></span></p>
<h3>使用した言語</h3>
<p>私はRubyが一番得意だと思っていますが、非同期処理が書きやすいとか型が着いていると嬉しい、みたいなことはあり今回も<strong>Go</strong>言語です。<br />
でも今回はN+1潰すときの型マッピングで無駄に時間を溶かしてしまったので、Rubyの方が良かったかもしれない……つらい……</p>
<h3>開始前の準備</h3>
<p>Prometheus/Grafana等のサーバの設定を @h-otter にお願いしました。前回のコードを読み返しつつ、何をしたかを思い出すなどした。</p>
<p>時間がなくて完全に忘れてしまいましたが、せめて練習はやっておくべきでしたね…</p>
<p>あと、 Alibaba Cloud の UI が色々不思議な感じで良かったですね。</p>
<h3>本番</h3>
<p>完全に正解していますが、今回はマイクロサービス問だということに気が付いたのは開始してからだいぶ経ってからでした。</p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr">開始30分前、チームメイトとの雑談「今日は何がでるかなー」「フリマアプリかオークションかそういうやつでしょ」「マイクロサービスとかね」「わかる〜」 <a href="https://twitter.com/hashtag/isucon?src=hash&amp;ref_src=twsrc%5Etfw">#isucon</a></p>
<p>&mdash; kyontan@新刊はまだ (@sukukyon) <a href="https://twitter.com/sukukyon/status/1170651769401069568?ref_src=twsrc%5Etfw">September 8, 2019</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>今回できたことが異常に少ない気がする。kataribeのログを眺めつつ、チームでやったことは以下のことです。比較的時系列だけどそうでない部分もあるかも。</p>
<ul>
<li>開始スコアは <strong>2310</strong></li>
<li>10:30 メモリ多いな〜って思っていたら2, 3台目のインスタンスタイプを間違えていたことに気がつく。インスタンス立て直し
<ul>
<li>コードは既にリポジトリへ追加していたのでチームメイトはルール/コードリーディングを進める</li>
</ul>
</li>
<li>10:50ごろ: 作業開始</li>
<li>11:30ごろ?: MySQL 5.7 を 8.0 へ (@h-otter)
<ul>
<li>スコア変化なし</li>
</ul>
</li>
<li>11:45 DBにインデックスを張る(@kyontan)
<ul>
<li>多分間違えていて、これらにインデックスを貼りましたがあまり効いていなかったようにみえました</li>
<li>BigQuery の触りすぎでRDBのインデックスの挙動をほぼ忘れたのも敗北ポイント</li>
</ul>
</li>
</ul>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">config (name)
items (created_at, id)
items (id)
items (buyer_id)
items (seller_id)
shippings (transaction_evidence_id)
transaction_evidences (id)
transaction_evidences (item_id)
users (account_name)
users (id)
</pre>
<ul>
<li>12:20: カテゴリをオンメモリへ (@hogas, @h-otter)
<ul>
<li><strong>2510点</strong>ぐらい</li>
</ul>
</li>
<li>12:30: http2 対応, 静的ファイルをキャッシュ, アップロードされた画像を nginx で返すなど
<ul>
<li>スコア変化なし</li>
</ul>
</li>
<li>13:30: config もキャッシュするように</li>
<li>14:00: 新着商品には発売中の商品だけを返すようにする (@hogas)</li>
<li>14:45  &#8211; 16:00: <code>GET /users/transactions.json</code><span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;"> の N+1 を潰す (@kyontan)</span>
<ul>
<li><strong>3500点</strong>ぐらい</li>
<li>なぜか色々ハマって2時間半ぐらい溶かしていた。これは敗北ポイント</li>
<li>多分ここらへんでMySQLがサチらなくなっていた気がする
<ul>
<li>CPUがサチっていたことに気が付いていたが原因が分からず (pprofをなぜ見なかったのか……)</li>
</ul>
</li>
</ul>
</li>
<li>15:30: <code>UserSimple</code> が持つ情報は全てオンメモリでキャッシュする
<ul>
<li>ユーザの存在チェックだけするような部分 (権限チェック) も基本的にこれで対応できるのでそうした</li>
<li><strong>4210点</strong>
<ul>
<li>ここからスコア上がらず……</li>
</ul>
</li>
</ul>
</li>
<li>16:00: 同じクエリを何度か叩いているエンドポイントがあったので潰す (@hogas, @kyontan)</li>
<li>16:00ごろ: transactions 以外詰まってないしCPUに余裕があるので campaign (負荷レベル)を弄ったところ外部APIで 403エラー  {&#8220;error&#8221;:&#8221;IP address is not allowed&#8221;} が連発しだす
<ul>
<li>主に<code>GET /users/transactions.json</code> <span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;">での外部 shipment  サービスへのリクエストで連発</span></li>
<li>外部APIへの403はアプリケーション的には500を返す仕様だったので、これが連発してベンチマーカが途中終了し完走しない</li>
<li>ここらへんで手詰まりに</li>
</ul>
</li>
<li>17:00: 明らかに不要な <code>SELECT FOR UPDATE</code> を削除 (4箇所+ぐらい)
<ul>
<li>これかこれの次辺りで<strong>4410点</strong>。これがベストスコア</li>
</ul>
</li>
<li>17:10: 外部APIを叩く部分で exponential backoff を実装 (@h-otter)
<ul>
<li>変化なし / 403 が連発する</li>
</ul>
</li>
<li>17:30: 外部APIをリクエストするエンドポイントだけ2台へ分散する
<ul>
<li>403 の連発は解決せず、なぜ……</li>
</ul>
</li>
<li>18:10: 最終スコア0点 (failed) で終了</li>
</ul>
<p>色々施策を打つもスコアの変化要因が今ひとつ分からず頭が回っていなかったですね。<br />
特に外部API が undocumented な 403 を返す (しかもメッセージは 「許可されていないIPアドレス」) というのは全然分かりませんでした。<br />
マイクロサービス問題なら単一IPから連続でアクセスすると弾くようになっているのかな、などと思い、後半で外部APIへリクエストをするエンドポイントだけ複数台へ分散するなどしていましたが全く解決せず泥沼へ。</p>
<p>これベンチマーカと外部API側に問題あるのでは? みたいな気持ちになりつつ、マイクロサービス問だしちゃんとbackoffとか実行すればいけるでしょ! と思っていましたが、意図したエラーだったのかは未だに分からず……</p>
<p>他の方の感想を見た限りでは、ポータルサイトへ登録されていないIPからのアクセスは弾かれるみたいですが、これについてはUI上で正しく登録されていることを確認したので問題なさそうでした。<br />
11:00 ごろにインスタンスを立ち上げ直してIPを再登録したのがポータルサイトの何らかのエッジケースを踏んだのでは? などと勝手に邪推しています。謎ですね。</p>
<p>そのほか、 campaign の値を変えると何が変わるのか (POST系アクセスが増える?)、みたいなことも終了後にログを分析してようやくなんとなく傾向がわかり悔しい気持ちに。</p>
<h3>感想</h3>
<p>終わってみれば途中重大な気付き (「外部APIのレスポンスキャッシュできるじゃん」「ユーザの嗜好に合わせて商品出し分けたら?」など) があり、見逃しの多い回でした。<br />
bcrypt の件は全く気づいておらず。前回は初手でやった(があまり意味がなかった) pprof を今回なぜ見なかったのか……</p>
<p>短い時間で追い詰められている環境の中でどれだけ集中できる / 気付けるか、というのが重要になると改めて感じました。</p>
<p>コンテストとしては今回も設定が面白く、運営の手の込みようが分かり、かつ短期間で取り組みがいのあるとても良い問題でした。<br />
運営の皆様、大変お疲れさまでした。</p>The post <a href="https://blog.monora.me/2019/09/reboot-not-supoprted-at-isucon9-qual/">ISUCON9 予選の参加ログ (チーム: 再起動非対応)</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1998</post-id>	</item>
		<item>
		<title>YubiKey 5C を買ったので ECDSA鍵で ssh した</title>
		<link>https://blog.monora.me/2019/04/bought-yubikey-5c-and-ssh-using-ecdsa-key/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=bought-yubikey-5c-and-ssh-using-ecdsa-key</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Thu, 18 Apr 2019 16:38:43 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[macOS]]></category>
		<category><![CDATA[OpenSSH]]></category>
		<category><![CDATA[YubiKey]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1944</guid>

					<description><![CDATA[<p>こんにちは。唐突に YubiKey が欲しくなったので買いました。こんなことをやっている場合ではない…… 正確には、Amazon.co.jp を見たら異常に高くてそりゃ転売したら儲かるな、という気持ちになったので、適当に [&#8230;]</p>
The post <a href="https://blog.monora.me/2019/04/bought-yubikey-5c-and-ssh-using-ecdsa-key/">YubiKey 5C を買ったので ECDSA鍵で ssh した</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんにちは。唐突に YubiKey が欲しくなったので買いました。こんなことをやっている場合ではない……</p>
<p>正確には、Amazon.co.jp を見たら異常に高くてそりゃ転売したら儲かるな、という気持ちになったので、適当に人を募って Amazon.com (US) で共同購入しました。<br />
関税や送料を足した結果、YubiKey 5 NFC が5500円, YubiKey 5C が6100円ぐらいで買えました。良かったですね。</p>
<p>YubiKey といえばそもそも OTP が出てくるキーボードとして認識されるデバイスですが、最近だと WebAuthn で使えたりしますね。あとは PKCS#11 の署名用や適当な鍵を登録できたりします。</p>
<p>雑に手元の macOS でssh するぞ、と思ったら地味にハマってしまったのでいろいろやった結果動くようになったのでメモ</p>
<p>手順だけ分かればおっけー！という方は Gist にパッチ等まとめたので、そちらを参照してください: <a href="https://gist.github.com/kyontan/763952e7be68a2e96d5c3f0ad0d3bce8">https://gist.github.com/kyontan/763952e7be68a2e96d5c3f0ad0d3bce8</a></p>
<p><span id="more-1944"></span></p>
<p>検証環境のバージョンは macOS Mojave 10.14.4 で、OpenSSH は 7.9p1, LibreSSL 2.7.3 が入っていました。<br />
ただ、今回は最終的に OpenSSH と OpenSSL は自前でビルドしたのであまり関係ありません。<br />
より重要そうな Homebrew でインストールしたパッケージのバージョンは、 OpenSSH 7.9p1, OpenSSL 1.0.2r (26 Feb 2019), OpenSC 0.19.0 です。</p>
<p>まず、下記の記事などを参考に鍵の生成を試みます。</p>
<blockquote><p>Putty CAC で SSH に YubiKey を使う(OpenSC編) &#8211; enjoy struggling<br />
<a href="https://blog.haniyama.com/2018/02/02/yubikey-ssh-opensc/"><span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;">https://blog.haniyama.com/2018/02/02/yubikey-ssh-opensc/</span></a></p></blockquote>
<p>GUI のツール (YubiKey PIV Manager) の場合は PIN を設定すると自動的に Authentication と Key Management 用の鍵を生成してくれます。現代だとデフォルトで <code>ecdsa-sha2-nistp256</code> の鍵が生成されるんですね。便利。</p>
<h2>公開鍵を取り出そうとした</h2>
<p>YubiKey へのアクセスや署名(でよいのでしょうか?) にはスマートカード等で使う OpenSC を使用するようです。今回は Homebrew でインストールしました。 (<code>brew install opensc</code>)</p>
<p>早速試してみます。まずは上の</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shellscript" data-enlighter-linenumbers="false"># ssh-keygen -D /usr/local/Cellar/opensc/0.19.0/lib/opensc-pkcs11.so
C_GetAttributeValue failed: 18
C_GetAttributeValue failed: 18
cannot read public key from pkcs11</pre>
<p>うまく行きませんね。(上手く行った場合はこの記事を読む必要はありません。最後のステップまで飛ばしてください。</p>
<h2>パッチを当てる</h2>
<p>エラー文でググると偉大な先達の記事が出てきます。今回この記事がなかったら即死していたでしょう。</p>
<blockquote><p>ssh with yubikey ECDSA keys &#8211; lithium03の物置<br />
<a href="https://lithium03.info/yubikey/index.html">https://lithium03.info/yubikey/index.html</a></p></blockquote>
<p>この記事を読むと、「RSA鍵なら問題なくいける」「OpenSSH が OpenSC を使うときに (具体的には PKCS#11 の署名等で) ECDSA鍵に対応できてない」ということが分かります。</p>
<p>親切にパッチや、そのパッチの元になったチケットまでリンクがあります。</p>
<blockquote><p>2474 – Enabling ECDSA in PKCS#11 support for ssh-agent<br />
<a href="https://bugzilla.mindrot.org/show_bug.cgi?id=2474">https://bugzilla.mindrot.org/show_bug.cgi?id=2474</a></p></blockquote>
<p>このチケットを見ると、Fedora 28 では既にこのパッチがバックポートされていること、upstream には OpenSSH 8.0 でマージされる予定であることが分かります。</p>
<p>ちなみにパッチは OpenSSH 7.6p1 用で、上の記事では 7.8p1 用に書き換えられたものが公開されていますが、現時点の Homebrew でインストール可能なのは 7.9p1 ということで、パッチを修正しました。</p>
<p>というわけでパッチです: <a href="https://gist.github.com/kyontan/763952e7be68a2e96d5c3f0ad0d3bce8">https://gist.github.com/kyontan/763952e7be68a2e96d5c3f0ad0d3bce8</a></p>
<h2>ビルドする</h2>
<p>Homebrew でパッチとかどうやるんだ……と思いましたが、どうやら <code>brew edit openssh</code> で行けるみたいです。こんなに簡単に当てられるなんて……便利だ……</p>
<blockquote><p>Homebrew: Patching an existing package<br />
<a href="https://www.ralfebert.de/snippets/brew-apply-patch-to-package-formula/">https://www.ralfebert.de/snippets/brew-apply-patch-to-package-formula/</a></p></blockquote>
<p>というわけで雑に既に書かれている <code>patch</code> の下に、以下のように追記してやるとパッチが当たります。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="ruby" data-enlighter-linenumbers="false"># Add support ECDSA for PKCS11, ref: https://bugzilla.mindrot.org/show_bug.cgi?id=2474
patch do
  url "https://gist.githubusercontent.com/kyontan/763952e7be68a2e96d5c3f0ad0d3bce8/raw/2ad5f854eba7704fbb7af2182ac57ee82b9a8f61/openssh-7.9p1-pkcs11-ecdsa.patch"
  sha256 "93b4e48321db94d785833a9414b12467a4741156cec90fa3052a4092acec8938"
end</pre>
<p>&nbsp;</p>
<p>インストールは <code>brew install --build-from-source openssh</code> です。既にインストールしてあるものがある人は <code>install</code> を <code>reinstall</code> に読み替えてください。</p>
<p>ビルドできたら、ビルドした ssh や ssh-keygen のパスをよしなに通してやります。勝手に通ってるかもしれません。(<code>rehash</code> なりしてから <code>ssh -V</code> の結果を見るとかすれば分かると思います)</p>
<p>うおおおおお！！！！</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shellscript" data-enlighter-linenumbers="false"># ssh-keygen -D /usr/local/Cellar/opensc/{version}/lib/opensc-pkcs11.so
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBDnIbZ4ANu...
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBv0e8HKnx...
</pre>
<p>というわけで公開鍵が見られました。2つ見えたのは、上で自動的に作られると行っていた Authentication と Key Management 用の鍵がどちらも見えてるからだと思います。普通は上の方を使えば良いはずです。</p>
<p>鍵を登録して、<code>ssh</code> していきます。 <code>ssh -I /usr/local/Cellar/opensc/{version}/lib/opensc-pkcs11.so host</code> です。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="shellscript" data-enlighter-linenumbers="false"># ssh -v -I /usr/local/Cellar/opensc/0.19.0/lib/opensc-pkcs11.so user@xxx.monora.me
OpenSSH_7.9p1, OpenSSL 1.0.2r  26 Feb 2019
...
debug1: Connection established.
debug1: provider /.../opensc-pkcs11.so: manufacturerID &lt;OpenSC Project&gt; cryptokiVersion 2.20 libraryDescription &lt;OpenSC smartcard framework&gt; libraryVersion 0.19
debug1: provider /.../opensc-pkcs11.so slot 0: label &lt;Yubico PIV Authentication&gt; manufacturerID &lt;piv_II&gt; model &lt;PKCS#15 emulate&gt; serial &lt;...&gt; flags 0x40d
debug1: have 1 keys
debug1: have 2 keys
...
debug1: Will attempt key: /.../opensc-pkcs11.so ECDSA SHA256:nr/MvmFI6cYmChV97dMVIBeE2Uq5UmhVvoIdIuayLvg token
debug1: Will attempt key: /.../opensc-pkcs11.so ECDSA SHA256:Z7dluZC4FCEsUAC0HYiITr5+I83bLtHUxOwdla81Rtc token
...
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering public key: /.../opensc-pkcs11.so ECDSA SHA256:nr/MvmFI6cYmChV97dMVIBeE2Uq5UmhVvoIdIuayLvg token
debug1: Server accepts key: /.../opensc-pkcs11.so ECDSA SHA256:nr/MvmFI6cYmChV97dMVIBeE2Uq5UmhVvoIdIuayLvg token
Enter PIN for 'Yubico PIV Authentication':
debug1: Authentication succeeded (publickey).
Authenticated to xxx.monora.me ([xxx.yyy.zzz.www]:22).
...
# sl
...
</pre>
<p>というわけで ssh 出来ました。嬉しいですね。</p>
<p>パッチを見て当ててみたらエラーが出た瞬間にやる気をなくして、うだうだやっていたら3時間ぐらい掛かってしまいましたが、なんとか動いてよかったです。</p>
<p>それでは皆さまもハッピーYubiKeyライフをお過ごしください！</p>The post <a href="https://blog.monora.me/2019/04/bought-yubikey-5c-and-ssh-using-ecdsa-key/">YubiKey 5C を買ったので ECDSA鍵で ssh した</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1944</post-id>	</item>
		<item>
		<title>ISUCON8 予選に参加して再起動試験に落ちました</title>
		<link>https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=failed-reboot-test-in-isucon8-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 16 Sep 2018 12:35:11 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1864</guid>

					<description><![CDATA[<p>おはようございます。名取さなにハマっている kyontan です。 チーム「hhkb」で同期3人 (自分 @kyontan, @hogashi, @h-otter) 2回目の参加で2日目で Go 実装でした。学生枠突破な [&#8230;]</p>
The post <a href="https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/">ISUCON8 予選に参加して再起動試験に落ちました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>おはようございます。名取さなにハマっている kyontan です。<a href="https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129.png"><img loading="lazy" class="aligncenter wp-image-1867 size-medium" src="https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129-320x218.png" alt="" width="320" height="218" srcset="https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129-320x218.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129-200x136.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/a5a52fbc5d024df5c788b1f71ee6d129.png 414w" sizes="(max-width: 320px) 100vw, 320px" /></a></p>
<p><figure id="attachment_1879" aria-describedby="caption-attachment-1879" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de.png"><img loading="lazy" class="size-large wp-image-1879" src="https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-640x502.png" alt="" width="620" height="486" srcset="https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-640x502.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-200x157.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-320x251.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/b3747e99d8a088593e5290ae549054de-768x603.png 768w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1879" class="wp-caption-text">最終スコア</figcaption></figure></p>
<p>チーム「hhkb」で同期3人 (自分 @kyontan, @hogashi, @h-otter) 2回目の参加で2日目で Go 実装でした。学生枠突破ならずでした、悔しい。というよりは <strong>55,982点</strong>で全体4位の点数で落ちました。ちなみに hhkb は h-otter, hogashi, kyontan, :boom: ???? の略です。<br />
スキルセット的には、 @h-otter がインフラ(ミドルウェア含)なんでもできる+Goの経験が一番あるマンで、 @hogashi がアプリケーションなんでもできるマンで、 @kyontan はアプリとインフラとDBを一通り見られるマンみたいな感じでした。</p>
<p>今回の参加に向けて、取り組んだことをつらつらと書きます。</p>
<p><span id="more-1864"></span></p>
<p>今回は真面目に本戦に行きたかったので前々日に ConoHa で ISUCON7 の予選を解き直して練習しました。具体的には ConoHa の練習用イメージを使って 1GBプラン x3台で予選環境を再現しました。結果、10時間程度で 5,204点から509,190点まで持っていけることが分かり、計測と試行の反復を効率的に行えば ISUCON の予選は突破できるという確信を深めていました。<br />
また、前回は最後の最後でベンチマーカを走行させた結果点数が下がって落ちたので、前回の直後に「泣きの1回はやらない」というスローガンを掲げ、1年越しでそれを達成しました。</p>
<p><figure id="attachment_1875" aria-describedby="caption-attachment-1875" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2018/09/score_init.png"><img loading="lazy" class="wp-image-1875 size-large" src="https://blog.monora.me/wp-content/uploads/2018/09/score_init-640x160.png" alt="" width="620" height="155" srcset="https://blog.monora.me/wp-content/uploads/2018/09/score_init-640x160.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/score_init-200x50.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/score_init-320x80.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/score_init-768x192.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/score_init.png 984w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1875" class="wp-caption-text">ベンチマークの初回走行の結果しばらく1位になった</figcaption></figure></p>
<p>事前に準備したのは Prometheus のサーバ (@h-otter がいい感じにやってくれた)と、やること/できることチェックリストぐらいでしょうか。だいたい大会では開始した瞬間にテンパってそのまま撃沈するのが常なので、思考停止状態でもコピペで動くようなコード片とかを用意しておくと便利ですね。あとは思考が無になったときに確認するべき事項とかを作っておくと良いのではないでしょうか? 頻繁に無になって帰りたくなりました。メンタルは大事。</p>
<p>例えば下のような感じです。</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3.png"><img loading="lazy" class="aligncenter size-large wp-image-1868" src="https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-640x433.png" alt="" width="620" height="419" srcset="https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-640x433.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-200x135.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-320x216.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3-768x519.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/3bbc737a859d096bd81af29e4991f3e3.png 1062w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>
<p>当日は3人がローカルで開発し、本番環境のVMへバイナリを転送して検証する、という進め方でやっていました。Go はクロスプラットフォームでのビルドがしやすいのが便利ですね。</p>
<p>具体的にやったことを羅列します。というか @h-otter が書いていたのを未承諾引用します。順番は適当</p>
<ul>
<li><code>SELECT *</code> する系のクエリを必要な列しか取らないようにした</li>
<li><code>/api/users</code> は <code>user_id</code> で <code>reservations</code> を全部とってきて、アプリ側で処理してやったらめっちゃ速くなった
<ul>
<li>ここでベンチマーカが重いと言ってくるエンドポイントが <code>/users/:id</code> から <code>/api/events/:id/actions/reserve</code> になった</li>
</ul>
</li>
<li><code>getEvent</code> を <code>getEventWithoutDetail</code> と分けた</li>
<li><code>getEvent</code> と <code>getEvents</code> を2クエリに</li>
<li><code>sheets</code> へのクエリを消す
<ul>
<li>効果があったのかは良くわからない</li>
</ul>
</li>
<li>MariaDB のチューニング</li>
<li>Prometheus と Grafana で可視化</li>
<li>ログインのクエリを1つに</li>
<li>パスワードを平文で突っ込むようにした</li>
<li>DB にインデックス張った (けどあまり良い結果がでなくてもんにょりした)
<ul>
<li>最初に <code>mysql</code> コマンドでインデックス張ったけど結果が全く変わらなくて、なぜ? と思ったら毎回 <code>/initialize</code> でテーブルを作り直していることに気がついた。</li>
</ul>
</li>
<li>IN句を使いたかったので DBにアクセスするライブラリを sqlx に切り替えた</li>
<li>トランザクションの開始がおかしいところがあったので直したり デッドロック時にエラーを返さずリトライするようにした</li>
</ul>
<p>最後は予約時のシート決定を高速化するコードが安定化しなくて入らなかったり、Redisでいい感じにやろうぜみたいなことを思うだけ思ってやらなかったりしました。多分ここができると数万点上がったはず。</p>
<p>あとはスコアに関係ないけど作業便利になる系として、 エラーログでソースコードの行番号を吐くようにしたり、 <code>Makefile</code> 弄って1コマンドでデプロイできるようにしました。<br />
開発は3台のサーバでバラバラにやっていましたがDBは1台だけを参照するようにしました。これはDBのチューニングとかがあって、1台でやった変更を他に反映したりするのが面倒くさかったので。こうすると、やりたい人間が適当にベンチマーク対象のサーバを変更して実行してやればいいので楽でした。</p>
<p>ソースコードは GitHub で管理し、いい感じにやりました。コミットログは下の通りです。</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814.png"><img loading="lazy" class="aligncenter size-large wp-image-1866" src="https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-308x640.png" alt="" width="308" height="640" srcset="https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-308x640.png 308w, https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-96x200.png 96w, https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814-154x320.png 154w, https://blog.monora.me/wp-content/uploads/2018/09/75d9b24b6f7dae18b7cdff0930e9b814.png 559w" sizes="(max-width: 308px) 100vw, 308px" /></a>数字がタグに付いていることがありますが、これはいいスコアが出た時にバイナリごとコミットしてタグつけておこうぜ、みたいな感じにした結果でした。</p>
<p>今回の僕の活躍はよく分からなくて、いい感じデバッグ担当だった気がします。PRを見るなりとりあえずマージしてベンチマーカを落としたりバグ探しをしていたりしました。とにかく @h-otter がぶち壊しつつ @hogashi がいい感じに安定化するコードを書いてくれてよかった感がある。</p>
<p>Webサーバはh2oで十分高速だし、画像のトラフィック詰まりもないしで、とにかくアプリケーションコードの改善に注力した/するしかなかった8時間でした。</p>
<p>最終的に残り30分でベンチマーカを叩いたところ3万点前後のスコアが5万点に若干跳ねてそこで打ち止め。一度再起動をしてブラウザからアクセスできることを確認し天命を待ったところ、無事再起動試験で落ち失格となりました。天命……</p>
<p>(追記: スコアが跳ねたのは、最後に実行先サーバを変えた時に インデックスを張る処理を <code>init.sh</code> に書いたサーバで実行したからかもしれないことを思い出した。)</p>
<p>なぜ失格になったのかは分かっていなくて、おそらく <code>/admin/api/reports/events/:id/sales</code> の処理が遅くて不整合が起きて落ちたのかなあなどと思っていますが、2回連続で落ちるのは運が悪かったなと……</p>
<p>なんやかんやでやることがなくならない8時間で、やることが見つからない8時間よりは良かったのではないかと思います。</p>
<blockquote class="twitter-tweet" data-width="550" data-dnt="true">
<p lang="ja" dir="ltr">ISUCONの予選に向けて昨日は練習をしていたわけだけど、知っていることをちゃんと愚直にできれば比較的現実的な時間で予選突破ラインには十分立てることが分かったので良かった</p>
<p>&mdash; kyontan@新刊はまだ (@sukukyon) <a href="https://twitter.com/sukukyon/status/1040457052307447810?ref_src=twsrc%5Etfw">September 14, 2018</a></p></blockquote>
<p><script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p>イキっているなどと言われてもこれは事実だと信じていて、典型的な N+1 を潰すなどすれば予選は通過できるはずなことは分かりましたね。くぅ〜〜</p>
<p>来年はちゃんと本選に行けたらいいですね。頑張りましょう。</p>
<p>そして、参加会場を提供していただいた mixi 様、惜敗の悔しさを教えてくれる最高のコンテストを運営をしていただいたISUCONの運営の皆様、お疲れ様でした、ありがとうございました!</p>
<p>以下は画像です</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/score_2.png"><img loading="lazy" class="wp-image-1877 size-large" src="https://blog.monora.me/wp-content/uploads/2018/09/score_2-640x141.png" alt="" width="620" height="137" srcset="https://blog.monora.me/wp-content/uploads/2018/09/score_2-640x141.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/score_2-200x44.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/score_2-320x71.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/score_2-768x170.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/score_2.png 1000w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>
<p><a href="https://blog.monora.me/wp-content/uploads/2018/09/score_3.png"><img loading="lazy" class="wp-image-1876 size-large" src="https://blog.monora.me/wp-content/uploads/2018/09/score_3-640x139.png" alt="" width="620" height="135" srcset="https://blog.monora.me/wp-content/uploads/2018/09/score_3-640x139.png 640w, https://blog.monora.me/wp-content/uploads/2018/09/score_3-200x43.png 200w, https://blog.monora.me/wp-content/uploads/2018/09/score_3-320x70.png 320w, https://blog.monora.me/wp-content/uploads/2018/09/score_3-768x167.png 768w, https://blog.monora.me/wp-content/uploads/2018/09/score_3.png 984w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>The post <a href="https://blog.monora.me/2018/09/failed-reboot-test-in-isucon8-qual/">ISUCON8 予選に参加して再起動試験に落ちました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1864</post-id>	</item>
		<item>
		<title>CoreOS で Docker Swarm クラスタを作ってみた</title>
		<link>https://blog.monora.me/2017/12/building-docker-swarm-cluster-on-coreos/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=building-docker-swarm-cluster-on-coreos</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sat, 09 Dec 2017 15:00:15 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[CoreOS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[whywaita Advent Calendar]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1717</guid>

					<description><![CDATA[<p>こんばんは。kyontanです。JobHunting 活動は順調ではないので頭を抱えています。 寒いです。12月10日です。10日ということは、 whywaita Advent Calendar 2017 の10日目とい [&#8230;]</p>
The post <a href="https://blog.monora.me/2017/12/building-docker-swarm-cluster-on-coreos/">CoreOS で Docker Swarm クラスタを作ってみた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんばんは。kyontanです。JobHunting 活動は順調ではないので頭を抱えています。</p>
<p>寒いです。12月10日です。10日ということは、 <a href="https://adventar.org/calendars/2253" target="_blank" rel="noopener noreferrer">whywaita Advent Calendar 2017</a> の10日目ということです。なんとあと1枠らしいです。</p>
<p>9日目は @kadokusei (~= @hyr3k) さんで <a href="http://hyr3k.hatenablog.com/entry/2017/12/09/032008">体重 &#8211; /var/log/</a> でした。</p>
<p>ところで文脈もなにもないですが Just Because! が良いです。小宮恵那さん……</p>
<p><span id="more-1717"></span></p>
<p>さて先日、 Twitter を眺めていたところ 「<a href="http://www.gdm.or.jp/crew/2017/1027/240884">真っ赤な“1/4Uサイズ”のブレードサーバーが税込4,980円で大量販売中</a>」  という記事が流れていました。<br />
Core i5-2520M@2.5GHz / RAM2G / Diskless という構成ですが、Intel の GbE NIC x4 があるなかなか変態なマシンです。5000円だったのでつい3台買いました。IPMI もあります。ちなみに1台当たりで RAM が 4GB でした。</p>
<p>kamijin_fanta さんという方がこれに VyOS on Hyper-V をやっている記事があるので、こちらもご参照ください。</p>
<blockquote><p><a href="https://blog.kamijin-fanta.info/2017/12/1206.php">赤鯖にVyos入れて最高のインターネッツを手に入れた</a></p></blockquote>
<p>これは <a href="https://www.atworks.co.jp/">A.T.WORKS</a> というメーカーの国産サーバで、謎です。とりあえずドキュメントとかファームウェアの更新は<a href="https://store.atworks.co.jp/download/">公式ストアのダウンロードページ</a>に転がっています。</p>
<p>何故かシャーシも付いてきたので適当に突っ込みます。10台入るので、あと7台追加できますね。とはいえ部屋の室温で冷却するにはこの程度の密度が限界かと……</p>
<p><img loading="lazy" class="aligncenter size-large wp-image-1721" src="https://blog.monora.me/wp-content/uploads/2017/12/IMG_1398-640x427.jpg" alt="" width="620" height="414" srcset="https://blog.monora.me/wp-content/uploads/2017/12/IMG_1398-640x427.jpg 640w, https://blog.monora.me/wp-content/uploads/2017/12/IMG_1398-200x133.jpg 200w, https://blog.monora.me/wp-content/uploads/2017/12/IMG_1398-320x213.jpg 320w, https://blog.monora.me/wp-content/uploads/2017/12/IMG_1398-768x512.jpg 768w, https://blog.monora.me/wp-content/uploads/2017/12/IMG_1398.jpg 1920w" sizes="(max-width: 620px) 100vw, 620px" /></p>
<p>画像の左下にある赤いやつがそれです。雑ですね。周りも汚いですね……</p>
<p>さて、ディスクレスとはいえ開けてみると SATAポートもディスクベイもあるので、2.5インチのHDDを買えば普通に使えるでしょう。<br />
しかし先立つものがなく、しかし他のサーバは余っているのでネットワークブートさせて遊んでみることにしました。</p>
<h3>PXE とは</h3>
<p>PXE とは…… ざっくりと説明するとネットワークブートのための仕組みの1つです。<br />
NIC に書き込まれたPXEブートローダが、ネットワーク上のサーバから OS のカーネルを取得して起動する方法です。</p>
<p>基本的には起動時に DHCP でIPアドレスを取得する際に、サーバが IPアドレス等の情報と一緒にカーネル等が置かれているサーバ(TFTPサーバ)のアドレスを返すことで実現されます。<br />
いわゆる大量のPCを管理する手間を減らしたい(~ シンクライアント化したい) 大学なんかでよく見かけますね。MMA部室の端末でも同様の仕組みを採用しています。<br />
<span style="font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;">もちろん一般的な誤家庭でも、DHCPサーバとTFTPサーバ等を立てれば実現できます。近年では PXE を発展させた iPXE などもあります。こちらだと例えばカーネルを通常の HTTPサーバから取得するようにできたりします。便利ですね。</span></p>
<p>実際の実現にあたっては、 「PXE 構築」なんかでググって頂ければ山のように日本語の資料がヒットしますので割愛します。</p>
<h3>Container Linux</h3>
<p>今回はこれを用いて <a href="https://coreos.com/">CoreOS Container Linux</a> を起動させ、自動的に Docker Swarm クラスタを構築したいという話をします。</p>
<p>Container Linux は CoreOS 社が開発している、コンテナ基盤のための軽量Linuxディストリビューションです。docker や etcd と言ったコンテナで用いるソフトウェアがデフォルトで入っているほか、fleet というクラスタマネージャ (というか分散 systemd) なんかがデフォルトで入っています。<br />
CoreOS 社は他にも Docker Registry の Quay やコンテナランタイムである rkt や cloud-config の代替を狙っている Ignition, エンタープライズ向け Kubernetes こと Tectonic の開発なんかもしていますね。</p>
<p>もうお察しかと思いますが、 Container Linux には fleet というクラスタマネージャがあり、更に Tectonic があります。つまり、 Docker Swarm の文脈にはかすりもしません。イケイケな皆さんは Kubernetes を構築すると便利だと思います。<br />
<small>(実は Kubernetes クラスタを構築しようとしたらオンメモリファイルシステムでは容量が足りなかったので Docker Swarm でお茶を濁しています)</small></p>
<p>CoreOS は今回のよう物理ホスト(ベアメタル)に対して直接プロビジョニングをするためのプロダクトも用意しています。 <a href="https://coreos.com/matchbox/docs/latest/">Matchbox</a> です。使ってください。<br />
今回は使いません。</p>
<h3>起動してみる</h3>
<p>CoreOS はもちろん PXE での起動に対応しており、<a href="https://coreos.com/os/docs/latest/booting-with-pxe.html">簡潔なドキュメント</a>があります。 これに従えば簡単に起動までは行なえます。やってみましょう。</p>
<p>最終的なディレクトリ構造としては以下のようになります。<br />
<code>/tftpboot</code> は適宜 tftp のルートディレクトリに読み替えてください。また、 <code>pxelinux.cfg/default</code> の内容は下に書いてあります。</p>
<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-linenumbers="false">/tftpboot
├── coreos
│   ├── coreos_production_pxe_image.cpio.gz
│   └── coreos_production_pxe.vmlinuz
├── pxelinux.0
└── pxelinux.cfg
    └── default
</pre>
<pre class="EnlighterJSRAW" data-enlighter-language="raw">default coreos
prompt 1
timeout 15

display boot.msg

label coreos
menu default
kernel coreos/coreos_production_pxe.vmlinuz
initrd coreos/coreos_production_pxe_image.cpio.gz
append coreos.first_boot=1
</pre>
<p>さて、対象のマシンは起動したでしょうか? 手元では30秒ほど OS の読み込みに掛かったあと、OS本体が約4秒で起動してくるのが観測できました。速いです。</p>
<p>ただ、おそらくログインもできず、ssh もできないでしょう。直接本体に接続されている端末にログインしたい場合は、ドキュメントにある通り、 <code>coreos.autologin</code> を設定すれば可能です。</p>
<p>実際にもうこれで fleet で遊んだりできます。この状況では、 <code>/</code>(rootfs) がメモリ上にあるので、メモリの空き容量分しか書き込むことができませんが、メモリが潤沢にあればこの上に Tectonic や kubeadm を用いて Kubernetes を構築したりもできるでしょう。ちなみに 4GB では足りませんでした。</p>
<h3>Docker Swarm</h3>
<p>Docker swarm というのは Docker 本体に取り込まれたクラスタリングの機能です。複数のノードでサービスという単位でコンテナの管理が行えます。<br />
Docker 本体に統合されているので、Container Linux に docker がデフォルトで入っているということはそのまま docker swarm mode で既存のクラスタに join させればそのままクラスタの一員となります。<br />
クラスタにはマネージャとワーカの区別があり、マネージャは Raft アルゴリズムで分散合意を行うため、本来であれば耐障害性のためにも3以上の奇数台を用意することが望ましいですが、今回は DHCP/TFTPにしたサーバをそのまま使います。</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-linenumbers="false"># docker swarm init
Swarm initialized: current node (hogefuga) is now a manager.

To add a worker to this swarm, run the following command:

    docker swarm join --token SWMTKN-1-... 10.0.xxx.yyy:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.</pre>
<p>上で表示されているコマンドを起動時に入力させればそのまま docker swarm のクラスタにジョインしてくれるでしょう。やっていきましょう。<br />
(ちなみに、デフォルトでは docker swarm のマネージャ自信もコンテナが起動するホストの1つとなります。次のコマンドを打てばそのノードではコンテナが起動しなくなります。 <code>docker node update --availability drain</code>)</p>
<h4>Ignition Config</h4>
<p>起動時に任意のコマンド等を実行する方法といえば、あの <code>cloud-config</code> がありますね……<br />
Container Linux では最近 <a href="https://coreos.com/ignition/docs/latest/">Ignition</a> というものに置き換えられました。直接書いてもいいですが、 cloud-config の記法で書いたものは <a href="https://github.com/coreos/container-linux-config-transpiler">ct</a> (<a href="https://coreos.com/os/docs/latest/overview-of-ct.html">config-transpiler</a>) というコマンドを用いて変換することができます。<br />
ちなみにオンラインの<a href="https://coreos.com/validate/">バリデータ</a>があって、 どちらの記法でもここでバリデーションができます。</p>
<p>では用意しましょう。ついでに <code>ssh</code> できるように <code>authorized_keys</code> なんかも追加できます。 <code>ssh</code> したくない? 確かに。<br />
ともかく <code>systemd unit</code> を2つ書くだけです。ところで <code>docker-swarm-leave.service</code> がちゃんと動いてない気がするのでどなたか教えてください。</p>
<pre class="lang:yaml EnlighterJSRAW" title="container-linux.config" data-enlighter-language="yaml">passwd:
  users:
    - name: core
      ssh_authorized_keys:
        - ecdsa-sha2-nistp256 ...
systemd:
  units:
    - name: docker-swarm-join.service
      enabled: true
      contents: |
        [Unit]
        Description=Docker swarm join script
        Requires=docker.service
        After=docker.service

        [Service]
        Type=oneshot
        ExecStart=/usr/bin/docker swarm join --tokenSWMTKN-1-... 10.0.xxx.yyy:2377

        [Install]
        WantedBy=multi-user.target
    - name: docker-swarm-leave.service
      enabled: true
      contents: |
        [Unit]
        Description=Docker swarm leave script
        Before=shutdown.target reboot.target halt.target

        [Service]
        Type=oneshot
        RemainAfterExit=yes
        ExecStart=/bin/true
        ExecStop=/usr/bin/docker swarm leave

        [Install]
        WantedBy=multi-user.target</pre>
<p>&nbsp;</p>
<p>さて、このファイルを実際に起動時に渡すためには <code>ct</code> で変換したり、 newc 形式のアーカイブにしたりする必要があるのでやります。</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-linenumbers="false">$ mkdir usr/share/oem
$ ct &lt; container-linux.config &gt; usr/share/oem/raw.ign
$ find usr | cpio -o -H newc -O oem.cpio
$ gzip oem.cpio
</pre>
<p>結果的にでてきた oem.cpio.gz を以下のような感じに配置します。</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-linenumbers="false">/tftpboot
├── coreos
│   ├── coreos_production_pxe_image.cpio.gz
│   ├── coreos_production_pxe.vmlinuz
│   └── oem.cpio.gz
├── pxelinux.0
└── pxelinux.cfg
    └── default
</pre>
<p>&nbsp;</p>
<p>また、 <code>pxelinux.cfg/default</code> も修正します。は以下のようになります。 <code>oem.cpio.gz</code> を読ませているのと、実際にそれを参照させている部分の2箇所です。</p>
<pre class="lang:default highlight:0 decode:true EnlighterJSRAW" title="pxelinux.cfg/default" data-enlighter-language="raw"> 
default coreos
prompt 1
timeout 15

display boot.msg

label coreos
menu default
kernel coreos/coreos_production_pxe.vmlinuz
initrd coreos/coreos_production_pxe_image.cpio.gz,coreos/oem.cpio.gz
# append console=tty0 console=ttyS1 coreos.autologin=tty0
append coreos.first_boot=1 coreos.config.url=oem:///raw.ign
</pre>
<p>さて、起動させて見ましょう。マネージャ側で <code>docker node ls</code> とか叩けば分かると思います。<br />
いい感じになりましたでしょうか?</p>
<p>あとは <code>docker service</code> コマンドでよしなにサービスを作ってやると、いい感じにロードバランスされたりヘルスチェックしたりライブアップデートできたりすると思います。<br />
ポートの公開をすると、マネージャを含む全てのノードでそのポートが共有され、自動的にロードバランスされます。つまり、そのサービスのコンテナが動いていないノードにアクセスしても、内部のトンネル(VXLANです)を通ってコンテナへの疎通性が確保されます。</p>
<p>そのあたりは「docker swarm」とかでググると出ると思います。 <code>nginx</code> とかでも簡単にできますね。</p>
<p>ところでボリュームのマウントは癖があって、 bind なんかは各ノードのローカルファイルシステムを参照します。なので、そういったことをしたい時はよしなにやりましょう。 <code>nfs</code> とかを検証できると良いですね。</p>
<p>ちなみに再起動したりするとどんどん死んでるノードが一覧に増えますが気にしないでください。気になる時は <code>docker node rm</code> で消しましょう。以下がワンライナーです。</p>
<pre class="lang:default highlight:0 decode:true nums:false" title="pxelinux.cfg/default"><code class="EnlighterJSRAW" data-enlighter-language="shell"> 
docker node ls | tail -n+2 | grep Down | cut -d' ' -f1 | xargs -r docker node rm"
</code></pre>
<p>さて、今回は簡単に Docker Swarm を用いたクラスタの構築をしてみましたが、実際により大きい規模でやろうとすると Kubernetes や DC/OS (Mesos, Marathon) なども候補に入るかと思います。<br />
そちらについてもやっていきましょう。</p>
<p>ところで Docker / CoreOS をプロダクションでバリバリ使うサービスに興味のある方向けに、 <a href="https://www.sakura.ad.jp/recruit/entry/career_29.html">こんな求人</a>や<a href="https://www.wantedly.com/projects/23766">こんな募集</a>があります。もしご興味ありましたら Twitter 等でも良いのでお声掛けください。</p>
<p>では皆様、よいコンテナライフを!</p>The post <a href="https://blog.monora.me/2017/12/building-docker-swarm-cluster-on-coreos/">CoreOS で Docker Swarm クラスタを作ってみた</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1717</post-id>	</item>
		<item>
		<title>ISUCON7 予選に参加しました</title>
		<link>https://blog.monora.me/2017/10/participated-isucon7-qual/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=participated-isucon7-qual</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 22 Oct 2017 17:29:29 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ISUCON]]></category>
		<category><![CDATA[コンテスト]]></category>
		<category><![CDATA[参加しました]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1665</guid>

					<description><![CDATA[<p>チーム「まだチーム名で消耗してるの?」で同期3人 (自分 @kyontan, @hogas, @h-otter) 初参加で2日目でした。学生枠突破ならずでした。 Ruby実装で挑み、最終スコア 38605点@2017-1 [&#8230;]</p>
The post <a href="https://blog.monora.me/2017/10/participated-isucon7-qual/">ISUCON7 予選に参加しました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>チーム「まだチーム名で消耗してるの?」で同期3人 (自分 @kyontan, @hogas, @h-otter) 初参加で2日目でした。学生枠突破ならずでした。</p>
<p>Ruby実装で挑み、最終スコア 38605点@2017-10-22 20:59:30, ベストスコア: <strong>67792点</strong>@2017-10-22 20:44:59 でした。<br />
ベストスコアでは予選ラインは超えていたんだなあと思いますが、最終的には伸び悩んだチームも多いようで、結局落ち着くところに落ち着いたのかなと思います。</p>
<p>ソースコードは <a href="https://github.com/kyontan/isucon7_qual">kyontan/isucon7_qual</a> です。踏み台でやっていた影響でコミッタが僕に見えますが、だいたい僕ではない。</p>
<p><figure id="attachment_1668" aria-describedby="caption-attachment-1668" style="width: 620px" class="wp-caption aligncenter"><a href="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart.png"><img loading="lazy" class="wp-image-1668 size-large" src="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-640x254.png" alt="" width="620" height="246" srcset="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-640x254.png 640w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-200x79.png 200w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-320x127.png 320w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart-768x304.png 768w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_chart.png 1696w" sizes="(max-width: 620px) 100vw, 620px" /></a><figcaption id="caption-attachment-1668" class="wp-caption-text">ISUCON7 予選での Score / LoadLevel の変化</figcaption></figure></p>
<p>次回も参加したいなという気持ちになってきたので、ひとまずはやったことを記していきます。</p>
<p><span id="more-1665"></span></p>
<p>実は僕と @hogas は ISUCON6 の夏期講習に出たことがありましたが、そのときには日程等もあり参加しておらずということで、今回が初参加に。<br />
@h-otter というインフラに<strong>とても強い</strong>同期がいたことや、周囲でも参加する人間が何故か多く、とにかくやっていくしかないという流れに。</p>
<p>チーム名を決めるところで消耗/摩耗し、本番前日までSlackはほとんど流れておらず。前日夜になって僕とか @h-otter がぽちぽち参加記やチューニングできそうなところを貼っていく感じに。</p>
<p>最近、正午より前に起きると早起きしたと言い出す僕が時間に間に合っていたあたりで色々とミスっていたんですが、東京都内の某所で3人で集まってやっていました。</p>
<h2>事前にやった</h2>
<p>とりあえずグローバルIPを持つ作業用サーバを用意しておいた。Rubyは事前に入れておいて、開始後に MySQL  も入れてスタンドアロンで動くようにした。あとあと @hogas はここでずっと作業してたり、 @h-otter が Prometheus のサーバを立てたりしていた。便利</p>
<p>コードについては GitHub リポジトリを立てて、普通にブランチ切ってやっていた。便利</p>
<p>情報共有は対面だったので、コードスニペット貼れるしリアルタイムで最高な HackMD を例のごとく使っていた。ベンチマーカの結果を全部ペタペタ貼っていたら容量制限に引っかかり、2スレ目、3スレ目が誕生した。HackMDのタイトルは<strong>「ISUCON7 まだチーム名で消耗してるの? 2スレ目」</strong>でした。</p>
<h2>やったこと</h2>
<p>ミドルウェアより下は正直 @h-otter に丸投げしていたので、アプリケーションより上をぽちぽち見ていました。<br />
インフラについては正直何をしたのかは全容を把握していないですが、初手で nginx や MySQL に基本のチューニングを突っ込み、Prometheus で延々と監視しながらPDCAを回していたっぽい。正しいインフラチューニングや……</p>
<p>言語は僕と @hogas が使い慣れている Ruby を選択しました。正直クエリ弄るぐらいでいいなら Go でもいいよねーって言っていましたが、慣れてるほうが便利でした。Sinatra の文字列には幼馴染のような安心感がある。</p>
<p>僕と @hogas はよしなにアプリケーションコードを読みながら色々した。以下は色々</p>
<h4>erb を haml に置き換える / hamlit gem の導入</h4>
<p>気持ち+2000点ぐらい</p>
<p>初期実装が erb で、erubis に置き換えるというのも一案ありましたが、行きの車内で「erubis hamlit 速度」などで検索した結果やっぱり hamlit かとなっており、ノータイムで haml に書き換えることを決断しました。<br />
erb2haml とかあったね〜と @hogas と話しながらやってもらった。</p>
<p>以下様子です</p>
<blockquote class="twitter-tweet" data-width="550">
<p lang="ja" dir="ltr">. <a href="https://twitter.com/hogextend?ref_src=twsrc%5Etfw">@hogextend</a> 「erb2hamlどうやって使うの?」ぼく「とりあえず rails new して突っ込んでみたら?」 <a href="https://twitter.com/hashtag/isucon?src=hash&amp;ref_src=twsrc%5Etfw">#isucon</a></p>
<p>&mdash; きょんたん (@sukukyon) <a href="https://twitter.com/sukukyon/status/922121692440182785?ref_src=twsrc%5Etfw">October 22, 2017</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<blockquote class="twitter-tweet" data-width="550">
<p lang="ja" dir="ltr">僕「ﾖｯｼｬ(gem install rails)」</p>
<p>&mdash; hogas (@hogextend) <a href="https://twitter.com/hogextend/status/922125423697305600?ref_src=twsrc%5Etfw">October 22, 2017</a></p></blockquote>
<p><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script></p>
<p><small>(erb2haml はコマンドラインツールとかではなく、Rails に追加する rake タスク群ということに気が付いた様子)</small></p>
<h4>nginx &lt;-&gt; Puma を UNIXドメインソケットに</h4>
<p>気持ち +2000点</p>
<p>定番です。HTTP 5000/tcp から UNIXドメインに変えた。</p>
<h4>SQL のクエリ改善</h4>
<p>気持ち+10000点ぐらい</p>
<p>これは定番ですね。SELECT のカラムを絞ったり (@hogas)、 <code>LIMIT</code> を付けたり (@hogas)、インデックスを張ったりした。N+1 は手を付けていましたが、コード変更に集中できなくて最終的に投げてしまった。悔しい</p>
<p>終了直前にソースコード眺めてたら <code>statement.close</code> を意図的に忘れていそうなコードが見つかり慌てて修正した。スコア上の変化は分からず。</p>
<h4> 画像を静的ファイルに書き出す</h4>
<p>気持ち+15000点ぐらい</p>
<p>ユーザーのアバター画像が DB に <code>blob</code> で入っていたので、雑に Ruby のワンライナーで書き出して (ここまで @kyontan)、 nginx に <code>try_files</code> で食わせる (@h-otter) みたいなことをした。<br />
既に話題になっていますが、最終的には <code>Cache-control</code> 的な問題でキャッシュヒット率が悪かったらしい。むむむ。</p>
<h4>SHA1 を殺す (パスワード, アバター画像)</h4>
<p>気持ち+2000点</p>
<p>パスワードのソルトを生成している <code>random_string</code> を見たときに、これは要らないのではと思ってしまったのが始まり。初期データのパスワードはハッシュ化されていたので、 <code>id</code> が1000より大きい user は全て平文パスワードを DB に突っ込んだりした。 (by @hogas)<br />
アバター画像は、ファイルの内容を SHA1 したものをファイル名に使用する実装になっていましたが、もしかしていけるのではと言いながらユーザIDをそのままファイル名にしたら通ってしまったのでそのままに。</p>
<h4>Redis (最終的に入れず)</h4>
<p>気持ち+2000点ぐらい(?)</p>
<p>画像をバイナリで入れるのはまあそうだね〜〜と言いながら、Redis に載せようとしていた。正直コードの変更は大したことがないのは分かっていたので実装はシュッとできたけれど、実際に動かしてみると意外とスコアに有意な差が出なかった。その後も永続化周りで少し足踏みしていたり、他の変更を見ていたために最終的に入れられなかった。残念</p>
<h4>アプリケーションサーバ3台化</h4>
<p>気持ち +3000点ぐらい</p>
<p>@h-otter がラスト30分でイケると言い出してやってた。ここで Puma (アプリケーションサーバ) のスレッド数を調整していた (10 -&gt; 18スレッド)時に出したのがベストスコアです。</p>
<h2>その他</h2>
<ul>
<li>再起動試験は何の問題もなかった????
<ul>
<li>過去の参加記なんかを見てるとここが関門かなというのはあったので絶対やっておきたかった (やりました)</li>
<li>Redis に手を出してなかったのでここで不安はあまりなかった</li>
</ul>
</li>
<li>MySQL の Too Many Connections が割りと頻発した
<ul>
<li>ここは <code>statement.close</code> 忘れも影響してるかなと思うけれど、500が途中で出たり安定しないことがあった。最終的には安定しました</li>
</ul>
</li>
<li>日ごろは頭痛の頭の字もないのに、とにかく頭痛が酷かった。緊張にはやはり弱い。</li>
<li>JSONシリアライザが遅いのは分かっていて、 <code>Oj</code> を入れるぞと言いながら入れるのを忘れた。あれを入れただけでシリアライズについては数倍速くなるというのは分かっていたので、ただただつらい。</li>
<li>ICTトラブルシューティングコンテストでスコアサーバを延々とやっていたことが知見として生きたとは思う。DB設計なりアプリケーション設計なりチューニングなり。
<ul>
<li>当時のオーバーキルなチューニングしたときの操作が生きることになるとは思ってなかった</li>
</ul>
</li>
<li>最後のベンチマークの結果を見て全員で嘘やんって言ってた
<ul>
<li>ルールを読んでなかった。次回は読みます</li>
<li>にゃーん</li>
</ul>
</li>
</ul>
<p>そういえば30分ほどですがスコアボードの上位に乗っていました。学生トップなのは分かっていたので、これは予選突破できるんじゃない? とか言いながら笑っていたのを覚えています。このあたりが後々ボーダーになるんだろうな〜という話をしていて、実際そうなったのである程度読みは正しかったのかなと思いつつ。</p>
<p><a href="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot.png"><br />
<img loading="lazy" class="aligncenter size-large wp-image-1676" src="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-640x259.png" alt="" width="620" height="251" srcset="https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-640x259.png 640w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-200x81.png 200w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-320x129.png 320w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot-768x311.png 768w, https://blog.monora.me/wp-content/uploads/2017/10/isucon7_best_shot.png 1968w" sizes="(max-width: 620px) 100vw, 620px" /></a></p>
<h2>総括/最高</h2>
<p>監視に強い人(@h-otter)強い。常に横で IOバウンドかネットワークバウンドか、みたいなことを見ながらアドバイスしてもらえる環境は最高。</p>
<p>限られた時間の大会という環境でもくもくとコードいじれる人(@hogas)強い。とにかく僕が頭が回ってなくてコードをまともに書けない状況にあったので、そんな中でちゃんと改善する変更を入れ続けてくれて最高。</p>
<p>基本的にどこに手を入れればいいか、この変更はコスパ的にどうかみたいなことを常に考えながら立ち振る舞えてはいたと思うので、そういった点ではなかなか善戦はできたかなと思いつつ。<br />
しかし、できたことは山のように残っているなという感想。、途中で集中力が切れてしまったこともあり、こういう結果になったのは悔しいなと思う。</p>
<p>ただ、これだけ言えるというのはつまりバランスが最高だということに他ならなくて、こういった駆け引きができるバランスのゲームを作るのはとにかく難しいなと思っているだけに最高だな！！！という気持ちです。<br />
こんな最高のコンテストを生み出してくれた運営の皆様、ありがとうございました。そしてお疲れ様でした！</p>
<p>本選に行かれる皆様はぜひとも頑張ってほしいなと思うところです。</p>
<p>&nbsp;</p>
<p>次回は最高の♨️から最高の心構えでやっていきたい。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>The post <a href="https://blog.monora.me/2017/10/participated-isucon7-qual/">ISUCON7 予選に参加しました</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1665</post-id>	</item>
		<item>
		<title>Zabbix で収集したデータを Datadog へ投げる</title>
		<link>https://blog.monora.me/2017/08/zabbix-to-datadog/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=zabbix-to-datadog</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sat, 05 Aug 2017 16:23:14 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[datadog]]></category>
		<category><![CDATA[zabbix]]></category>
		<guid isPermaLink="false">https://blog.monora.me/?p=1641</guid>

					<description><![CDATA[<p>こんにちは。これを書いているのは JST 4:30 ですが、最近は JST+0900で生きているので、昼間です。そろそろ夕方でしょうか。 最近の仕事の成果は Zabbix に投げ込む XML をエイヤで自動生成するような [&#8230;]</p>
The post <a href="https://blog.monora.me/2017/08/zabbix-to-datadog/">Zabbix で収集したデータを Datadog へ投げる</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんにちは。これを書いているのは JST 4:30 ですが、最近は JST+0900で生きているので、昼間です。そろそろ夕方でしょうか。<br />
最近の仕事の成果は Zabbix に投げ込む XML をエイヤで自動生成するような何か、もしくは SQL を生成する何かです。</p>
<p>成果物は <a href="https://github.com/kyontan/datadog-zabbix-history">kyontan/datadog-zabbix-history</a> です。</p>
<h2>長い前置き</h2>
<p>ところで皆様は Datadog を使われていますでしょうか?<br />
インフラ監視系の SaaS やソフトウェアというと、今挙げた Datadog を始め, Mackerel や Zabbix, Nagios, AWS Cloudwatch 等々、現状では様々なプロダクトが存在しています。最近だと Datadog や Prometheus の名前をよく見かける気がします。</p>
<p>そんな中最近、自分のバイト先では使われているのが <a href="https://www.datadoghq.com/">Datadog</a> です。サーバの監視なんかだと、 Integration の種類も多く、デフォルトで様々なメトリックが取れることや、ダッシュボードの見やすさなどがイケているかなと。<br />
特に SaaS だと、バッファリングがあるにしてもメトリクスの抜け落ちや一時アクセスできなくなる問題などはあり、クリティカルなものを全部載せるわけにもいかず、ただ SaaS の恩恵は受けたいというのが正直なところでしょう。<br />
(mackerel-agent のログを眺めているとたまに何故か 404 が返ってきていて笑います)</p>
<p>ただ、設定が複雑化したり、そもそも設定数が多くて移行がダルいというのが正直なところです。エイヤでやる体力があれば良いですが、ホスト数が増え、監視項目が万の単位であるとそれはそれは……</p>
<p>おそらく皆さんは Zabbix のアイテムやらなんやらを XML で書き出して<strong>ごにょごにょ</strong>したり、それを Prometheus の設定に<strong>いい感じ</strong>に変換する何かを書いたりされているかと存じます。そしてそんなコードは短いから/特定のドメインに特化しているからと公開せず、誰もが<strong>誰かは書いているだろう</strong>と思いながら書いていることでしょう。そうですよね?</p>
<p>今回ご紹介するのはそんなあるあるプロダクトです。やることは記事のタイトルに書いてありますね。</p>
<p><span id="more-1641"></span></p>
<h2>本編</h2>
<p>最初にも書きましたがこれ (<a href="https://github.com/kyontan/datadog-zabbix-history">kyontan/datadog-zabbix-history</a>) です。実装としては、Zabbix の DB からメトリクス (Zabbix でいうアイテムのヒストリ) を勝手に拾ってきます。<br />
いい感じに動きます。良かったですね。</p>
<p>現状イケてないところが1つあって、 dd-agent は独自の組み込み python を使うので pip で入れたパッケージを読んでくれません。インポートパスを弄ります。良くないですね。</p>
<p>まだ、とりあえず動くというところなので、様子を見ていきたいですね。</p>The post <a href="https://blog.monora.me/2017/08/zabbix-to-datadog/">Zabbix で収集したデータを Datadog へ投げる</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1641</post-id>	</item>
		<item>
		<title>CloudStack の VM を cs コマンドでデプロイしようとしてハマった</title>
		<link>https://blog.monora.me/2016/10/deploying-vm-using-api-on-cloudstack/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=deploying-vm-using-api-on-cloudstack</link>
		
		<dc:creator><![CDATA[きょんたん]]></dc:creator>
		<pubDate>Sun, 23 Oct 2016 17:00:17 +0000</pubDate>
				<category><![CDATA[Infrastructure]]></category>
		<category><![CDATA[CloudStack]]></category>
		<category><![CDATA[ICTSC6]]></category>
		<guid isPermaLink="false">http://blog.monora.me/?p=1394</guid>

					<description><![CDATA[<p>こんばんは。タイトルだけ書いた下書きが溜まっているので書いていきますということです。 ICTSC6 で CloudStack を使用していた話はまだ書いていなし多分書かないですが、使用していました。 その中で、API を [&#8230;]</p>
The post <a href="https://blog.monora.me/2016/10/deploying-vm-using-api-on-cloudstack/">CloudStack の VM を cs コマンドでデプロイしようとしてハマった</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></description>
										<content:encoded><![CDATA[<p>こんばんは。タイトルだけ書いた下書きが溜まっているので書いていきますということです。</p>
<p><a href="http://icttoracon.net/archives/category/%E7%AC%AC6%E5%9B%9E%E3%83%88%E3%83%A9%E3%82%B3%E3%83%B3" target="_blank" rel="noopener noreferrer">ICTSC6</a> で CloudStack を使用していた話はまだ書いていなし多分書かないですが、使用していました。</p>
<p>その中で、API を叩いてくれる薄っぺらいラッパーコマンドであるところの <a href="https://github.com/exoscale/cs" target="_blank" rel="noopener noreferrer">exoscale/cs</a> を叩いてデプロイなりVMの起動停止なりボリュームのアタッチなどをやっていたわけですが、デプロイ関連で少しハマったので解決策を紹介。</p>
<p>ちなみにこれ: <a href="https://github.com/exoscale/cs" target="_blank" rel="noopener noreferrer">https://github.com/exoscale/cs</a>。 exoscale 、 CloudStack なんですかね……</p>
<p><del datetime="2016-10-23T14:00:50+00:00">CloudStack の API はあまりにも愚直なのでパラメータが無限に多くてしんどいという話はさておき</del></p>
<p>APIの一覧は <a href="http://cloudstack.apache.org/api/apidocs-4.9/" target="_blank" rel="noopener noreferrer">http://cloudstack.apache.org/api/apidocs-4.9/</a> にあります。 (4.9 の場合)<br />
VM を作成する場合は、 <a href="http://cloudstack.apache.org/api/apidocs-4.9/apis/deployVirtualMachine.html" target="_blank" rel="noopener noreferrer">deployVirtualMachine</a></p>
<p>書いてある通りですが、必須なパラメータは以下の3つです。</p>
<ul>
<li>serviceofferingid</li>
<li>templateid</li>
<li>zoneid</li>
</ul>
<p>それとは別に、IPアドレスを固定したり複数のネットワークにVMを接続するときは iptonetworklist パラメータを指定するわけですが、このパラメータの設定がなんもわからんという感じです。</p>
<pre>iptonetworklist[0].ip=10.10.10.11&amp;iptonetworklist[0].ipv6=fc00:1234:5678::abcd&amp;iptonetworklist[0].networkid=uuid</pre>
<p>難しすぎる。なんで突然配列の演算子が出てきて &amp; で繋ぐ必要があるんだ……</p>
<p>実際に直に API を叩いたことはないのですが、 cs ではこの通りにパラメータを書いても上手く動いてくれません。<br />
なので、以下のようにする必要があります</p>
<pre>cs deployVirtualMachine ... iptonetworklist[0].ip=192.168.15.3 iptonetworklist[0].networkid=4bbc38e5-3e36-4a11-9c93-5a5261911120</pre>
<p>ただ &amp; で繋げずにスペースで区切るだけです。どういう挙動なんだろう……<br />
どこにも仕様が載っていないので試行錯誤せざるを得ないわけですが、やっていきましょう</p>
<p>結局 cs コマンドの引数はこんな感じになってしまうので非常に読みづらい。各位 Ansible のパワーに頼っていきましょう。僕は Ruby でラッパーを書きました。</p>
<pre>cs deployVirtualMachine displayname='vm1-p15-t7' name='vm-x-hoge' serviceofferingid='3ebb38bf-dbb6-42b1-b301-041d3546b5dc' templateid='cec5838f-1bae-442f-9009-9e27dcf33941' zoneid='57305097-d51a-467b-bbec-862ab20850d1' hostid='3edc5cc0-5375-462d-8a38-b2e4920791f4' account='xxx' domainid='1d43bf7b-b00c-41ba-959a-e422c4649547' startvm='false' iptonetworklist[0].ip=192.168.15.3 iptonetworklist[0].networkid=4bbc38e5-3e36-4a11-9c93-5a5261911120</pre>The post <a href="https://blog.monora.me/2016/10/deploying-vm-using-api-on-cloudstack/">CloudStack の VM を cs コマンドでデプロイしようとしてハマった</a> first appeared on <a href="https://blog.monora.me">monolog</a>.]]></content:encoded>
					
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">1394</post-id>	</item>
	</channel>
</rss>
