窓を作っては壊していた人のブログ

この謎のブログタイトルの由来を知るものはもういないだろう

ISUCON11予選にソロ参戦して敗退しました

今年もISUCONに参戦してきました

昨年は社外の人と組んで3人チームで参加したのですが、今年はそういった話も特になかったのもありソロでの力を試してみたくソロ参戦してきました。

得点は17767点で235位(?XPathで適当に調べたけど合ってるはず)でした。 要は半分より上ですヤッター

isucon.net

やったこと

github.com

こちらのリポジトリにコミットしてあることだけです、本当にこれだけ。

今年は3台構成が可能だったのですが、それを試す時間もなく1台のアプリケーションをいじっていくだけの感じになりました。

git管理

差し戻しが出来るようにってことで今回ガッツリいじっていくGoのディレクトリとその他必要なディレクトリや、ミドルウェアの設定の管理をしました。

いい感じのMakefileを配置

2週間ほど前に練習した時に使ったMakefileを配置して、覚えるコマンドを減らしていきました。 これからはこのMakefileを育てていこうかなと思っています。

Goのバージョンアップ

Go 1.16系が使われていたので最近出たどうも速いと言われている1.17系を使うようにしました。 シュッとバージョン上げることが出来るのはGoの利点ですね。

User情報のキャッシュ

まずはINSERTやUPDATEがかかっているかみたいなことをざっくり見てキャッシュするのが簡単そうなやつからスタート。

Userのcache · yamachu/isucon11-qualify@b8c485f · GitHub

キャッシュできるものはやってしまえな考えから…この時はまだ計測とかはしていない。

getIsuListのN+1の解消

alp見たらこのエンドポイントがめちゃくちゃSUMで見たら大きかったので対処していこうってことで始めた。

サブクエリで一気に取る · yamachu/isucon11-qualify@fbb2e13 · GitHub

そもそもGo書いてないからどうやってStructにマッピングするんだよとかキレながら実装。 SQLも書けないのでググりながらやりたいことの単語を入れてそれっぽいSQLパクって 参考にして実装。

割とこの施策で上がった。

Icon画像をDBに入れるのをやめてファイルに落とし込む

DBにBlobを突っ込んでるのをやめる · yamachu/isucon11-qualify@32303f7 · GitHub

Revert "DBにBlobを突っ込んでるのをやめる" · yamachu/isucon11-qualify@ecf5301 · GitHub

Bye 画像 · yamachu/isucon11-qualify@148b715 · GitHub

一回リバートを挟んだ施策。 alpで見たらちょっとリクエスト多めかな…?と思えたので試してみた。 昔のISUCONでもDBからBlobを排除したら負荷が落ちたみたいのがあった記憶があったのもあり試した。

リバートをするのに至った理由としてはベンチで404とか302とかが返ってきて欲しいのに200が返ってきたみたいなログが見えてダメそうだと思ったから。 けどその意味をその時にちゃんと理解していればリバートいらなかったんじゃ…

ということで終了直前にこれpostIsuでロールバックかかってるじゃんに気づき(SlowQueryみてもその辺りの処理が多かったのが気になっていた)画像もロールバック(削除)したら200にならないじゃんになり試したら通った。

正直あまりスコアは上がらなかった(上がったのは1000点ぐらい)。

Bulk Insertを試す

bulk insert一番いい · yamachu/isucon11-qualify@70ce3d7 · GitHub

毎回数十件以上のINSERTするPayloadが飛んできていて、DBのロック時間がめちゃくちゃ取られるだろうなって想像してBulk Insertに変更。 2〜3000点ぐらい上がった記憶がある。

最新のISUのConditonをキャッシュする

早くなるはず(ベンチ回せない) · yamachu/isucon11-qualify@e6f1843 · GitHub

getIsuListでも行われていた最新のisuConditionを見てごにょごにょする処理。 同じクエリを使いまわしても良かったのだけれども、これテーブルに分けたほうが楽ではと思ったのでテーブル分けて実装。

getTrendはこれを採用したら一気にスコアが上がったけれども、getIsuListで使ったらスコアが10000以上落ちて何も分からなかったのでこのキャッシュはTrendだけで採用した。

反省

結局これしか出来なかった。

必死にクエリ書くのを1時間ぐらい頑張っていたけれども、最初っからテーブル分けるかRedisやOnMemoryキャッシュ試すとかに移れればよかったなと思った。 判断が遅い。

あとMariaDBのConfigにSlowQuery吐き出すためのフラグのやつがなくて出ない出ない!!!!!で騒いでたのがアホだった。

show variables like '%slow%';

でOFFになっているのを何度も見ているんだからONにするのを一回書こうねっていう………。

あと最初にコメントアウトでこの辺り数字変えると上がるはずだから変えろっていうのも忘れていたり、INDEX貼り忘れがあったりと初歩的なミスが多かった。 これやれば上がるは早めに頭を使わなくても出来るように練習をもうちょっとしておこうと思った。

後はベンチ回せない時にレスポンス合っているのかを自分で試せる施策を今後は試していきたい。

来年は頑張ろう!!!!!!来年も個人スポンサーやって応援しよう。

MAUIのようなMulti TargetingなC#のプロジェクトをVSCodeで開発する際、Targetを切り替えやすくする拡張を作った話

まず最初に成果物のリンクを。

marketplace.visualstudio.com

VSCodeとMulti Targetingなプロジェクトの今

VSCodeMulti Targeting な Project を開くと、基本的には <TargetFrameworks></TargetFrameworks> に囲まれた先頭のTargetがコード補完などに使用するTargetに設定されます。

そのため、例えばmacOSで先頭が.NET Frameworkなプロジェクトを開くとコードが補完されない、もしくはOmniSharpが正常に動作しないといったことが起こります。 そのため取り入れられている解決手段としてTargetFrameworksの先頭に.netstandardなTargetを持ってくるといったものがあります。

例えばこんなPR

Improve Visual Studio Code support by pellared · Pull Request #2015 · open-telemetry/opentelemetry-dotnet · GitHub

この様にまずはプロジェクトを開くことが出来るようにしようというのは全とっかえで済むことがわかっています。

では、そんな中なぜこの拡張を作ったのか、その理由などを次に述べます。

Targetを切り替えたくなるプロジェクト

最近クロスプラットフォーム開発フレームワークMAUIPreviewですがリリースされました。 MAUIについては詳しくは述べませんが、一つのプロジェクトでiOS, Android, macOS, Windows向けのアプリケーションが作れるものと認識してもらえれば。

このMAUIを採用するアプリケーションもMulti Targetingなプロジェクトとして作られるのですが、前述したように基本的には <TargetFrameworks></TargetFrameworks> に囲まれた先頭のTargetがコード補完などに使用されます。 これが何を意味するかと言うと、Platform非依存のInterfaceを定義して、Platform依存の実装を書く際にTargetFrameworksの先頭に対象のPlatformのTargetが書かれていないとコードの補完が行われず、PlatformのAPIエスパーして書かなければならないということです。 流石にエスパーして書くわけにはいかないので、対象PlatformのTargetを先頭に持ってきたりするわけですが、そういった書き換えを自分で行うのは非常に手間がかかります。

そのためその書き換えに近いことを行うことを支援する拡張として TargetFrameworksSwitcher for C# が生まれました。

拡張機能が提供する機能

拡張機能名前そのままですが、TargetFrameworkを切り替えてくれます。

動作の様子は以下のGifを。

f:id:yamachu_co:20210725202805g:plain
Switch target framework by using extension

この様に拡張機能を使って定義されているTargetを指定すると、そのTargetのAPIなどが補完されるようになります。 上記のGifではMAUIのプロジェクトで利用したものですが、例えば

jwt/JWT.csproj at c871e2428c1587c237069c509a530635076d53bf · jwt-dotnet/jwt · GitHub

<TargetFrameworks>net35;net40;net46;netstandard1.3;netstandard2.0;net50</TargetFrameworks>

のように、先頭に.NET Frameworkが含まれるプロジェクトでも同様に動作します。

macOSLinuxでこういったプロジェクトを開発する方にとっては割と便利な拡張なのでは?と思うので、是非とも使ってみてください。

以下どういう仕組なのか知りたい人向け

どの様に実現しているか

拡張機能リポジトリ

GitHub - yamachu/TargetFrameworksSwitcherForOmniSharp

実際のコアライブラリ

GitHub - yamachu/NodeCsprojModifier

上記のコアライブラリを見てもらえるとなんとなくわかると思うのでさらっと解説。

MSBuildのtargetファイルに明示的に<TargetFramework></TargetFramework>のプロパティを挿入し、そのtargetファイルをcsprojから読むようにして実現しています。

TargetFrameworkSwitcher.targets

<Project>
    <!-- NOTE: DO NOT EDIT YOURSELF
        You should add this file to gitignore
    -->
    <PropertyGroup>
        <TargetFramework>net6.0-maccatalyst</TargetFramework>
    </PropertyGroup>
</Project>

Some.csproj

<Project Sdk="Microsoft.NET.Sdk.Razor">
+   <!-- NOTE: TargetFrameworkSwitcher inserts it, DO NOT EDIT YOURSELF and IT REQUIRES TOP-LEVEL EVALUATION BEFORE USING "TargetFramework" VARIABLE -->
+   <Import Project="$(MSBuildProjectDirectory)\TargetFrameworkSwitcher.targets" Condition="Exists('$(MSBuildProjectDirectory)\TargetFrameworkSwitcher.targets')" />
+

これはMAUIプロジェクトで拡張機能を使って net6.0-maccatalyst をTargetFrameworkに指定した例です。 プロジェクトの先頭でtargetsをImportしTargetFrameworksの構成を変更せずTargetFrameworkを指定する、と言った方法で切り替えを実現しています。

NOTEとして書いているように、targetsファイルはあってもなくてもビルドは出来るというものにすることで、Visual Studioで開発している人とVSCodeで開発している人、拡張機能を入れている人と入れていない人でも問題ないようにしています(そのためどちらかと言うとlocalファイルないしuserファイルに近いのでignoreすべきと書いています)。

OmniSharp-Roslyn自体を拡張するのは非常に大変ですが、VSCode拡張機能で監視されているcsproj自体に作用してしまえば解決できると思ったこの課題、手法としては悪手ではなかったと思うので自分では満足しています。 使っていく中で見つけた更なる課題や、使ってくださった方からIssueが上がったらまた解消していこうと思います。