tag:blogger.com,1999:blog-84852711762798342162024-03-09T00:13:28.942+09:00hidekiy blogインターネット、Go、JavaScript、Python、Perl によるプログラミング、ISUCON、Windows、Raspberry Pi など、興味のある事について気まぐれに記事を書いています。Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.comBlogger186125tag:blogger.com,1999:blog-8485271176279834216.post-45814317391309639672022-07-26T20:10:00.007+09:002022-07-27T10:11:07.976+09:00ISUCON12 予選突破しました #isucon<h3 style="text-align: left;">概要</h3><div>2022年7月23日土曜日に、ISUCON12のオンライン予選が開催され、チーム名 hidekiy で何とか予選突破出来たので、参加記録を残しておきます。</div><h3 style="text-align: left;">全体指針の検討</h3><p>最初にざっくりアプリを触ってみて、マルチテナントと沢山のAPIが入り混じっていて大変難しいと思いながら、コードとクエリを確認して明らかに直した方が良さそうな所として、2か所発見しました。</p><p>1か所目がMySQL側のvisit_historyで、これは集約して来訪時刻の最小値のみが使用されているため、最小じゃないレコードは不要そうでした。2か所目がSQLite側のplayer_scoreで、スコアの最新値のみが使用されているので、そうじゃないレコードは書き込まなくても良さそうでした。そこで、2か所とも、初期データとアプリの書き込み処理を、どちらも修正する事にしました。</p><p style="text-align: left;">また、SQLiteをMySQLに載せ替えるかという事に関しては、意味深な変換スクリプト (~/webapp/sql/sqlite3-to-sql) が同梱されていた事から、そもそもそういう問題ならこの機能は自力で用意させるはず?とメタ推理し、このルートは大変不審であると考えたので、誘惑に惑わされず、載せ替えは無しで進める事にしました。</p><div><h3 style="text-align: left;">visit_historyの改良</h3><p>visit_historyに関して、初期データを更新 (@k_enokiがいい感じにやってくれました) し、アプリ側でも2件目以降の登録を阻止するために、(tenant_id, competition_id, player_id) でユニークインデックスを設定し、Duplicate Key Errorを無視するコードをアプリ側に追加して、これはスムーズに完成しました。</p>スコアは初期スコアからほぼ変化なし (4000程度) です。<h3 style="text-align: left;">player_scoreの改良</h3><p>player_scoreに関しては、初期データを更新するため、~/initial_dataのSQLiteの各ファイルに以下のようなクエリ:</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div style="background-color: white; font-family: Consolas, "Courier New", monospace; font-size: 14px; line-height: 19px; white-space: pre;"><div style="line-height: 19px;"><div><span style="color: blue;">delete</span> <span style="color: blue;">from</span> player_score</div><div><span style="color: blue;">where</span> id <span style="color: blue;">in</span> (</div><div> <span style="color: blue;">select</span> id <span style="color: blue;">from</span> (</div><div> <span style="color: blue;">select</span> id, <span style="color: #795e26;">row_number</span>() <span style="color: blue;">over</span> (</div><div> <span style="color: blue;">partition</span> <span style="color: blue;">by</span> tenant_id, player_id, competition_id</div><div> <span style="color: blue;">order by</span> row_num <span style="color: blue;">desc</span>) <span style="color: blue;">as</span> rn</div><div> <span style="color: blue;">from</span> player_score</div><div> )</div><div> <span style="color: blue;">where</span> rn > <span style="color: #098658;">1</span></div><div>);</div><div>vacuum;</div></div></div></blockquote><p>を流して内容を更新 (9割程度削減できたはず?) して、アプリ側は、CSVアップロードで全レコード追加した風のレスポンスを返しつつ、DBには最新値のみを追加するという処理に変更しました。</p><p>この過程で、ファイルの各行でのループ中で、breakする箇所を見落としていたせいで、rowCountとしてrowNumを流用して返したところ、件数カウントのチェックに違反するバグを仕込んでしまいましたが、件数のカウンターを別途用意することで回避し、手こずりましたが完成しました。</p><p>この時点でもスコアは初期スコアからほぼ変化なしです。</p><h3 style="text-align: left;">テナント排他的ロックの改良</h3>テナント毎に懐かしいflockによる排他的ロックが行われ、それによりダーティーリードを阻止していることは理解したのですが、SQLiteのままトランザクションを使うコードに変更して、ロックを外せるのか、良く分かっていなかったので@kotaroyに調べてもらいました。<p>並行して、ロックの必然性は不明だが、一旦読み取りの場合は排他的ロックは必要ないはずなので、 sync.RWLock に交換しておきました。スコア向上はイマイチでした。</p><p>調査の結果、SQLiteのままでトランザクションは対応出来そうという事になり、コードの修正を試みましたが、上手く動かず、未完のままいったん保留しました。</p><h3 style="text-align: left;">ボトルネック特定から提出版作成</h3><p>@k_enokiがNew Relic Go AgentをEcho Integrationで導入してくれて、TransactionsのMost time consuming順により、ボトルネックとなっているAPIは以下のように特定</p><p></p><ul style="text-align: left;"><li>GET /api/player/competition/:competition_id/ranking</li><li>GET /api/player/player/:player_id</li></ul><p></p><p>出来たのですが、処理内容が盛り沢山で、まだはっきりどこが遅いのかわからなかったため、処理段階ごとに <a href="https://docs.newrelic.com/docs/apm/agents/go-agent/instrumentation/instrument-go-segments/">Instrument Go segments</a> を細かく埋め込んで調べたところ、排他的ロックが問題となっている事がはっきりしました。</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZn-Rpo0SeMprmubtiys2A7FD3ANltzQi-2Q1_2XKjCiLdPoAhRmdidEaCcZhQvl1_wDOYISPcDvsqlilI4dAvvtIi-CW8N3-o_018ZkTIJTTkji8SG2QwLDIFiiAZ6KIYOqdxlAY2QUyQwy6oJaca6L0QCjD1GHFVNa8kmAbzpP6Zq11esLigdZCj/s2086/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202022-07-26%20185137.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="715" data-original-width="2086" height="138" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjZn-Rpo0SeMprmubtiys2A7FD3ANltzQi-2Q1_2XKjCiLdPoAhRmdidEaCcZhQvl1_wDOYISPcDvsqlilI4dAvvtIi-CW8N3-o_018ZkTIJTTkji8SG2QwLDIFiiAZ6KIYOqdxlAY2QUyQwy6oJaca6L0QCjD1GHFVNa8kmAbzpP6Zq11esLigdZCj/w400-h138/%E3%82%B9%E3%82%AF%E3%83%AA%E3%83%BC%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%83%E3%83%88%202022-07-26%20185137.jpg" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">こげ茶色がtenant rwlock</td></tr></tbody></table><br /><p>そこで、未完となっていたスコア登録のトランザクション導入ブランチについて、処理ボトルネックだという確信が深まったので、渋々再度修正を試みたところ、17時過ぎについに完成し、ようやくスコアが進捗 (17000程度) しました。</p><p>その後、MySQLサーバーを別サーバーに向ける改良を @k_enoki が素早くやってくれて、各種デバッグ情報の出力を止め、再起動試験をし、24000 程度のスコアが出るようになった状態で最終提出版としました。<br /></p><h3 style="text-align: left;">さいごに</h3><p>素晴らしい出題と大会運営、スポンサー企業・個人スポンサーの皆様には大変感謝してます。本選でもよろしくお願いします。</p></div>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-58004491589267317312020-10-11T22:08:00.011+09:002020-12-19T10:12:06.464+09:00ISUCON10 本選8位でした #isucon<h2 style="text-align: left;">概要</h2><div style="text-align: left;">10月3日にISUCON10 本選にチーム名 hidekiy、チームメンバー @hidekiy, @kotaroy で参加して、結果8位でした。賞金圏内は逃しましたが、過去の本選出場時のやられっぷりに比べて、若干の進歩は感じました。</div><h2 style="text-align: left;">何をやったかメモ</h2><h3 style="text-align: left;">10:00</h3><div style="text-align: left;">レギュレーション、アプリ仕様確認</div><div style="text-align: left;">盛り沢山過ぎて過去の ISUCON 本選でほぼ何もできなかった悪夢が蘇って焦る。</div><h3 style="text-align: left;">11:00</h3><div style="text-align: left;">アプリのコード確認、やはりボリューム感が凄くて気分が悪くなる。</div><div style="text-align: left;">予選と同じく Cloud Profiler, Cloud Trace 設定する。サーバー1号機がメモリ不足でアプリのビルドが遅すぎるので、仕方なくスペックが少し良さそうな2号機に移行したら行けた。</div><h3 style="text-align: left;">12:00</h3><div style="text-align: left;">ホームディレクトリに作った Makefile から、make -C webapp/golang としていたら明後日の場所 ~/bin にバイナリが出来ていてデプロイ出来ていない事に気づく。(cd webapp/golang && make) として対処完了</div><h3 style="text-align: left;">13:00</h3><div style="text-align: left;">ListNotifications の負荷が高いため、Web Push に移行する対応を行う。サンプルコードのおかげて特に難しい事は無く出来た。</div><h3 style="text-align: left;">14:00</h3><div style="text-align: left;">Audience Dashboard はユーザーごとに変化させなくて良く、一律でキャッシュ可能なので、<a href="https://pkg.go.dev/golang.org/x/sync/singleflight">singleflight</a> で一定時間内(1秒間)に来たユーザーには同じレスポンスを返しておく対応をする。シリアライズ後のバイナリを作るところまでを共通処理とした。</div><h3 style="text-align: left;">15:00</h3><div style="text-align: left;">Leaderboard を対処するため、クエリ側からユーザー固有パラメーターを抜いて、ジョブ履歴とチーム一覧を全ユーザー共通で取得出来るようにし、ユーザー固有の調整(スコアフリーズ中のスコアなど)は後でアプリ側で行うことで、Audience Dashboard と同様にキャッシュ可能にする</div><h3 style="text-align: left;">16:00</h3><div style="text-align: left;">ListNotifications で使っている loginRequired の負荷が高いので調べたところ、必ずしも getCurrentTeam しなくとも、contestant.TeamID が入っている事で判断出来るようなので修正</div><h3 style="text-align: left;">17:00</h3><div style="text-align: left;">ListClarifications も同様に、全ユーザー共通でDBクエリ結果のキャッシュを、アプリ側でユーザー固有のフィルタをしようと修正したが、ベンチマーカーの不整合検知を解決できず元に戻す。</div><div style="text-align: left;">チームキャパシティを増やすとエラーが出て動かなくなるが、よう分からんので大丈夫な所まで減らして回避 (Envoy の Too many open files だった模様)。この影響により再起動しないと調子が悪くなる状態になり大変困る。再起動すれば動くであろう状態にして競技時間終了</div><h2 style="text-align: left;">反省点</h2><div><ul style="text-align: left;"><li>インフラ</li><ul><li>3台の CPU コア数、メモリ容量がどうなってるか良く分かっていなかった。</li><li>最後まで2号機のみを使っていて、複数台構成に出来ていなかった。</li><li>Envoy のトラブルシュートと設定修正が出来ていなかった。</li></ul><li>アプリ</li><ul><li>singleflight だけ使うんじゃなくて cache + singleflight が良かったかもしんない。</li><li>ベンチマーカー側のアプリのロックなどを改良出来ていなかった。</li></ul></ul><div style="text-align: left;">スコアフリーズ後の最終リーダーボードに、1時間ほど2位で載っていたのは嬉しかったです🤣</div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-YYWqKuGa174/X4MCKtrlU5I/AAAAAAAArWk/tpMrFJP49009Wf-Vwev0nVGxk9XIXPtkwCLcBGAsYHQ/s1921/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B2020-10-11%2B214021.png"><img border="0" data-original-height="1078" data-original-width="1921" height="225" src="https://1.bp.blogspot.com/-YYWqKuGa174/X4MCKtrlU5I/AAAAAAAArWk/tpMrFJP49009Wf-Vwev0nVGxk9XIXPtkwCLcBGAsYHQ/w400-h225/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B2020-10-11%2B214021.png" width="400" /></a></div><h2 style="text-align: left;">謝辞</h2></div><div><div style="text-align: left;">いつも ISUCON を通して、何も出来なくて負けるのがとても悔しいから、日々精進するという貴重な機会を頂いていると思います。</div><div style="text-align: left;">運営の方々には、このような素晴らしいコンテストを開催いただき大変感謝しています。</div></div>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-70369512905744527712020-09-13T21:53:00.010+09:002020-10-16T23:36:05.614+09:00ISUCON10 予選通過しました #isucon<p></p><div style="text-align: left;">チーム名 hidekiy で、<a href="https://twitter.com/kotaroy" target="_blank">@kotaroy</a> と ISUCON10 予選に参加して、何とか通過しました。</div><div style="text-align: left;">ブログ記事の募集期間が終わらないうちに、当日の行動について記録しておきます。</div><h2 style="text-align: left;">タイムライン</h2><p style="text-align: left;"></p><h3 style="text-align: left;">12:20</h3><div style="text-align: left;">予選開始</div><div style="text-align: left;">仕様把握、なぞって検索が本丸っぽい予想。</div><div style="text-align: left;">不要そうな node_modules, target を抜いて、コードを Git 管理する。SSH のエージェント転送で連れてきた鍵を使って、サーバーから直接 GitHub にアクセスしてデプロイとかやる事にする。</div><div style="text-align: left;">サンプルの SSH の設定ファイルに、8081~8083 でそれぞれのサーバーのポート80を開けるようにする設定を入れた LocalForward を追加してチーム内に共有した。</div><div><p></p><p></p><h3 style="text-align: left;">14:00</h3><p style="text-align: left;">去年のISUCON予選1位チームのありがたい記事 <a href="https://www.takono.io/posts/2019/09/isucon/" target="_blank">ISUCON9 予選を全体1位で突破しました<br /></a></p><div style="text-align: left;"> で学んだ Cloud Trace, Cloud Profiler をまず設定する。New Relic はプロファイルが取れれば不要と思ったんで、入れない事とする。リソース監視は top を更新間隔1秒で目視確認して行う事にした。</div><p></p><div style="text-align: left;">いずれ問題になってくると思ったんで、nginx.conf でのボット対策を依頼した。</div><p></p><p></p><h3 style="text-align: left;">15:00</h3><div style="text-align: left;">検索機能がクソ重い事分かったんで、ソート用にいくつかインデックスを追加 (EXPLAIN 確認してない)</div>MySQL サーバーのスレーブ追加を依頼<p></p><h3 style="text-align: left;">16:00</h3><div style="text-align: left;">なぞって検索のN+1クエリについて、1段目のクエリのWHERE条件に、後段の条件を追加する感じで修正して対応した。</div><blockquote><div style="background-color: white; font-family: consolas, "courier new", monospace; font-size: 14px; line-height: 19px; white-space: pre-wrap;"><div><span style="color: blue;">SELECT</span> *</div><div><span style="color: blue;">FROM</span> estate</div><div><span style="color: blue;">WHERE</span></div><div> latitude <= ? <span style="color: blue;">AND</span> latitude >= ? <span style="color: blue;">AND</span> longitude <= ? <span style="color: blue;">AND</span> longitude >= ?</div><div> <span style="color: blue;">AND</span> ST_Contains(ST_PolygonFromText(%s), ST_GeomFromText(<span style="color: #795e26;">CONCAT</span>(<span style="color: #a31515;">'POINT('</span>, latitude, <span style="color: #a31515;">' '</span>, longitude, <span style="color: #a31515;">')'</span>)))</div><div><span style="color: blue;">ORDER BY</span> popularity <span style="color: blue;">DESC</span>, id <span style="color: blue;">ASC</span></div></div></blockquote><div style="text-align: left;">latitude, longitude から POINT を作る方法について、いま冷静に見ると ST_GeomFromText は使わずとも、直接 POINT(latitude, longitude) で大丈夫と思います。</div><h3 style="text-align: left;">16:30</h3><div style="text-align: left;">searchRecommendedEstateWithChair の条件式が直そうとしてバグらせた。</div><div style="text-align: left;">いつバグったか最初は不明だったためコミットごとにベンチ実行し、切り分けの後当該コミットを Revert して復旧した。</div><h3 style="text-align: left;">17:00</h3><div style="text-align: left;">椅子購入時のロックが無駄なので UPDATE ~ WHERE ~ で、Affected Rows を見る感じに修正した。</div><div style="text-align: left;">SELECT * を画面上に使うカラムのみに減らしてみたが、FAIL しちゃうので元に戻す (レギュレーション良く読んでない)、あまり減らせそうにないので、放置する事とする。</div><h3 style="text-align: left;">18:00</h3><p style="text-align: left;"></p><div style="text-align: left;">MySQL スレーブが出来たので、物件検索を別のDBに向けるように修正した。</div>やる事が無くなったので、なぞって検索の空間インデックス対応に着手する。<p></p><h3 style="text-align: left;">19:00</h3><div style="text-align: left;">空間インデックス対応 (estate に POINT 型のカラム location を追加) が完成して、なぞって検索のクエリを修正 (EXPLAIN 確認した)</div><blockquote><div style="background-color: white; font-family: consolas, "courier new", monospace; font-size: 14px; white-space: pre-wrap;"><div style="font-family: consolas, "courier new", monospace; line-height: 19px; white-space: pre-wrap;"><div><span style="color: blue;">SELECT</span> *</div><div><span style="color: blue;">FROM</span> estate</div><div><span style="color: blue;">WHERE</span> ST_Contains(ST_PolygonFromText(%s), <span style="color: blue;">location</span>)</div><div><span style="color: blue;">ORDER BY</span> popularity <span style="color: blue;">DESC</span>, id <span style="color: blue;">ASC</span></div></div></div></blockquote><div style="text-align: left;">この辺でスコア2500くらい獲得</div><h3 style="text-align: left;">20:00</h3><div style="text-align: left;">20時半くらいから謎に FAIL し始めて、initialize 時のスリープとか試したが特に変化せず、再起動したりして何とか最終スコア 2210 獲得して終了。</div><h2 style="text-align: left;">感想</h2><div style="text-align: left;">とても素晴らしい運営と問題作成をありがとうございました。</div><div style="text-align: left;">本選でもよろしくお願いします。</div><h2 style="text-align: left;">反省点</h2><div style="text-align: left;">popularity DESC, id ASC の複合インデックスは、ソート時に使われていると思っていたけれど、使われておらず、その事に最後まで気づきませんでした。同時にデプロイした rent ASC, id ASC のインデックスが多少効いていたことで満足していました。<a href="https://dev.mysql.com/doc/refman/5.7/en/order-by-optimization.html" target="_blank">MySQL 5.7 ドキュメント: ORDER BY Optimization</a> も今更ながら読んでます。そもそも複合インデックスの末尾に PRIMARY KEY のカラム入れるのはおかしかったですね😅</div><div style="text-align: left;">なぞって検索のクエリに LIMIT を入れられるはずが入れられていなかった。影響度合いは不明ですが、せっかくクエリで多角形内包条件込みの最終結果を取り出せるように直したのに、無駄に取得してしまっていました。</div><div style="text-align: left;"><a href="https://echo.labstack.com/" target="_blank">Echo Framework</a> のデバッグモードがオンで、ログも出したままでした。デバッグモードは影響をあまり認識していなかったのですが、JSON エンコード時に無駄にインデントを追加してくれたりするので、検索結果の巨大なレスポンスの時、多少は効いてきたかもしれないです。</div><div style="text-align: left;"><a href="https://cloud.google.com/profiler" target="_blank">Cloud Profiler</a> は、プロファイル取得にいちいち手を取られずに、パフォーマンス改善で刻々と変化するボトルネックを分析するのに非常に役に立ちました。</div><div style="text-align: left;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-CAQOEWGLkIE/X14Lv4YL6xI/AAAAAAAApn0/sMsSev5qCYU69YNWJvq_Yg8EmZ_wk3rvACLcBGAsYHQ/s2048/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B2020-09-13%2B202813.png" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1079" data-original-width="2048" height="211" src="https://1.bp.blogspot.com/-CAQOEWGLkIE/X14Lv4YL6xI/AAAAAAAApn0/sMsSev5qCYU69YNWJvq_Yg8EmZ_wk3rvACLcBGAsYHQ/w400-h211/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588%2B2020-09-13%2B202813.png" width="400" /></a></div><br /><p><br /></p></div>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-28438770163036561602020-08-16T22:36:00.002+09:002020-10-16T23:36:56.611+09:00Google Trust Services 用の CAA レコードを追加しました当ブログで使っている独自ドメイン hidekiy.com では、学習用で無駄に <a href="https://jprs.jp/glossary/index.php?ID=0218">CAA レコード</a> を設定して証明書発行が出来る認証局を制限しているのですが、<a href="https://pki.goog/">Google Trust Services (GTS)</a> についてのレコードを追加した事についての記事です。<div><div>2018年に設定した当初は、<a href="https://www.blogger.com/">Blogger</a> の独自ドメイン用証明書には <a href="https://letsencrypt.org/">Let's Encrypt</a> が使われていたので、以下のような CAA レコードを設定していました。</div><blockquote><div>0 issue "letsencrypt.org"</div><div>0 issuewild "letsencrypt.org"</div></blockquote><div>その後、巷の Blogger のブログでは GTS へ変更されているのに、何故か自分のブログだけ GTS に切り替わらないのが気になって調査した結果、GTS の証明書発行が出来るような CAA レコードを設定する必要がある事が分かり、<a href="https://static.googleusercontent.com/media/pki.goog/ja//GTS-CP-1.11.pdf">Google Trust Services, Certificate Policy</a> などを参考に、<blockquote><div><div>0 issue "pki.goog"</div><div>0 issuewild "pki.goog"</div></div></blockquote><div style="text-align: left;">を追加したところ、無事 GTS 発行の証明書に置き換わりました。 </div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-3nfXva7h5Qg/Xzk0Beh4m6I/AAAAAAAAob4/dVO8m-dfLpcWOULJ7c8lzlJ4LAKbXtL5ACLcBGAsYHQ/s508/%25E3%2582%25B3%25E3%2583%25A1%25E3%2583%25B3%25E3%2583%2588%2B2020-08-16%2B222606.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="270" data-original-width="508" height="173" src="https://1.bp.blogspot.com/-3nfXva7h5Qg/Xzk0Beh4m6I/AAAAAAAAob4/dVO8m-dfLpcWOULJ7c8lzlJ4LAKbXtL5ACLcBGAsYHQ/w325-h173/%25E3%2582%25B3%25E3%2583%25A1%25E3%2583%25B3%25E3%2583%2588%2B2020-08-16%2B222606.png" width="325" /></a></div><div style="text-align: left;">Blogger 側の挙動としては、GTS、Let's Encrypt の順で発行可能な証明書が発行されているような雰囲気があります。</div></div></div><h3 style="text-align: left;">関連記事</h3><div><a href="https://blog.hidekiy.com/2018/04/blogger-https.html">[blogger] ブログの HTTPS 化が完了しました</a><br /></div>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-81803344045396355382019-02-03T23:19:00.002+09:002019-02-03T23:19:35.024+09:00Intel Dual Band Wireless-AC 7260 付属の Bluetooth がデバイス記述子要求の失敗となるWindows 10 の PC にて、インテル® ドライバー & サポート・アシスタント というツールを使って、Intel 製のドライバを色々更新していたら、使用していた Intel Dual Band Wireless-AC 7260 付属の Bluetooth 部分が正常に認識されなくなり、デバイス記述子要求の失敗 コード43 というエラーがデバイスマネージャー上で出るようになりました。<br />
<br />
再起動、シャットダウン、シフトキーを押しながらシャットダウン、ドライバを削除と色々試したのですが、特に変化なく、途方に暮れていたところ、こちらの記事<br />
<a href="http://smh.smartly.net/2015/11/43.html">圏外恐怖症: デバイス記述子要求の失敗 コード43 なんじゃこれ!!</a><br />
を参考にして、PC の電源をコンセントより抜いて、しばらく放置してから起動したところ、正常に認識され動作するようになりました。<br />
<br />
こちらの方法は試していないのですが、同様なエラーを別の方法で解決されているようでした。<br />
<a href="http://sunao.orz.hm/blog/?no=87">超絶はらへ('A`) - USB機器がエラーコード43を返してきた場合の対処方法</a><br />
<br />
詳しく調査していないのですが、必要な何らかのリセット処理が正常に行われておらず、デバイス側とホスト側が矛盾した状態になり、復旧出来なくなる不具合があるのではと想像しています。Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-19334447074999350752018-05-06T23:36:00.000+09:002019-02-03T23:27:40.588+09:00ASUS TPM-L R2.0 のファームウェアを 5.63.3144 に更新しましたWindows 10 Version 1803 に更新したところ、Windows Defender セキュリティセンターにて、TPM チップのファームウェアの更新が必要という警告が出るようになったので、さっそく更新してみました。作業内容についてメモしておきます。<br />
<br />
<b>更新手順</b><br />
1. 更新元バージョンを調べて USB ストレージを準備<br />
2. ASUS のマニュアルの指示の通り、以下を実行<br />
2.1. UEFI の設定で、Security Device Support と Launch CSM を Disable<br />
2.2. USB ストレージから起動して、EFI シェルで更新手続きを実行<br />
2.3. UEFI の設定を元に戻して再起動<br />
3. Microsoft の指示の通り TPMのクリアを実行<br />
<br />
<b>補足</b><br />
更新手順はマニュアルの通りで上手くいきましたが、更新元のバージョンに合わせたファイルをダウンロードして使用することが必要でした。<br />
更新元のバージョンによっては、ASUS のダウンロードページで Show all を押すと出てくるもう一つの方を使う必要がある場合があります。<br />
<br />
TPM チップのバージョンを確認するには、<br />
Windows Defender セキュリティセンター > デバイスセキュリティ > セキュリティプロセッサ > セキュリティプロセッサの詳細<br />
を見ると良いようです。<br />
<br />
EFI シェルに入る方法は、配布されているファイルを、X:\EFI\Boot\BOOTX64.EFI というパスになるように USB ストレージに展開して、起動すれば良いようでした。<br />
<br />
UEFI の設定変更や、TPM のクリアを行う際は、BitLocker の保護の中断を行ってから作業をすると回復キーを何度も入れなくて済むので便利です。<br />
<br />
<b>リンク</b><br />
<a href="https://support.microsoft.com/ja-jp/help/4096377/windows-10-update-security-processor-tpm-firmware">セキュリティ プロセッサ (TPM) ファームウェアを更新する - Windows Help</a><br />
<a href="https://www.asus.com/Motherboard-Accessory/TPM-L-R2-0/HelpDesk_Download/">TPM-L R2.0 Driver & Tools | Motherboard Accessory | ASUS Global</a> - 2018年5月現在、更新元バージョンの異なる2種類のファイルがダウンロード出来るようになっています。<br />
<a href="https://www.asus.com/Motherboard-Accessory/TPM-L-R2-0/HelpDesk_Manual/">TPM-L R2.0 Manual | Motherboard Accessory | ASUS Global</a> - ファームウェアの更新の仕方がコマンドと共に載っているので必読です。Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-66212292181364954472018-04-01T23:30:00.005+09:002020-08-16T22:37:39.479+09:00[blogger] ブログの HTTPS 化が完了しましたBlogger のカスタムドメイン用 HTTPS 対応がリリースされたので、さっそく有効にしてみました。特に追加費用は発生せず、証明書は <a href="https://letsencrypt.org/">Let's Encrypt</a> の DV (Domain Validation) 証明書が自動で設定されるようで、大変便利でした。<br />
<br />
証明書が設定されたことで、GFE (Google Front End) の配信方式が、HTTP 1.1 から、HTTP 2, QUIC 39 に変更され、やけに最先端感があります (2018/04/01 時点)。また、HTTPS 有効化前からですが、当たり前のように IPv4, IPv6 のデュアルスタックになっています。<br />
<br />
ブログ内の http:// な画像は親切なことに Blogger 側で用意してくれたプロキシで https:// な URL に変換されるので、mixed content 問題も回避してくれるようです。<br />
<br />
Google App Engine のカスタムドメイン用 HTTPS 機能でも同じように Let's Encrypt + GFE で設定されたので、どうやら同じ仕組みを使っているようです。<br />
<br />
特に問題はないと思うので、HTTP サイトの表示変更が予定されている、2018/07 の Chrome 68 リリースまでに、HTTPS リダイレクトまで有効化しておくと良いと思います。<br />
<a href="https://www.chromium.org/Home/chromium-security/marking-http-as-non-secure">Marking HTTP As Non-Secure - The Chromium Projects</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-48830495863900345452018-03-19T08:51:00.003+09:002018-03-19T08:55:34.201+09:00So-net フレッツ回線を IPv6 + DS-Lite に変更して劇的に速度改善しました最近、毎晩8時~12時くらいの時間帯で、So-net フレッツ光マンションタイプのインターネット回線のダウンロード速度が非常に遅くなる (0.1~1Mbps程度) 現象に見舞われており、大変困っていました。<br />
<br />
具体的には、YouTube の 1080p や、AbemaTV の最高画質はダウンロードが追い付かず、低ビットレートのモヤモヤした画面を見させられ、アプリの更新やデータダウンロードでもやたら時間がかかるという感じで、この回線に繋がる Wi-Fi よりも、ドコモ Xi の 4G+ の方がずっと速いという、いったい何にお金払っているんだろうかという状況でした。<br />
<br />
切り分け用に NTT 東日本の用意してくれている <a href="http://www.syutoken-speed.flets-east.jp/">フレッツ速度測定</a> では、十分に高速 (90Mbps 以上) な速度になっているので、おそらくボトルネックは So-net 用の PPPoE 部分にあるようで、先駆者のブログでの改善報告も参考にして、以下のページより IPv6 接続オプションを申し込みました。<br />
<a href="https://www.so-net.ne.jp/support/mbr/catalog/ipv6/ipoe.html">「IPv6」ご利用のご案内 | 会員サポート | So-net</a><br />
<br />
申し込み数時間後、手続きが完了したようで、ルーター広告 (RA) でグローバル IPv6 アドレスが降ってきて IPv6 で通信できるようになり、Google, Facebook, YouTube, Netflix など、IPv6 接続性のあるサイトの速度が改善しました。<br />
<br />
この調子で IPv4 の速度も改善するため、So-net での IPv4 over IPv6 トンネリング (IPv6 ネットワーク上で IPv4 の通信を行う技術) のために必要な DS-Lite に対応した無線LANルーター <a href="http://buffalo.jp/product/wireless-lan/ap/wxr-1751dhp2/">WXR-1751DHP2</a> を導入してみました。セットアップ自体は PPPoE の設定すら必要なく、有線で繋いで電源を入れるだけで、あとは IPv6 と IPv4 (DS-Lite) の接続性が得られました。<br />
<br />
速度測定結果は以下のように、混み合っていた時間帯でも安定してダウンロード 60Mbps 以上は出るようになって、非常に快適になりました。<br />
<br />
<a href="http://www.speedtest.net/result/7083551212"><img src="http://www.speedtest.net/result/7083551212.png"/></a><br />
<br />
プロバイダを So-net に変えてから、遅延がひどくてやらなくなっていた、FPS も試しにやってみたところ、ちゃんと敵の居場所が反映されるようになって、レイテンシーも安定して良くなっているようです。首都圏や都市近郊部などで、夜間の混雑のひどいフレッツ光回線を使用している方は、ぜひ同様のオプションをご検討されると良いと思います。<br />
<br />
<b>蛇足</b><br />
DS-Lite 対応のためには、必ずしも対応する専用機器を買う必要はなく、何らかの DS-Lite 対応ルーター + 無線アクセスポイントでも良いと思います。<br />
<br />
これまで、PPPoE 終端装置の増設状況により差別化 (予想) されていたプロバイダ品質は、いったい今後どうなるのか考えると、そもそも IPv4 トンネリング部分で、JPIX, BBIX, MFEED の三社しか NTT 側と繋がっていないので、フレッツ光のどんなプロバイダを選ぼうとも、IPv6 接続して、IPv4 トンネリングを行えば、IX 品質の最高のインターネット接続を享受できるようになったのではないかと思い、今後の回線状況に期待します。<br />
<br />
<b>リンク</b><br />
<a href="http://www.mfeed.ad.jp/transix/index.html">サービスのご案内 - transixサービス</a> IPv4 トンネリングに関する図があります<br />
<a href="http://www.mfeed.ad.jp/transix/ds-lite/">DS-Lite IPv4接続オプション接続確認機種情報</a><br />
<a href="http://www.speedtest.net/">Speedtest by Ookla</a> 人気のある速度測定サイト、手動変更すると、SoftEther 社なども選べて面白いです<br />
<a href="https://fast.com/ja/">インターネット回線の速度テスト | Fast.com</a> こちらの計測サーバーは Netflix の CDN なので品質が高いと思います<br />
<br />
<b>細かい注意</b><br />
IPv6 オプションの申し込み完了後、設定状況によっては、問答無用で IPv6 経由でグローバルに晒されるので、注意してください。参考:<br />
<a href="https://qiita.com/sumomoneko/items/fa56737f97beff3566f3">IPv6通信にNDプロキシを指定すると安全になるとはどういうことか</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-49096736085867622522018-03-12T22:20:00.002+09:002019-02-03T23:23:05.398+09:00[adtech] 行動ターゲティング広告を最大限強化するにはインターネット広告について、もし広告ブロッカーなどは使わず、広告を受け入れるポリシーなのであれば、完全に最適化してもらうのも面白いと思います。行動ターゲティング広告という仕組みはご存知であっても、具体的に最適化を強化するには何をすれば良いかは、各社気持ち悪がられることを恐れてか、あまり明確な説明をしていないように思います。そこで、広告の最適化をより進め、広告の配信が楽しみになるアイディアをご紹介します。<br />
<br />
まず、Google, Facebook, Twitter, Yahoo! JAPAN など、広告配信に直結したアカウントで、モバイルを含む普段使うすべてのブラウザにログインしましょう。クッキーを受け入れていれば、すでにブラウザごとに履歴が蓄積しているのですが、アカウント経由で全ての行動履歴が統合されることでより正確なプロフィールが仕上がります。<br />
<br />
Safari のデフォルトの設定は広告最適化上よろしくないものがあるので、サードパーティークッキーは受け入れる、サイト越えトラッキングも防がない設定に変更すると良いです。<br />
<br />
次に、所持しているモバイル端末全てに、各社のモバイルアプリをインストールし、ログインしましょう。これにより、デバイス単位で存在する IDFA (iOS), AdID (Android) の広告用識別子と、ユーザープロフィールが統合され、モバイルアプリ内の広告も最適化が完了します。追加で、位置情報も定期送信しておくと良いです。<br />
<br />
これらのユーザーごとに広告配信を最適化する仕組みは、必ずしもリアルタイムではなく、日次~週次ほどのバッチ処理で随時更新されるような雰囲気です。すぐに面白い広告が出なくともしばらく放置してみると良いと思います。<br />
<br />
以上の対応により、例えば、<a href="https://adssettings.google.com/authenticated">Google 広告設定</a> を見てみると、以下のように収集された興味関心が一覧で表示されると思います。<br />
<br />
<a href="https://1.bp.blogspot.com/-8EkCSSlg9eE/WqZ7wIu86SI/AAAAAAAASsg/tFTxbEFu_s8mS2WaP5QQsBc9Ebe6k6sLwCLcBGAs/s1600/google-adsettings.png" imageanchor="1" ><img border="0" src="https://1.bp.blogspot.com/-8EkCSSlg9eE/WqZ7wIu86SI/AAAAAAAASsg/tFTxbEFu_s8mS2WaP5QQsBc9Ebe6k6sLwCLcBGAs/s400/google-adsettings.png" width="400" height="249" data-original-width="900" data-original-height="561" /></a><br />
<br />
<b>現状の分析</b><br />
現状どれくらい正確なユーザーの情報を得られているかについて、Google は Google Chrome により、SDK の埋め込みがなくても、全ての閲覧履歴を収集する仕組みを持っているので、格段に優位な状況にあると思います。<br />
<br />
Facebook のモバイルアプリも、標準ブラウザでログイン済みかどうかを定期的に確認し、ログインさせる機能を有しているので、広告の正確性向上にこだわっていると思います。<br />
<br />
Twitter では Android アプリでインストールしているアプリ一覧を収集する機能があるのですが、まだブラウザのログイン状態を検知し、ログインさせる機能は無いように思います。<br />
<br />
<b>広告の最適化を望まない場合</b><br />
これらの仕組みを望まないのであれば、ログイン状態を維持したまま、以下の各社のアカウント設定にある広告設定で、アカウント単位でオプトアウトしておきましょう。<br />
<a href="https://adssettings.google.com/authenticated">Google 広告設定</a><br />
<a href="https://www.facebook.com/ads/preferences/">Facebook 広告設定</a><br />
<a href="https://twitter.com/settings/personalization">Twitter カスタマイズとデータ</a><br />
<a href="https://btoptout.yahoo.co.jp/optout/preferences.html">Yahoo! JAPANの配信する行動ターゲティング広告の無効化について</a><br />
<br />
もしログアウトしておきたいのであれば、ブラウザのトラッキング拒否設定をオンにし、以下のサイトでオプトアウト状況を確認して、必要に応じてクッキーを設定すると良いと思います。<br />
善良な広告配信業者はこのサイトからのオプトアウトに対応しています。<br />
<a href="http://optout.aboutads.info/">WebChoices: Digital Advertising Alliance's Consumer Choice Tool for Web US</a><br />
Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-26139963789641631162018-02-25T23:27:00.003+09:002020-09-14T21:23:26.107+09:00[isucon] ISUCON7 本選17位でした2017年11月25日、LINE の新宿ミライナタワーの会場にて、<a href="http://isucon.net/archives/50949022.html">ISUCON7</a> 本選にチーム 円山町(hidekiy, kotaroy, k_enoki) として参加してきました。成績は ISUCON6 本選と比べて若干の進歩はしたのですが、まだまだ上位層との壁を感じました。<br />
当日やったことを書いておきます。<br />
<br />
<b>10:00~</b><br />
SSH 鍵ログイン設定、Mackerel Agent 設定、Go 実装に変更、アプリの動作確認、Go の CPU プロファイル取得 (pprof)<br />
<br />
<b>12:00~</b><br />
分析の結果、初期状態のボトルネックは、DB と API のどちらの CPU, 各種 IO も使い切っていると言えないので、ロック競合か何かかと思ったが、煮え切らないまま深く考えなかった (これが致命的にまずかった)<br />
CPU プロファイル的には、多倍長整数演算が遅かったのと、コード上明らかにおかしな1000回ループ、テストコード付属という親切設計を見て、このループを最初に修理することにした。<br />
<br />
<b>16:00~</b><br />
初めて使う Go の多倍長整数演算ライブラリで、苦労の末1000回ループの除去に成功、それでも相変わらずボトルネックはDBのロックにあるように見え、これを何とか小細工しようとするが、特に有効な手を打てないまま時間切れとなった。<br />
<br />
<b>感想</b><br />
速やかに、オンメモリー方式に作り替え、ロックを部屋別に分散させる決定をする必要があった。<br />
Go の多倍長演算には結構苦しんだ。<br />
糖を消費したせいか、ISUCON ケーキが美味しかった。<br />
<br />
<b>総括</b><br />
素晴らしいイベントを企画、運営いただいた、LINE、KLab、さくらインターネット様には大変お世話になりました。ありがとうございます。<br />
<br />
<a href="https://4.bp.blogspot.com/-tvvVcVCSeSY/WpLB-XVuClI/AAAAAAAASls/cypuYYPaEhw9JRTf86Ol3UIvBUyqn_D9ACLcBGAs/s1600/DSC_0076.JPG" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-tvvVcVCSeSY/WpLB-XVuClI/AAAAAAAASls/cypuYYPaEhw9JRTf86Ol3UIvBUyqn_D9ACLcBGAs/s400/DSC_0076.JPG" width="400" height="300" data-original-width="1600" data-original-height="1200" /></a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-63997002698110626032017-10-25T23:38:00.003+09:002017-10-26T21:36:48.265+09:00[isucon] ISUCON7 予選通過しましたISUCON7 にチーム名 円山町 (@hidekiy, @kotaroy, @k_enoki) として出場し、去年に引き続き予選通過しました。当日について、記憶が定かな内にメモしておきます。<br />
<br />
<b>今回の予選問題について</b><br />
isubata という名前で、これは ISUCON 参加者になじみの深い <a href="https://idobata.io/">idobata</a> というチャットサービスを参考に作られているようでした。<br />
<br />
<b>用意したもの</b><br />
<a href="https://gitlab.com/">GitLab</a> のプライベートリポジトリと権限設定<br />
専用の <a href="https://slack.com/">Slack</a> チャンネル<br />
<a href="https://mackerel.io/">Mackerel</a> オーガニゼーションと公式プラグイン (inode, linux, mysql, nginx, proc-fd, uptime) の設定<br />
<a href="https://github.com/lebinh/ngxtop">ngxtop</a> の使い方<br />
<br />
<b>2017/10/22 13:00</b><br />
無事全員そろって開始<br />
当日用マニュアル熟読 (@hidekiy, @kotaroy)<br />
公開鍵ログイン設定と ssh config 作成 (@k_enoki)<br />
アプリのソースコードを GitLab へアップロード (@k_enoki)<br />
アプリを Go 実装へ切り替えと自動起動設定の修正 (@k_enoki)<br />
isubata アプリの動作確認 (@hidekiy, @kotaroy)<br />
インフラ構成と、nginx, MySQL の動作状況の確認 (@k_enoki)<br />
トラブルシュート用の mackerel-agent を全台に設定 (@hidekiy)<br />
<br />
<b>14:00</b><br />
ローカル開発環境構築 (@hidekiy, @kotaroy)<br />
make deploy で全台にアプリがデプロイ (ローカルで GOOS=linux でクロスコンパイル後、scp して rename して systemctl restart) されるように設定 (@hidekiy)<br />
静的ファイルの nginx 配信化と事前圧縮設定 (@k_enoki)<br />
DB のネットワーク上りがあんまりな状態だったので、一旦 image のオンメモリキャッシュを実装 (@hidekiy)<br />
/icon にインチキ Etag + If-None-Match 実装を試すが、全く 304 を返せず挫折 (@hidekiy)<br />
/profile の画像アップロード機能で、DB に二重に書き込まないように修正、ついでにアップロード内容をオンメモリーキャッシュに乗せるように修正 (@hidekiy)<br />
/profile の2個のアップデート文を1個に統合 (@hidekiy)<br />
<br />
<b>16:00</b><br />
このあたりでようやく API リクエストを順調にさばけるようになり、 ようやく nginx の too many open files を拝めて、チーム内安堵した。<br />
2台構成にすればリーダーボードに載りそうな気配があったので、一時的に2台構成に変更し記念スコア取得 (@k_enoki)<br />
スロークエリログ 0.1 で集めたクエリを pt-query-digest で集計して調査 (@kotaroy)<br />
URL を保存し、初期 icon も静的配信に変更 (@k_enoki)<br />
なぜか2台構成にすると 304 が減ってしまい、1台の時よりもスコアが落ちてしまう問題の調査 (@k_enoki, @hidekiy)<br />
→ 議論の末、2台のサーバー間の差分は mtime しかないので rsync --archive してもらい解決 (@k_enoki)<br />
<br />
<b>18:00</b><br />
/message, /history の N+1 クエリを修正 (@hidekiy)<br />
/message, /history のバグ (IN () の内容が空になって SQL エラー) を修正 (@hidekiy)<br />
/fetch の N+1 クエリを修正 (WHERE で OR して GROUP BY) (@hidekiy)<br />
遅くなったという報告があったので、/fetch の N+1 クエリを修正その2 (初期状態のクエリを UNION ALL) (@hidekiy)<br />
<br />
<b>20:00</b><br />
/fetch に入っているスリープ秒数を色々テストするが特に効果なしと判断して元に戻す (@hidekiy)<br />
不要なカラムの取得をしないように修正 (@hidekiy)<br />
アプリログ出力機能を削除 (@hidekiy)<br />
nginx ログ出力を停止 (@k_enoki)<br />
<br />
<b>感想</b><br />
かなり苦しかったですが、ファイルの mtime を揃える必要があるということが解明できたのが良かったです。<br />
また、チャンネル一覧に未読カウントカラムを追加して、COUNT(*) を節約するという改善には、当日たどり着かなかったので今後精進します。<br />
<br />
インフラ、アプリ、データベースの知識がバランスよく必要になる、素晴らしい問題を作成された <a href="http://www.klab.com/">KLab</a> さま、ありがとうございます。<br />
また、安定したサーバーインスタンスで支えていただいた <a href="https://www.sakura.ad.jp/">さくらインターネット</a> さま、ありがとうございます。的確に帯域制限されたローカルネットワークは今までになく面白い ISUCON 予選になっていたと思いました。<br />
<br />
<b>リンク</b><br />
<a href="http://isucon.net/archives/50949022.html">ISUCON7 まとめ</a><br />
<a href="http://isucon.net/archives/50961437.html">ISUCON7 オンライン予選 全ての順位とスコア(参考値)</a> 予選通過順位は9位でした<br />
<br />
<b>過去の記事</b><br />
<a href="http://blog.hidekiy.com/2016/10/isucon6-isucon.html">ISUCON6 本戦敗退しました #isucon</a><br />
<a href="http://blog.hidekiy.com/2016/09/isucon-isucon6.html">[isucon] ISUCON6 予選通過しました</a><br />
<a href="http://blog.hidekiy.com/2015/09/isucon-isucon5.html">[isucon] ISUCON5 予選敗退しました</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-85318770194541743392017-01-22T23:51:00.000+09:002017-01-22T23:52:41.095+09:00[golang] crypto/rand で疑似乱数生成器を初期化するGo 言語で疑似乱数 <a href="https://golang.org/pkg/math/rand/">math/rand</a> を使うとき、実行ごとに別の乱数列を選択するための方法として、rand.Seed(time.Now().UnixNano()) とするのが人気があるようなのですが、より予測困難さを追加するためには以下のコードのようにすると良いです。<br />
<br />
今日では、Perl, Ruby, Python などで、明示的な seed をせずに rand を使った場合に、内部的に行われる自動的な seed では、OS の乱数生成器由来の値が使われるようになっているので、Go でも同じ感じで良いと思います。<br />
<br />
<pre><code class="golang">
package main
import (
cryptorand "crypto/rand"
"encoding/binary"
"math/rand"
)
func main() {
randSeed()
println("rand int:", rand.Int())
}
func randSeed() {
var seed int64
err := binary.Read(cryptorand.Reader, binary.LittleEndian, &seed)
if err != nil {
panic(err)
}
rand.Seed(seed)
}
</code></pre><br />
LittleEndian は BigEndian でも良いです。crypto/rand には big.Int のインターフェースもありますが、こちらの方式の方が簡潔に書けると思います。<br />
<br />
蛇足ですが、暗号化用の鍵や、何とかトークンのような、長さ分のエントロピーを持つ乱雑な文字列を作りたい場合は、math/rand ではなく、<a href="https://golang.org/pkg/crypto/rand/">crypto/rand</a> をそのまま使う必要があります。<br />
<br />
<b>リンク</b><br />
<a href="https://github.com/golang/go/issues/11871">math/rand: Deterministic random by default is dangerous #11871</a><br />
Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-38918054153313615042016-10-27T00:01:00.003+09:002020-09-14T21:23:56.212+09:00ISUCON6 本戦敗退しました #isucon22日土曜は第6回の <a href="http://isucon.net/">ISUCON</a> に参加しました。当日は無事起床は成功したのですが、完全に打ちのめされました。チーム名は円山町です。参加メンバーは会社の同期 @k_enoki, @ymz_kotaro です。今後のため当日やったことをメモしておきます。<br />
<br />
<b>10時~12時</b><br />
4コア * 5台の構成が Azure のデフォルトのコア数制限にひっかかってデプロイ失敗、運営で2コア * 5台に変更していただき、この構成で競技することになる。<br />
デプロイ後なぜかログインできないと思ったらユーザー名が自分の名前で入ろうとしていた。isucon@ としてログインに成功する。<br />
バックエンド側アプリを Go 実装に変更後、何もいじらずにベンチ流してみるが、フロント側アプリの Node.js でアクセスログが出ていないのでアクセス状況は良く分からず。<br />
<br />
<b>12時~14時</b><br />
Go のアプリのプロファイルを取得するためにアプリを改造する。Node.js 部分は @ymz_kotaro に依頼する。<br />
@k_enoki が Node.js の前に nginx を立ててアクセスログを解析する。<br />
isu05 に MySQL と Redis を立ててもらうのを @k_enoki に依頼する。<br />
本番環境では別ノードの MySQL を使いたいが、ちゃんとした設定が良く分からないのでひとまずホストネットワーク設定とする。<br />
docker-compose の扱い方でローカル環境構築に手こずったが、Docker for Mac ではホストネットワークが使えない問題があることが分かったので本番でのみ使うこととする。<br />
<br />
<b>14時~16時</b><br />
docker-compose build していなくてイメージがリビルドされずコードの変更が反映されない問題を解決する。<br />
Go のプロファイル上最も時間を費やしていた、あるルームの全情報を取得する API を Redis でキャッシュする機能を作成する。<br />
ポーリングで沢山無駄にクエリを発行している、SSE で部屋の更新情報を通知してくれる API を Redis の Pub Sub を使って改造することを計画する。<br />
<br />
<b>16時~18時</b><br />
Redis のキャッシュ機構はバグ修正を git pull してようやく機能するようになる。<br />
更新情報通知用の Pub Sub 機構は作ってみるがいつまでも FAIL が解決できない。<br />
nginx で TLS 終端した後、Node.js へも TLS で接続しているのはもったいないので、Node.js 側のTLSを外す改造を @ymz_kotaro にやってもらう。<br />
<br />
<b>全体の感想</b><br />
懇親会でも聞いた通り、予選では簡単だったアプリのデプロイも、本戦ではちゃんと考えないとあっさり失敗するということを身をもって体感しました。<br />
初めて本戦会場に来て、ただ素晴らしいネームカードを受け取っただけで、すでにいい気分になっていて、実際に勝つことをイメージして行動出来ていなかったと思います。<br />
問題を理解して、やるべき事を速く確実にこなす、トラブルシュートを的確に行う、ということがそもそも出来ていなくて、力を発揮できる状況まで持って行けず負けたという感じでした。<br />
自分がてんやわんやな状況になっている間も、問題を着実に解いている上位チームの圧倒的な力を感じます。<br />
素晴らしいイベントを開催いただいた運営の皆様、ならびに問題作成者の皆様にとても感謝しています。<br />
Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-5203630551420354212016-09-19T00:13:00.002+09:002020-09-14T21:24:15.873+09:00[isucon] ISUCON6 予選通過しました今回はついに予選通過しました。チーム名は円山町です。17日土曜日の予選当日にやったことをメモしておきます。<br />
<br />
<b>予選当日のタイムライン</b><br />
10時<br />
出社 (会社のオフィスから参加させてもらいました。大変感謝)<br />
前の日の晩に作った無料試用アカウントでデプロイ<br />
Go 実装に変更、動作確認<br />
記事を削除したら /initialize しても復活しなくて、初期データを壊してしまったので復旧方法を調査<br />
/var/log/cloud-init-output.log を見て展開イメージの tar.gz を発見したので、中に入っている SQL ダンプでデータを復元<br />
<br />
11時<br />
Go 実装に切り替えたところ、スターが付かない不具合があったので、コードを検査、ngrep で調査して原因を特定<br />
ローカルでコードいじるためにホームディレクトリで git init、必要そうなものを add/commit して push<br />
ローカルの MySQL にデータを入れて似たような環境を構築、バグ修正、動作確認<br />
正常に動作するが、キーワードの置換処理があるページが遅くてベンチどころじゃないので、アプリに <a href="https://golang.org/pkg/net/http/pprof/">net/http/pprof</a> を仕込んで、キーワード個別ページを叩いた時の CPU プロファイルを取得<br />
htmlify の正規表現コンパイルと正規表現マッチングが遅いことが分かったので、何とかする方法を検討<br />
<br />
12時<br />
昼食、修正方針の検討<br />
<br />
13時<br />
htmlify で行っているキーワードの発見部分は、元上司の okzk さんが活用しているのを見たり、他プロジェクトのコードで見たことがあったトライ木で何とかするのが良さそうと判断、触ったことのあった <a href="https://github.com/armon/go-radix">github.com/armon/go-radix</a> を使わせていただいて試作してみたところ、特に問題なく動き、動作はだいぶ速くなった。<br />
ベンチを流しながらプロファイルを取ったところ、トライ木の構築に時間がかかっていたので構築済みのトライ木をキャッシュする (キーワードリストが変わったら破棄) ように修正<br />
<br />
14時<br />
isutar のスター追加処理でキーワードの存在チェックにキーワード個別ページを叩いていて迷惑なので MySQL から存在情報を取るように修正<br />
isuda のスター取得部分で HTTP API を使う必要はないと思ったので直接 MySQL を参照して取るように修正<br />
<br />
15時<br />
SPAM フィルタの部分が明らかに何か怪しいので、isupam を10個に増やして nginx の upstream に入れてもらったりしてテスト<br />
とくに改善しないので全て元に戻す<br />
キーワードと内容をくっつけて isupam に投げても問題なかったので、これでリクエストは減らせたので良しとする<br />
<br />
16時<br />
キーワード本文のキャッシュを追加 (htmlify の先頭で同じ内容のリンク済み内容が分かってればそれを返す、キーワードリストの変更があったら破棄する)<br />
トライ木の Insert, Delete で差分更新を行えば、完全な再構築を回避できることが分かったので修正、これで画期的にスコアが上がる<br />
再起動テストを実施、起動直後の初期化で MySQL につながっていなくてアプリがクラッシュする問題を発見したので修正<br />
<br />
17時<br />
ユーザー名をキャッシュするように修正<br />
記事全件数をキャッシュするように修正<br />
<br />
<b>終わってから気づいた点</b><br />
/ のスター取得部分のスター取得クエリが記事の件数と同じ回数流れちゃってるのは良くない<br />
htmlify で []string 作って Join したが十分な長さの ByteBuffer でやった方が良かったのでは<br />
isutar を廃止して、スターをオンメモリ化できたのでは<br />
<br />
<b>参加された方のレポート見て出来ていなかった点</b><br />
キーワード本文キャッシュ破棄を全破棄ではなく上手くやる方法<br />
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/sora_h">@sora_h</a> <a href="https://twitter.com/kani_b">@kani_b</a> select keyword from entry where description like '%#{keyword}%' で引いてきたやつを全部消した</p>— Kazuhito Hokamura (@hokaccha) <a href="https://twitter.com/hokaccha/status/777465117000605696">2016年9月18日</a></blockquote><script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script><br />
<br />
<b>関連リンク</b><br />
<a href="http://blog.hidekiy.com/2015/09/isucon-isucon5.html">[isucon] ISUCON5 予選敗退しました</a><br />
<a href="http://blog.hidekiy.com/2014/10/isucon4.html">ISUCON4 に挑戦して予選敗退しました</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-15832877550021287552016-01-26T08:31:00.000+09:002016-01-26T08:31:04.494+09:00[windows] BitLocker の暗号化モードを新しい XTS-AES に変更してみましたWindows 10 バージョン 1511 の新機能で、BitLocker の暗号化方式が追加されたので、早速変更してみました。<br />
<br />
変更方法は、いったん暗号化を解除した後、再度暗号化をする際に、以下の画面の選択肢の中で「新しい暗号化モード」を選べばよいです。<br />
<br />
ディスクがリムーバブルではなく内蔵のときはデフォルトで新しい暗号化モードが選択されていました。<br />
<br />
<a href="http://4.bp.blogspot.com/-Q7n5_t_suPs/VqZSxXUyPQI/AAAAAAAAKKY/C_wmaF65u9M/s1600/bitlocker-xts-aes.png" imageanchor="1"><img border="0" src="http://4.bp.blogspot.com/-Q7n5_t_suPs/VqZSxXUyPQI/AAAAAAAAKKY/C_wmaF65u9M/s400/bitlocker-xts-aes.png" /></a><br />
<br />
GUI 上は暗号化方法を確認出来る画面が見つからなかったのですが、BitLocker のコマンドラインツール manage-bde を使うと以下のように XTS-AES が使われていることを確認できました。<br />
<br />
<pre>C:\WINDOWS\system32>manage-bde -status
BitLocker ドライブ暗号化: 構成ツール Version 10.0.10011
Copyright (C) 2013 Microsoft Corporation. All rights reserved.
BitLocker ドライブ暗号化で保護可能な
ディスク ボリューム:
ボリューム C: [Windows]
[OS ボリューム]
サイズ: 475.98 GB
BitLocker のバージョン: 2.0
変換状態: 完全に暗号化されています
暗号化された割合: 100.0%
暗号化の方法: XTS-AES 128
保護状態: 保護はオンです
ロック状態: ロック解除
識別子フィールド: 不明
キーの保護機能:
TPM
数字パスワード
</pre><br />
<a href="https://technet.microsoft.com/ja-jp/library/mt403325">BitLocker の新機能 (Windows)</a> - 公式のリリースノートのようなものがあります。<br />
<a href="http://www.securevm.org/svms2-slides/svms2-omote.pdf">セキュアVMを支える暗号技術 - 筑波大学 セキュアVM開発室 面 和成</a> - XTS-AES についての丁寧な説明が載っています。Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-58339316154676750282016-01-17T00:59:00.000+09:002016-01-17T01:11:39.758+09:00[windows] 復元ポイントに保存されたレジストリを閲覧する (Windows Vista 以降用)管理者コマンドプロンプトにて、vssadmin list shadows、とすると復元ポイントごとの保存先アドレスが、項目「シャドウ コピー ボリューム」に表示されます。通常の復元機能では見えるコメント欄がないので、通常の復元機能の方で日時の当たりを付けておくと良いと思います。<br />
<br />
出力例<br />
<pre>Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.
C:\WINDOWS\system32>vssadmin list shadows
シャドウ コピー セット ID: {0000000-1111-2222-3333-444444444444} の内容
1 個のシャドウ コピー、作成時刻: 2015/12/26 8:39:27
シャドウ コピー ボリューム: \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1
元のコンピューター: PC123
サービス コンピューター: PC123
プロバイダー: 'Microsoft Software Shadow Copy provider 1.0'
種類: ClientAccessibleWriters
属性: 恒久, クライアント アクセス可能, 自動リリースなし, 差分, 自動回復
</pre><br />
しかしとてもアクセスしにくいので mklink でシンボリックリンクを作成すると便利です。mklink /d SRC DEST で、DEST 末尾の \ を追加で付ける必要があるので注意してください。<br />
<br />
<pre>C:\WINDOWS\system32>mklink /d c:\shadowcopy1 \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\
c:\shadowcopy1 <<===>> \\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1\ のシンボリック リンクが作成されました
</pre><br />
この後は c:\shadowcopy1 に対して、エクスプローラーで閲覧したり、ファイルをコピーしたりすることが出来るようになります。<br />
<br />
レジストリを閲覧するには、レジストリエディタ regedit で、HKEY_LOCAL_MACHINE を選択後レジストリハイブの読み込み機能で、例えば C:\shadowcopy1\Windows\system32\config\SYSTEM を適当な名前 system_shadowcopy1 で読み込み、中を閲覧することができます。不要になりましたらこのキーをアンロードすれば元に戻ります。<br />
<br />
<b>リンク</b><br />
<a href="http://blogs.msdn.com/b/adioltean/archive/2008/02/28/a-simple-way-to-access-shadow-copies-in-vista.aspx">A simple way to access Shadow Copies in Vista - Antimail - Site Home - MSDN Blogs</a><br />
<a href="https://msdn.microsoft.com/ja-jp/library/cc759303(v=ws.10).aspx">レジストリにハイブを読み込む</a><br />
<a href="http://blog.hidekiy.com/2012/11/windows.html">[windows] 復元ポイントに保存されたレジストリを閲覧する (Windows XP用)</a> - Windows Vista 以降では復元ポイントごとにレジストリがコピーされるわけではなく、ボリュームシャドウコピーの中に丸ごと保存されているようなので、以前の記事を更新しています。Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-7965897480892509242015-11-06T23:12:00.004+09:002018-02-25T22:45:25.982+09:00おさいふ Ponta に移行してみました<b>2015/11/3</b><br />
<a href="http://www.osaifuponta.lawson.co.jp/">おさいふ Ponta</a> をローソンでゲットしたので、会員登録を行おうとしました。最初のステップで届くメールが Gmail の迷惑メールフォルダに分類されましたが登録自体は問題なく完了しました。旧カードからの移行は障害中だったのであきらめました。<br />
<br />
<b>2015/11/4</b><br />
次の日の晩、復旧のニュースを見たので早速移行申請し、2015/11/5 の昼頃見てみたら移行完了していました。<br />
<br />
<b>感想</b><br />
Ponta 部分は特に変更なく、発行の敷居の低さに反して JCB デビット自体の機能は十分と思います。<br />
<br />
おさいふ Ponta マイページから暗証番号の登録と <a href="https://www.jcb.co.jp/Jsecure/whats.html">J/Secure</a> (JCB の本人認証サービス) の有効化が行えるので設定すると良いと思います。<br />
<br />
ローソン店頭でおさいふ Ponta 決済をするときは、カードを出した時点でおさいふ Ponta で決済したい旨を伝えなかった場合は、Ponta カードのスキャンだけして返してくれました。<br />
<br />
<b>個別の移行手順</b><br />
<b>ローソンモバイル Ponta</b><br />
Android 端末内蔵の FeliCa に登録するローソンモバイル Ponta の変更はローソンアプリからログアウトして、かざすフォルダのおさいふポンタを削除、ローソンアプリで新 Ponta ログイン、ログイン時にモバイル Ponta 登録オプションを有効にして更新できました。<br />
参考: <a href="http://www.lawson.co.jp/ponta/benri/mobileponta/detail/faq.html#faq_05">5. 機種変更する場合はどうなりますか?</a><br />
<br />
<b>リクルートID</b><br />
リクルートIDとの連携は旧 Ponta 側をコネクト解除して、新 Ponta 側とコネクトしました。これは即座に完了しました。<br />
参考: <a href="http://www.ponta.jp/c/faq/connect/#q-03">Pontaコネクトを解除するにはどうすればよいですか。</a><br />
<br />
<b>JMB×Ponta会員</b><br />
JMB×Ponta会員は旧 Ponta 側でログインし連係解除を行った後、3日目にようやく新カードでの連携に成功しました。ここの連携は日次バッチ?のようなので気長に待つ必要があるようです。<br />
参考: <a href="http://www.ponta.jp/c/faq/jmbponta/#q-07">Pontaカードを2枚持っているが、JMBとの登録カードを変更したい場合はどうすればよいですか?</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-39562546002211383762015-09-29T23:50:00.001+09:002020-09-14T21:24:23.603+09:00[isucon] ISUCON5 予選敗退しましたISUCON5 予選に土曜日の日程で参加しました。チーム名は円山町、チームメンバーは @ymz_kotaro と2人です。主にアプリの改良を担当しました。午後6時半ごろのスコアは12000点ほどで予選敗退しました。<br />
<br />
予選当日の流れは大体こんな感じでした。<br />
<br />
<b>午前11時~午後2時</b><br />
何もいじらずにベンチマーク実行、タイムアウトでFAIL。<br />
my.cnf の設定すべき個所に右往左往しながら innodb_buffer_pool = 1G を設定してようやくベンチマーク通過。<br />
<a href="http://goaccess.io/">GoAccess</a> で nginx のアクセスログを解析してアプリ宛にしかリクエスト来てないと判断し、nginx の設定は放置することとする。<br />
Ruby 実装のまま MySQL にスロークエリログ 0.1 秒を仕込んで pt-query-digest 見る、インデックスなしのクエリを発見したのでひとまずインデックスを修正。<br />
Go 実装に systemd の設定を切り替えてテスト、ベンチマークはエラー多数で FAIL。<br />
エラー原因を目視確認しようとするが見つけられず。試しに一度 go build -o app を実行して再起動すると動くことを発見。<br />
3回連続でベンチマーク正常を確認したのでGo実装を使うこととする。<br />
<br />
<b>午後2時~午後7時</b><br />
Go実装のアプリにデバッグ用サーバー net/http/pprof を組み込んで再起動する。ベンチマークを流しながら go tool pprof で CPU プロファイルを取得し、top50 -cum で関数プロファイル、list GetIndex で行プロファイルを取得して遅い部分を解析<br />
プロファイル上時間がかかっているように見える N+1 クエリを修正。<br />
users テーブルへの書き込みがないので初期化時に全体をロードするいんちきオンメモリ化を施す。<br />
全て修正完了したと思っていた N+1クエリについて、テンプレート関数経由でデータベースアクセスしている部分を発見したので修正。<br />
テンプレートエンジンを高速化しようと試行錯誤するがいまいち早くならず終了。<br />
<br />
<b>午後7時時点でやり残したと思っていた点</b><br />
<a href="https://golang.org/pkg/html/template/">html/template</a> の使い方でリクエストごとにテンプレートを解析していたので何とかする<br />
<a href="https://github.com/gorilla/mux">gorilla/mux</a> を <a href="https://github.com/julienschmidt/httprouter">julienschmidt/httprouter</a> に交換<br />
<br />
<b>翌日の反省点</b><br />
クエリごとに毎回 relations テーブルと JOIN せずに、友達一覧を先にとって、各クエリで再利用したほうが有効なことが <a href="https://github.com/kazeburo/isucon5-elimination-public/blob/master/perl/lib/Isucon5/Web.pm">GoBoldチームさんのコード</a> を見て気づく<br />
ローカルストレージ遅いと聞いてからデータの安全性を犠牲にする感じの MySQL の設定を試していなかったことに気付く<br />
<br />
<b>リンク</b><br />
<a href="http://isucon.net/">ISUCON公式Blog</a><br />
<a href="https://github.com/hidekiy/isucon5q/blob/master/go/app.go">hidekiy/isucon5q - app.go</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-38769763805031234912015-08-01T10:34:00.002+09:002015-10-07T08:52:05.598+09:00Windows 10: EMET 5.2 有効下で Internet Explorer 11 が起動しないInternet Explorer 11.0.10240.16384 と、EMET 5.2.5546.19547 の組み合わせで、Internet Explorer が起動時に音沙汰なくクラッシュします。<br />
<br />
イベントビューアーの Windows ログ > Application には以下のようなログがありました。<br />
<blockquote>障害が発生しているアプリケーション名: iexplore.exe、バージョン: 11.0.10240.16384、タイム スタンプ: 0x559f3a1c<br />
障害が発生しているモジュール名: ntdll.dll、バージョン: 10.0.10240.16392、タイム スタンプ: 0x55a864a2<br />
例外コード: 0xc0000409<br />
障害オフセット: 0x00000000000963e0<br />
障害が発生しているプロセス ID: 0x10c0<br />
障害が発生しているアプリケーションの開始時刻: 0x01d0cbebdd651de2<br />
障害が発生しているアプリケーション パス: C:\Program Files\Internet Explorer\iexplore.exe<br />
障害が発生しているモジュール パス: C:\WINDOWS\SYSTEM32\ntdll.dll<br />
</blockquote><br />
EMET をアンインストールしても回避できますが、以下の公式サポートフォーラムに具体的な解決策がありました。<br />
<a href="http://answers.microsoft.com/en-us/insider/forum/insider_wintp-insider_perf/emet-52-on-windows10-10130/0d0e91db-9fb6-4596-8008-ab9fb5714267">Emet 5.2 on windows10 10130 - Microsoft Community</a><br />
<br />
EMET の設定画面を開いて、Configuration > Apps で、iexplorer.exe の EAF を無効化すると大丈夫みたいです。EAF+ は有効なままでも大丈夫でした。Default Action が Audit only になっていても EAF が有効だとクラッシュするようです。<br />
<br />
この問題に関して、マイクロソフトにはクラッシュレポートが大量に送信されていると思うので、速やかに修正されると思います。問題の修正後はこの一時的な無効化を解除するため、デフォルトの設定にリセットすると安全と思います。<br />
<br />
<b>2015/10/7 追記</b><br />
Windows 10 に正式に対応する <a href="http://www.microsoft.com/en-us/download/details.aspx?id=49166">EMET 5.5 Beta</a> がリリースされていて、EAF を無効化しなくても Internet Explorer が起動するようになっていることを確認しました。<br />
<br />
<b>リンク</b><br />
<a href="https://support.microsoft.com/ja-jp/kb/2909257">EMET 緩和策のガイドライン</a> - アプリケーションごとに互換性のない緩和策が載っています<br />
<a href="https://technet.microsoft.com/ja-jp/security/jj653751">Enhanced Mitigation Experience Toolkit - EMET</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-3479086839376913062015-07-04T22:53:00.004+09:002015-09-04T23:20:03.287+09:00[Node.js] http client がリクエスト6回目以後ハングするNode.js v0.10.x の http.globalAgent は、keepAlive = true, maxSockets = 5 になっているので、同一 Origin に対して5コネクション全てを腐らせるとハングします。<br />
<br />
具体的には <a href="https://nodejs.org/docs/v0.10.36/api/http.html#http_http_get_options_callback">公式ドキュメントの http.get のサンプルコード</a> そのままで、複数回のリクエストを行うようにすると6回目以降必ずハングします。<br />
<br />
<pre><code class="javascript">
var http = require('http');
setInterval(function () {
http.get("http://www.google.com/index.html", function(res) {
console.log("Got response: " + res.statusCode);
// res.resume(); すれば OK
}).on('error', function(e) {
console.log("Got error: " + e.message);
});
}, 1000);
</code></pre><br />
この事情に関しては、<a href="https://nodejs.org/api/http.html#http_class_http_clientrequest">Class: http.ClientRequest</a> の章に丁寧に記述されているとおり、コールバック関数で受ける res は paused readable stream で、on data で内容を読むか、resume で捨てるかどちらかを必ず行う必要があります。<br />
<br />
この状況の詳細なログを見るには、以下のように環境変数 NODE_DEBUG に http を入れるとデバッグログが出力されます。<br />
<br />
<pre><code class="sh">$ node --version
v0.10.39
$ NODE_DEBUG=http node foobar.js
# 正しい場合の出力
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: AGENT socket keep-alive
# ダメな場合の出力
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: AGENT incoming response!
HTTP: AGENT isHeadResponse false
Got response: 302
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
HTTP: outgoing message end.
</code></pre><br />
サンプルコードが間違っているという凶悪な状況だったので、<a href="https://github.com/joyent/node/pull/25471">この PR</a> で修正してもらいましたが、今のドキュメントには反映されていないようなのでメモしておきました。Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-52463081047162671292015-07-04T21:50:00.000+09:002015-12-20T12:09:32.823+09:00[raspberrypi] mackerel-agent を簡単に導入する<a href="https://www.raspbian.org/">Raspbian</a> を使っている場合、こちらの公式 GitHub <a href="https://github.com/mackerelio/mackerel-agent/releases/latest">mackerel-agent - Latest release</a><br />
にて、以下のファイルをダウンロードします。バージョンは 2015/07/04 時点のものです。<br />
mackerel-agent_0.17.1-1_all.deb<br />
mackerel-agent_linux_arm.tar.gz<br />
<br />
deb パッケージをインストールします<br />
<br />
<pre>sudo dpkg -i mackerel-agent_0.17.1-1_all.deb
</pre><br />
この状態だと設定ファイル類は正しく存在するのですが肝心のバイナリが i386 になっていて正常に動作しません。 <br />
<br />
<pre>$ file /usr/local/bin/mackerel-agent
/usr/local/bin/mackerel-agent: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), statically linked, not stripped
</pre><br />
この状態で起動しようとしたとき、/var/log/mackerel-agent.log には以下のような出力がありました。<br />
<br />
<pre>/usr/local/bin/mackerel-agent: 1: /usr/local/bin/mackerel-agent: <E0>^G^H4<F4>4: not found
/usr/local/bin/mackerel-agent: 1: /usr/local/bin/mackerel-agent: ^?ELF^A^A^A^B^C^A<96>^A@<E0>^B^F^PQ<E5>td^F^D<80>^U^De*^D^A^A^F
<8C>^D^H^LP<84>: not found
/usr/local/bin/mackerel-agent: 2: /usr/local/bin/mackerel-agent: Syntax error: word unexpected (expecting ")")
</pre><br />
arm のバイナリに上書きします。<br />
<br />
<pre>$ tar zxf mackerel-agent_linux_arm.tar.gz
$ sudo cp mackerel-agent_linux_arm/mackerel-agent /usr/local/bin
$ file /usr/local/bin/mackerel-agent
/usr/local/bin/mackerel-agent: ELF 32-bit LSB executable, ARM, version 1 (SYSV), statically linked, not stripped
</pre><br />
これで /etc/mackerel-agent/mackerel-agent.conf に apikey を設定すれば動作するはずです。<br />
<br />
各種ファイルがある場所<br />
<br />
<pre>起動スクリプト /etc/init.d/mackerel-agent
設定ファイル /etc/mackerel-agent/mackerel-agent.conf
ログ /var/log/mackerel-agent.log
</pre><br />
リンク<br />
<a href="https://mackerel.io/">Mackerel(マカレル): 新世代のクラウドパフォーマンス管理・監視ツール</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-81738449690822099852014-12-30T08:54:00.001+09:002019-02-03T23:21:05.152+09:00Intel Dual Band Wireless-AC 7260 でスリープ解除後 Wi-Fi が繋がらなくなるスリープ解除後 Wi-Fi が繋がらなくなって、再度スリープ、スリープ解除するか、デバイスの有効無効を切り替えないと復帰しない不具合が、<a href="http://www.intel.co.jp/content/www/jp/ja/wireless-products/dual-band-wireless-ac-7260-bluetooth.html">Intel Dual Band Wireless-AC 7260</a> (Intel® PROSet/Wireless Software and Drivers 17.1) と <a href="http://121ware.com/product/atermstation/product/warpstar/wf800hp/">NEC Aterm WF800HP</a> (ファームウェア Ver1.0.16) の組み合わせで発生していました。<br />
<br />
Intel 側も相互運用性に関する問題を認識しているらしく、<a href="http://www.intel.com/support/wireless/wlan/sb/CS-034875.htm">この解説</a> の通りデバイスの詳細設定で、省電力に関する機能 U-APSD 対応を無効とすることで繋がらなくなる現象は<strike>発生しなくなりました。</strike> 直っていませんでした。以下の追記のご参照をお願いします。<br />
<br />
<a href="https://4.bp.blogspot.com/-geG2qBtYOqg/VKHnqC8WHSI/AAAAAAAAGb0/rrM5JSLOQYc/s1600/intel-wifi-uapsd.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-geG2qBtYOqg/VKHnqC8WHSI/AAAAAAAAGb0/rrM5JSLOQYc/s320/intel-wifi-uapsd.png"></a><br />
<br />
<b>2015/01/22 追記</b><br />
U-APSD 無効の設定でもしばらく使っていると切れたままになる現象は起こったので、この機能は原因ではなかったようです。<br />
<br />
ドライバのバージョンを 17.13.11 に更新して、設定は U-APSD も含めて初期状態で、2週間ほどスリープを駆使しながら使っているのですがまだ一度も発生していないので、ドライバの更新をお勧めします。<br />
<br />
<a href="https://4.bp.blogspot.com/-I0mkv1eKIkU/VMA4m8Pv3PI/AAAAAAAAGfE/7tuKbgFmPk0/s1600/intel-wifi-driver.png" imageanchor="1" ><img border="0" src="https://4.bp.blogspot.com/-I0mkv1eKIkU/VMA4m8Pv3PI/AAAAAAAAGfE/7tuKbgFmPk0/s320/intel-wifi-driver.png"></a><br />
<br />
<b>リンク</b><br />
<a href="http://www.intel.com/support/wireless/wlan/sb/CS-034875.htm">Intel® Wi-Fi Products — TechNote: Access Point Interoperability Issue with uAPSD</a><br />
<a href="https://downloadcenter.intel.com/Detail_Desc.aspx?DwnldID=24576&lang=jpn">Windows 8.1* 用インテル® PROSet/Wireless ソフトウェア - インテル® ダウンロード・センター</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-73168150284160165582014-12-29T12:58:00.000+09:002014-12-29T13:08:51.654+09:00CloudFlare: サブドメイン毎に Flexible, Full SSL を設定するCloudFlare の SSL 設定の種類 (<a href="https://support.cloudflare.com/hc/en-us/articles/200170416">What do the SSL options (Off, Flexible SSL, Full SSL, Full SSL Strict) mean?</a>) の設定について、ドメイン全体に適用されるグローバルな設定だけでは不十分なときは、Page rules の SSL から個別に Flexible SSL にするか Full SSL にするかなどの設定を行うことが出来ます。<br />
<br />
設定画面へは My websites から、右の歯車を押して、Page rules で行けます。対象とするパスは www.example.com/* のように入力すれば OK みたいです。<br />
<br />
Page rules の設定は Free plan だとドメインあたり3個までなので、足りない場合は <a href="https://www.cloudflare.com/plans">Pro plan</a> に移行する必要があります。Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-84142156211313283852014-12-28T10:16:00.000+09:002014-12-28T22:16:03.511+09:00.htaccess を使って利用可能な Apache モジュールの一覧を取得する共有サーバーなど、httpd.conf や mod_info の server-info を確認できない状況で、組み込まれているモジュールを確認するには、IfModule と Header append を組み合わせると、指定した中で利用可能なモジュールをレスポンスヘッダー X-Module に出力することができます。<br />
<br />
<pre><code># .htaccess
<IfModule mod_deflate.c>
Header append X-Module mod_deflate
</IfModule>
<IfModule mod_expires.c>
Header append X-Module mod_expires
</IfModule>
<IfModule mod_rewrite.c>
Header append X-Module mod_rewrite
</IfModule>
<IfModule mod_ratelimit.c>
Header append X-Module mod_ratelimit
</IfModule>
<IfModule mod_setenvif.c>
Header append X-Module mod_setenvif
</IfModule>
</code></pre>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0tag:blogger.com,1999:blog-8485271176279834216.post-81088992577112402542014-12-13T10:24:00.001+09:002014-12-13T10:24:38.695+09:00Chrome でダウンロードしたファイル名の一部がハイフンになる<a href="https://www.google.com/chrome">Google Chrome</a> で Content-Disposition ヘッダでファイル名に時刻 (12:34:56) のような文字列を入れてダウンロードするとなぜか勝手に 12-34-56 のようにハイフンになってしまう理由が良く分からなかったのですが、Windows ではそもそもファイル名にコロンは使えないので、安全のため全プラットフォームでファイル名にコロンを含む文字列を設定しないようになっているからみたいです。<br />
<br />
変換対象の文字一覧は、<a href="https://chromium.googlesource.com/chromium/src.git/+/39.0.2171.95/net/base/filename_util_unsafe.cc">filename_util_unsafe.cc</a> の illegal_characters に入っていて、変換先がハイフンになる理由は、<a href="https://chromium.googlesource.com/chromium/src.git/+/39.0.2171.95/net/base/filename_util_internal.cc">filename_util_internal.cc</a> の GetSuggestedFilenameImpl でコールバック関数 replace_illegal_characters_callback を第二引数を '-' として呼び出しているからのようです。<br />
<br />
ReplaceIllegalCharactersInPath の使い方は変換先を ' ' にしたり '_' にしたりするバリエーションがあったので、必ずしもハイフンに変換されるという訳ではないみたいです。<br />
<br />
リンク<br />
<a href="https://chromium.googlesource.com/chromium/src.git/+/39.0.2171.95/net/base/filename_util_unsafe.cc">https://chromium.googlesource.com/chromium/src.git/+/39.0.2171.95/net/base/filename_util_unsafe.cc</a><br />
<a href="https://chromium.googlesource.com/chromium/src.git/+/39.0.2171.95/net/base/filename_util_internal.cc">https://chromium.googlesource.com/chromium/src.git/+/39.0.2171.95/net/base/filename_util_internal.cc</a>Hidekihttp://www.blogger.com/profile/18337582122205578131noreply@blogger.com0