Windows 10 May 2020 Update(Ver. 2004) に伴うPuTTYのフリーズ
本家PuTTYでは発生せず
Windows 10 May 2020 Update(Ver. 2004)にアップデートしたところPuTTYが接続時にフリーズするようになったため、調査まとめ。
(実際にはかなり前からノートPCで同症状になっていたが、だましだまし使っていた)
発生条件
- Windows 10 May 2020 Update(Ver. 2004)適用済み
- Listboxにフォーカスがある状態で軽くEnter
確認済みの影響範囲
再現手順
- PuTTYをインストールする
- SSH接続先を指定して保存する
- (不要かもしれないが)PuTTYを再起動
- ListBoxにフォーカス
- ListBoxからセッションを一つ選んで軽くEnter ※1
- ターミナルが開きユーザー入力待ちになるがフリーズ ※2
※1 後述するようにEnterキーを押す時間が長いと発生しない
※2 初回接続の場合は [SshHostKeys]
への追加ダイアログを表示してフリーズ
解決方法その1: 別のショートカットキーを使用
Alt + l → Alt + oなら発生しない(タイミングの問題かもしれないが)
解決方法その2: AutoHotKeyによる対応
iceiv+putty & 日本語化パッチ未適応の場合。
PuTTYrvの場合はクラス名が xListBox1
になる。
IsControlActive(ClassNN, WinTitle) { ControlGetFocus, CurCon, % WinTitle Return (CurCon=ClassNN) } ; Windows 10 2004でPuTTY PRIVATE PATCHESがフリーズする問題の対策 #If IsControlActive("ListBox1", "PuTTY Configuration") Enter::Send {Enter down} return #If
解決方法その3(?): Enterキー長押し
AutoHotKeyでいろいろ試した際の挙動からするとWM_KEYUP
がListBoxに飛ぶとまずいように見える。
実際、Enterキーを長めに押す(WM_KEYUP
を遅らせる)ことで、問題なく接続できた。
ただ、長く押しすぎるとユーザー名入力のプロンプトをスキップして終了してしまうため、現実的ではないか。
参考: 同症状?
ISUCON10予選に行ってきました。
毎度ながらとても楽しい8時間でした。時間が経つのが早い早い。
手元でのスコアは396(Python初期実装) -> 1601。それなりには増やせたものの、2歩ほど足りずに予選落ちとなりました。
例によって一人参加なので全部に手が回らないのは承知の上。
計測して遅い場所を解決するのを繰り返していきましたが、去年と同じく今年のベンチもスコアが安定しており、特に低スコアでもちゃんと差を出してくれていたのがとてもありがたかったです。
(とはいえ、最後までDBサーバーのCPU律速だったので、要らない修正もありましたが)
最後までDBのCPU使用率に悩まされたISUCONでしたが、Indexが思ったように効かなかったり、B-Treeの仕組みを把握しきれていない所がもろに出た感じですね。
定番の修正は以下のあたり
- Index付与
SELECT *
修正- N+1クエリ削除
- Nginxの静的ファイルキャッシュ
最終構成
- isucon1: Web/AP
- isucon2: AP
- isucon3: DB
前回と同じく定番の構成でした。
終了後にrandomで出ていましたが、DBを2台構成にして垂直分散というのが目から鱗でしたね。
確かにJOINもないし2テーブル……最後までDB CPUに悩まされていたのもあって「その手があったかー」感がすごい。
nazotte検索をOpenCVへ
動作を見たところ凸包検索だったので外積で内包判定ができるパターン。
ゲーム作りがこんなところで役に立つとは思わなかった。
DBサーバーの負荷が高いのもあって、APサーバーにopencv-pythonを入れて判定するように変更。
low_pricedのオンメモリキャッシュ
あまり変動しないのでメモリ上にキャッシュしましたが、複数台構成になるとCSVインポート時に http://isucon2/api/update_cache 的なリクエストが必要になってちと微妙だった。
呼ばれる回数が多いので何か対策を取りたいところだが、redisキャッシュとかでも良かったか。
単純に自分以外のサーバーに/api/update_cache呼ぶようにしたらisucon1 -> isucon2 -> isucon1と無限ループして落ちたりも。
range_idのカラム追加
範囲検索やらAND条件だらけを=の検索にできるのでそれなりに効果はあった感じ。
PG側で何とかしましたが、chair.priceの条件違いで30分ぐらい嵌りました。
分かりやすい問題点なだけに他の人も似たことをやっている人が多かったようですね。
ORDER popularity, idをsort_keyにまとめる
DESC/ASCの混在もあってIndexが効かなかったのでORDER BY用にsort_keyを追加。
generated columnsを知らなかったので、こちらもPG側で力業。
出題側の想定回答の1つだったようで、たどり着けたのは良かったです。
MySQLの全文検索(FULLTEXT INDEX)による機能検索
[Stashed]
サンプルスクリプト作って MATCH(features) AGAINST ('+IHコンロ +フローリング' IN BOOLEAN MODE)
などで検索できることは確認したものの、結局他のクエリが削り切れずにお蔵入り。
困ったところ1
ベンチマークがログ無しFailしてるけど、サーバー側ログにも何もない場合、原因追及が辛かったですね。
スコアは安定していたのですが、Portalの安定性も含めベンチマーカーからはもう少し情報が欲しかった所。
困ったところ2
Portalの不安定さや、直前のベンチマーカー全滅もあって、16:53の以下の発言を競技Portal自体の停止と勘違いしました。
あくまでleaderboardのみで、ベンチマーク自体は実行できたんですね……
16:53 根本対応を進めるため、 leaderboard を一瞬封鎖させてください
結局18:38の発言までベンチマーカーを動かさずに手元で開発していたので、ここのロスは痛かったです。
18:38 念の為書くとベンチはジョブリストから回せます
複数コミットあると前項の問題もあってベンチマーカーが落ちた場合の原因追及がつらい……
最後に
運営のみなさん、本当にありがとうございました&お疲れ様でした。
今回はコードも読み切れる量でちょうどよく、オーソドックスなISUCONでありながらもあちこちに問題のある良問だったと思います。
社内ISUCONとかに使いやすい感じ。
今回は足りませんでしたが、延長戦含め、来年また頑張ります。
ISUCON9本選でFailしてきました
TL; DR
- スコア: 0 → 1,227 → 8,181 → 19,023 → 0(Fail)
- リポジトリ: https://github.com/Sheile/isucon9
- 来年はスコアを残せるように頑張る
後は備忘録的にやったことや、嵌った点などをツラツラと。
スコア
予選と違っていつもと同じリクエスト数基準になりましたが、ベンチの出来が良いのか、スコアはかなり安定していたように思います。
他のチームだとリクエストを捌ききって、3連続で同じスコアとかもあったみたいですが、見た感じこちらでは起きていないので、まだまだ足りなかった様子。最後までCPUボトルネックでした。
- 初期実装 + 少しIndex: 1,227
- 1台構成で最適化: 8,181
- 3台構成(?): 19,023 ※後述
- 再起動後: 0 (Fail)
やったこと
事前準備
環境構築や測定用のスクリプトを準備。
- いつものdotfiles
- pt-query-digest
- kataribe
- netdata
1人参加では全体をいじるのはどうやっても手が足りないので、予選と同じく、計測して一番重い場所を直す、の繰り返しで進めることにする。
当日朝
9:15ぐらいに会場入り。すこし悩んだけどキーボードとマウスを持ち込みで。
焦っているときのタイプミスはさらなる焦りを呼ぶので、持って行って良かったと思う。
10:00-11:30
一人参加のメリットを活かして3台のサーバーにいつものdotfiles / 開発環境を構築。
続いて計測用の設定……あれ、/etc/mysql
がスカスカ?ってdocker composeだ!
だいぶ前の記憶を呼び起こしつつ、isutrain/webapp/mysql/conf.d
にslowクエリ用設定を書くが、slow_query_log_file
は変更されるのに、slow_query_log
がOFFのままという問題に悩まされる。
mysql> show variables like 'slow%'; +---------------------+-------------------------+ | Variable_name | Value | +---------------------+-------------------------+ | slow_launch_time | 2 | | slow_query_log | OFF | | slow_query_log_file | /var/log/mysql/slow.log | +---------------------+-------------------------+ 3 rows in set (0.00 sec)
試行錯誤して解決したが、 /var/log/mysql/slow.log
への書き込み権限が無いとOFFになる様子。
(ONだけどファイルが作られないなら、すぐに気づけたと思うんだが)
改めてdocker logs
見たら書いてあったので、Docker慣れが足りなくてもったいないことをした。
2019-10-06T01:25:44.909172Z 0 [ERROR] [MY-011263] [Server] Could not use /var/log/mysql/slow.log for logging (error 13 - Permission denied). Turning logging off for the server process. To turn it on again: fix the cause, then either restart the query logging by using "SET GLOBAL SLOW_QUERY_LOG=ON" or restart the MySQL server.
11:30-11:50
Slowクエリを元にIndexを追加。
とりあえず検索結果が見られるようになったのでベンチ実行
【初期スコア 1,227】
12:00-12:30
お昼ご飯食べながら方針検討。
デバッグのしやすさなどを考え、開発中はPythonをDockerコンテナの外に出すことに。
search/seatのN+1がひどいのでそこから手を付けることにするが、200行近くあるメソッドにめまいがする。
塚田農場のご飯美味しい。
13:25
station_master
をオンメモリに。/api/train/search
が少し落ち着いたので/api/train/seat
へ
【スコア 1,503】
14:25
reservations
にdeparture_id
, arrival_id
を追加して、2テーブルの結合で済むように。
優勝チームの話を聞いているとseat_reservations
の方に追加していれば1テーブルで済んだようだ。
【スコア 3,895】
15:50
seatのN+1を解消。
ご丁寧に「他予約の下車駅と自分の乗車駅が同じ場合は予約が取れる」といった仕組みがあるので、不等号にはまる。
あのドタバタの中で<
と<=
の条件を(しかも被る条件が欲しかったので反転して)考えるのは焦りっぷりがすごい。
readline
のバージョン?なのか、mysql-cliで検索クエリに日本語が入れられなかったのも拍車をかける。なんとか修正。
seat_list[seat_row * 5 + seat_column]['is_occupied'] = True
で直接occupiedフラグを書き換えられないかと思いついたが、先にデータ確認したら4列席の列車があったので断念。
【スコア 4,509】
16:10
あれこれ嵌ってたのもあって、時間がたつのが早い。
手が入れられていないpaymentやロックで待ち時間があるのもあって、CPUの上下移動が激しくなってきたので、(予選でもスコアがはねたし)APサーバーの台数を増やすことに。
とりあえずworkerを増やしてみる。
【スコア 6,715】
~16:53
ロック漏れによる多重発券に悩まされFail連発。
そういえば、事前説明に「ロックがちゃんとしていない」とあったなぁ……
読んではみたものの、300行近くあるreserveで原因追及は残時間では無理!と、広めのテーブルロックをかけて対処する。
【スコア 6,959】
17:00
残り1時間。
時間的には再起動試験とかに入りたいところだが、worker増加の効果が分かっているし3台は使い切りたい。
(実際はこの前にもベンチマーク中にB/Cサーバーの設定などは行っていたのである程度の準備はできていた)
なんとなく一番後ろがDBの印象があるのでサーバーCをDBサーバーにすることに。
docker-compose.db.yml
として切り出して、マニュアルに従ってDBサーバーを再構築……あれ、重……い……?
原因自体は(おそらくだが)すぐに分かった。
01_schema.sql
にあれこれIndexを張った状態で、時刻表マスタの280万件をいれようとして、死ぬんだ。RAM1GBの非力な環境というのも影響して、Swap地獄になっているっぽい。
状況はみるみる悪化し、SSHはつながらない、ps
は結果が返らない、systemctl stop
も動かないとボロボロに。
[isucon@team103-c]~ % ps -eaf | grep mysql zsh: fork failed: cannot allocate memory
ぎりぎり残っていたターミナルからsudo systemctl disable isutrain-db; sudo reboot
を投げるが反応が無い。エラーにはなっていないので、通るのを祈る。1
これ、もう無理じゃね?と思いつつも1台構成では10,000超えないのもわかっているので、ギリギリまであがくことに。
サーバーCは無事再起動できたとしても、データが破損してるので使えない。
サーバーBをDBサーバーにすることにして、同じ轍を踏まないようにALTER TABLE
していく。
01_schema.sql
にしか変更を残していなかったので、git log -p
からALTER TABLE
を作るのがまた大変。
並行してサーバーAのnginxにロードバランシングの設定を追加。
これ自体は予選の時にも経験済みなのでさくっと。
17:35ぐらい?
サーバーCがなんとかsudo reboot
まで通って再起動してくれたので、DBサーバーからAPサーバーに仕立て直していく。
あわわわわ
17:52
どのタイミングで実行してたのかわからないが、少しだけ高いスコアが記録されていた。
--workers 4
あたりだろうか。
【スコア 8,181】
17:55
APをdockerコンテナに戻したらDBに繋がらない!
.env
にはMYSQL_PORT
が無いことに気づき、慌ててDBサーバーを3306:3306
に。
17:56
正直、これがなぜ通っていたのか、いまだによくわからない。
当時は以下の3台構成が動いたと思っていた。
- A: APサーバー(4worker)
- B: DBサーバー
- C: APサーバー(4worker)
が、再起動後の状況を見るとサーバーCは.env
が最新化されておらず、DBサーバーへの接続ができていなかった。(ので最終結果がFail)
サーバーAでsystemctl restart nginx
したタイミングが分からないが、ひょっとすると、ロードバランシングの設定書いた後に再起動していない?
ただ、下記構成で19,023出るかというと……謎。
- A: APサーバー(4worker)
- B: DBサーバー
【スコア 19,023】
17:57
再起動しても問題を直す時間は無さそう。
APサーバー/DBサーバーを頻繁に切り替えたのもあって、systemctl disable/enable
の確認と修正に時間を費やす。
(後から考えるとそれでも再起動しておくべきだったか……)
最終結果
前述のとおり、サーバーCで最後のgit pull
が漏れており、.env
が最新化されていなかった。
結果、MYSQL_HOST
がサーバーBになっておらず、接続に失敗。
ということで最終結果はFail(0)となりました。
もったいないことしたけど、最後の1時間は全力以上でやり切った感はある……でもスコアが残らないのはやっぱり悔しい。来年の開催があったら残り時間を考えつつ頑張ろう。
最後になりますが、運営・問題作成・サーバー提供をしていただいたLINE様、さくらインターネット様、mercari様、Alibaba Cloud様、楽しいイベントをありがとうございました!
-
終了後にサポートチャットを見たら、似た症状で再起動してもらっているチームがあった。なかーま。↩
ISUCON9 予選
ISUCON9お疲れ様でした。
去年に引き続き「RE: ゼロから始めるISUCON」として1人チームで参加して来ましたが、無事16位に入ることができ、来月の本選に出場できることになりました。 3回目の挑戦で初本選ですね。ばんざーい ∩( ・ω・)∩
予選の感想
出題がSAKURA internetさんと、mercariさんということで、椅子を販売するサイトisucariでした。
「ベンチマーク」が「ベンチ」ジャンルに入っていたり、時間に追われながらもくすりとさせてもらいました。
ISUCON的にはRDBボトルネックから始まるものの、割とすぐに外部APIにボトルネックが移った印象。
結局API呼び出しをある程度減らしつつ、とにかくWorkerを増やすことでAPI結果待ちの間に他Workerが処理するようにしてスコアを稼いでいました。
感想部屋見ているといろいろ足りていなそうなので、怖いながらも講評が楽しみ。
使ったもの
最終的な構成
1台目:
- nginx(load balancer,
/upload
の画像配信) 1 - gunicorn (weight: 8)
2台目:
- gunicorn (weight: 10)
3台目:
- MySQL
- gunicorn (weight: 5)
やったこと
オーソドックスに計測・一番重い場所を改良の繰り返し。
items.root_category_idを追加
重いクエリの改善
categoriesテーブルをオンメモリに
親カテゴリ名まで含めて辞書定義
index追加
Slowクエリを元として、主にitems
にindexを追加
外部APIを出来るだけ呼ばずに済むように
この辺りで目立つSlowクエリが無くなって、API呼び出しが支配的に。
正直、これが正しかったのかはわからないですが、netdataで見ているとCPU使用率が0%と100%を行き来していたのでAPIのレスポンス待ちでworkerを使い切っているのかなー、と。
この時はcompaign
上げてなかったので、単純にベンチマーカーからリクエストが来ていなかったのかもしれません。
APIレスポンスの内容をJSONに含めて返す必要があったため、遅延処理もできず、workerをがっつり増やして対応。
改めて考えると裏でポーリングしておく手もあったかも?でもwait_shipping
以降の物が増えると破綻しそうだなぁ。
APIドキュメント読む→QRコードの実装に迷い込む
APPLICATION_SPEC.md
, EXTERNAL_SERVICE_SPEC.md
を読んで、Shipping statusがisucari側である程度把握できる(=APIレスポンスする必要が無いタイミングがある)ことを知る。
/accept
のタイミングがわかれば、大部分はわかるはず。でもこのURLは外部サービスのものだし……はっ!荷物を引き渡すときのQRコードを差し替えて、isucariを経由させれば……と実装。
1.5時間ぐらいかけて実装してみたものの、QRコードのvalidationに引っ掛かってしまってgit stash
orz
確かにレスポンスの変更にあたるからルール的に変更不可か……
3台構成に
アプリ側がうまく行かなくて凹んだのでインフラ側へ。
RDB負荷はある程度減らせていたようなので、DBサーバーにもgunicorn入れて数で勝負。
画像ファイルの配置がバラけてしまったのでNFSで無理やり共有。2
/upload
以下はnginxで提供。
結果
Job一覧を見ていると、こんな感じか。
- 13:45まで:色々手は入れているものの初期スコアのまま変化なし
- 14:00ぐらい: 3000点に上がって喜ぶ
- 14:20ぐらい: API関連弄って6000点
- 14:30ぐらい: worker数増やして9560点、一瞬だけ1位に
- 16:00ぐらい: QRコード系をあきらめてインフラ側へ
- 18:00ぐらい: ガチャが安定していたので数回走らせて12,960で終わり
最終スコアは12,960、最高スコアは13,560でした。
実はcampaignを上げるタイミングを逃し、後半で上げてみたら外部API呼び出しがエラりまくったので0のままです……(小声)
maimaiでらっくすの問題点
maimaiでらっくすが出て1か月ちょい。 色々困る点はありつつも、それなりに慣れたので改めて問題点を書いてみます。
書いてる人
- 無印maimaiからなので7年ぐらい
- FiNALE 8段 Max 15.58(3470クレ)
- でらっくす 9段 Max8500(75クレ)
それなりには出来るけど、上位の人たちとは大分差がある、でもmaimaiたのしー。な人です。
達成率(スコアシステム)
5月に公式にメールした時の記事にも書いていますが、1.02を受けて改めて。
マシにはなった、マシにはなったんだけど方向性が変わってないので、問題点も変わっていないです。
前回記事でも書きましたが、今作のスコアシステムの問題点は以下の2点(後者が前者の原因なので実質1点か)
- プレイヤーのうまくできた感と達成率がリンクしていない
- 極端なBreakの精度ゲー
1.02になっても解消はされておらず、「ヒバナ」のMasterを例にするとこんなことになります。
パターンA(色々失敗したがBreakはCritical Perfect)
Great 10 / Good 1 / Miss 2(-100 * 10 - 250 - 500 * 2 = -2250
)
Break2つはどちらも2600
(501500 - 2250) / 501500 + 1%
→ 100.5513%
パターンB(ほぼミス無しだがBreakがPerfect)
1グレのみ(-100
)
Break2つはどちらも2500
(501500 - 100) / 501500 + 0.5%
→ 100.4800%
パターンC(Bと同じ1グレだがBreakがGreat)
1グレのみ(-1000
)
Break2つは1500と2500
(501500 - 1000) / 501500 + 0.25%
→ 100.0506%
FiNALE以前はBreak1グレ = Tap10グレ~11グレ相当だった でらっくす(ヒバナ)だと0.25% = 1253.75点相当が追加されるので、Break1グレ = Tap23グレ~24グレに相当する
問題点
パターンAを見ればわかりますが、SSS+なんてフルコンすら要らないんですよ。Breakだけ光れば他がボロボロでも乗ります。
逆に、どんだけうまくできてもBreakが光らなければ達成率はボロボロです。
高スコアを出すためには何よりもBreak精度が重要になるわけですが、少なくとも私は、譜面の極一部でCriticalが出るか出ないか(2F)に拘るようなゲームをやりたいわけではありません。
また、1.02の変更で2500にも追加加算が付きました。maimaiは元々Break1グレ = Tap10グレ相当と、Breakの比重が高いゲームですが、(譜面のBreak数次第とはいえ)これ以上あげる必要はあったのでしょうか。
達成率(スコアシステム)その2
maimai FiNALEまでの2600はすごく良かったと思っています。
個人的な難易度は以下のような感じですが
S < FC < 赤FC <<<<< AP <<<< 理論値
※理論値難易度は譜面によって大きく違う
Breakの2600が入ることで数グレの許容ができ、赤FCからAPまでの長い道のりの中で丁度良い中間目標となってくれました。
S < FC < 赤FC << 鳥S <<< AP <<<< 理論値
※鳥S、理論値難易度は譜面によって大きく違う
また、APが取れてもBreakをいくつか落としていることは多々ありましたが、その場合も数百点(数グレ)程度の差だったたため、APには「やり遂げた」という達成感がありました。
さて、でらっくすです。 まず大きな変化として理論値(101.00%)以外の達成感がだいぶ少なくなりました。
- 99.8%: Break光ってれば鳥S乗ったのに……
- 100.1%: Break光っただけだしなぁ……
- 100.4%: Break光ってれば鳥S+乗ったのに……
- 100.5%: 達成感はあるけどBreak光っただけだしなぁ……そもそもFCすらしてないし……
- AP: やった……って100.80%……0.20%落ちとか達成率的にはボロボロだぁ
- 理論値: やった!
自分の腕では多数のBreakを安定して取ることは出来ないので、理論値ペースの後半とかBreak来なけりゃ良いのに……とか思ってますorz
FiNALEの頃は99.9%に落ちたスコアを最後のBreakでギリギリ100%に乗せたり、楽しかったなぁ……
レーティングシステム
Recent枠が無くなったのは良し悪しありますが、まぁ直に受け入れられました。
一応書いておくと個人的なメリデメは以下の通り
- メリット:苦手曲に手を出しやすくなった
- デメリット:変化が少なくなったのでずっとこの数字と付き合うことになりそう
問題はBest枠のSSS+上限化。スコアシステムの問題がここにも。
まず、1.02で少しマシになったとはいえ、SSS+は割と失敗しまくってもBreakさえ光れば取れます。
そうすると運よくBreakが光ってSSS+に乗ったプレイがBest枠に乗るわけです。
実際自分のスコアでもSSS+済の未FC+、未FCがちらほら。
さて、プレイヤー的にはまだまだ先があるわけですが、レーティング的にはこの曲を詰める理由はもうありません。
実際はFC埋め、FC+埋めをするのでプレイしないわけではないんですが、AP出してもレーティングが微動だにしないのはちょっと凹みますね。
オンゲキならSSS+(1007500)に乗せるにはほぼABFBが必要になるので、SSS+が上限でも良いんですが、maimaiでらっくすのこのスコアシステムでSSS+(100.50%)が上限なのはダメでしょう。
かといって100.75%を上限にするのもダメです。100.75%を上限にしたらBreak精度をさらに求めるゲームになりますし、それがプレイヤーの腕を反映していないのは前述した通りです。
お友達対戦
メインは語ったので後はさっくりと。
- 相手の名前出ないので対戦感が少ない
- 負けた時のゲージ、レーティング減少がでかいので確実に勝てる相手が来るのを待つ作業ゲー
タッチノーツ
大分慣れたものの、やっぱり押していて楽しさが薄いのが困り者。
判定が緩すぎるのと、判定抜けを嫌って手のひら全体で取るので、全体的におおざっぱな感が強く、リズムに合わせてノーツを取っている感じが弱いのが原因だろうか?
スライド中のタッチノーツも「これならスライドだけで良いよなぁ」と思ってしまうことがしばしば。
あと、エフェクトが邪魔で次のノーツが見えないことも多々。
100円3曲固定
筐体スペースやら考えると仕方が無いとは思いつつ、ぼっちにはツライ。
maimai でらっくす のスコアシステムについて
maimai でらっくす のスコアシステムについて、どうにも気になる点があったたため、公式にメールしてみました。 以下、内容。
いつも楽しく遊ばせていただいています。 出先でmaimaiでらっくすのロケテが行われていたため、遊ばせて頂きました。
JAEPOで発表された際も懸念点としては感じていましたが、実際に遊んでみた結果、スコアシステムについてあまりにも受け入れがたい点があったため、意見として送らせていただきます。
スコアシステムの問題点について
問題と感じているのは極端なBreak精度ゲーになっており、プレイヤーの「うまくできた感」とスコアが全くリンクしていない所です。
例として「ヒバナ」のMasterを上げますが、(簡略化のため)Hold/SlideはAll Perfectとした場合のスコアは以下のようになるかと思います。
ノーツ数: Tap 483 / Hold 48 / Slide 138 / Break 2
Break加点除く総得点: 483 * 500 + 48 * 1000 + 138 * 1500 + 2 * 2500 = 501500
パターンA(色々失敗したがBreakはCritical Perfect)
Great 10 / Good 1 / Miss 3(-100 * 10 - 250 - 500 * 3 = -2750
)
Break2つはどちらも2600
(501500 - 2750) / 501500 + 1%
→ 100.45%
パターンB(ほぼミス無しだがBreakがPerfect)
1グレのみ(-100
)
Break2つはどちらも2500
(501500 - 100) / 501500 + 0%
→ 99.98%
問題点
プレイヤーからすれば、明らかにパターンBの方がうまくできたにも関わらず、スコアとしては0.5%近くも低いボロボロ。
この問題は、Breakが少ない譜面で顕著ではありますが、多かれ少なかれ同じ問題を抱えることになります。
高スコアを出すためには何よりもBreak精度が重要になるわけですが、少なくとも私は、譜面の極一部でCriticalが出るか出ないかに拘るようなゲームをやりたいわけではありません。
CHUNITHM/オンゲキのように全ノーツに+1%を割り当てる形であれば良かったのですが……
(旧データに精度情報が無く、スコア引継ぎのために、この方法は取れなかったのだとは思いますが)
旧スコアシステムであればパターンAが99.49%、パターンBが99.98%とプレイヤーの感覚とも合致したスコアになっていました。
個人的に101%への統一なんて求めていなかった、という事情もありますが、ここまで酷いスコアシステムにしてまで101%へ統一する必要があるんでしょうか?
色々と考えられた上での実装かとは思いますが、なにとぞご再考のほど、よろしくお願いします。
ISUCON8に1人で参加してきました
ISUCON7は3人チームで参加しましたが、今回は1人参加も可能ということで、ぼっち参加してきました。
1人参加は枠数が限られていたので、慌てて申し込んだ結果、実は見たことのない「RE: ゼロから始めるISUCON 」に。
結果は最高スコア32,596、最終スコア26,873で予選落ちではあるものの、去年の反省を活かした動きである程度のスコアが出せたのは良かったです。
ただ、正直手が付けられていない箇所が多すぎて、不完全燃焼感も。
# 後日の検証でLBだけ有効にしたら79,356でましたが、不安定だし、たらればですね。(でも書いちゃう)
やったことと感想
事前に決めていたこと
1人参加、かつアプリ寄りの人間のため、迷ってる暇はなさそう。インフラ側の変更は最低限にして、アプリの改修を優先しよう。
ISUCON7でも使用したkataribe, pt-query-digest, netdataは今回も使いたいな。特に前回の教訓を元にネットワークの帯域には気を付けよう。
1人だと自由に本番環境を使えるから、手元環境で動作させる必要は無いよね。いつも使ってるdotfilesを本番に入れられる準備はしておこう。
前回同様、複数台構成の可能性もあるし、普段のサーバ(tmux入り)からwindow/paneを切ってつなごう。
事前準備
- 初期設定・計測用スクリプトの準備
- tmuxのwindow/pane切り分け
- 最終手順の手順書準備(不要サービス停止、ログ抑制)
チューニング方針
環境を確認した瞬間「出題DeNAじゃん!!」と叫んでしまったのですが……十分考えられる選択だったよね。
nginxに置き換えた人も多かったようですが、設定をみたら割と読みやすかったのと、事前方針を思い出してh2oのまま行くことにしました。
(Evernoteからnginxインストール/設定手順を取り出してダウンロードまでは掛けたんですが)
チューニングの手順としてはpt-query-digestで重い部分を洗い出して修正していくという基本的なもの。
一通りコードを読んでget_events
/get_event
が重いことは明らかだったんですが、呼んでいる箇所が多すぎて挙動を変えづらいのが難点でしたね。
結局、cancelの扱いがクエリを複雑にしているので、現在の予約状況を示すテーブルを新しく切って対応しました。
current_reservations( id, event_id, sheet_id, num, rank, user_id, reserved_at, reservation_id )
非正規化の極みとばかりに、どんどん必要になったカラムを増やしていきましたが、最終的にはcurrent_reservations
自身がボトルネックになってしまっていたのがちょっと残念かな。
(対応した順番としてはこっちが先ですが)残席数管理はredisにしました。
残席自体もredisのsetで管理しようと考えたんですが、何故か残席のsetじゃなくて、予約席のsetを作ろうと考えてしまい、そうするとreserved_at
をどこに持とう?とか考えて、結局RDBにしてしまいました。
atomicなpop処理ができれば、redisだけでロックの代替ができたのかな?
後は細かいところをあれこれと弄っていました。
- get_event
は呼び出し元によってはdetail
が要らないので、with_detail
引数を増やしたり
- sheets
情報をpython中にハードコーディング
- sha256の計算をhashlib
でやってみたり
- kataribe的にloginが重いと言われたからやってみたけど、ストレッチングも無いのでそもそも重くないかも
- テーブルへのindex追加
- get_login_user
を呼ぶ必要のない場所があったので削除
- mysqlをserver3に移動
悔やまれる点
- admin側が全然見られなかった
- lock問題についてはそこまで悩まされなかったが、理解して回避したというより、運よく回避した、という感じが強い
- 実際、スコアが不安定で、failすることもあった
- 明らかにここ変えたい、という場所に手が回らなかった
order by rand()
- h2oのLBが
/etc/hosts
でできることを知らなかった /etc/hosts
に2レコード書いてping
飛ばすところまではやったけど、ダメだったのであきらめた。h2o本体で試すべきだった。- ISUCON7予選のトラウマから50Mbpsのグローバル帯域を気にしすぎた
課題・環境について
ポータルがすごく便利。ベンチマークも全く待ち時間が無く、とても快適でした。
課題としては面白かったものの、lockが主題になるとスコアが安定しないのが難点か。
修正が役に立ったのかどうかがもひとつ判断できず、ツライ時間が続いたりしました。
サーバについては、終了後にベンチ環境まで含めて1週間公開してくれるというのがすごくありがたいです。
時間切れで試せなかった場所とか、ロックの関連とかいろいろ見てみたいと思います。
サーバ提供のConoHa GMOインターネット株式会社さまと、このはちゃんには足を向けて眠れませんね!
1人参加のメリット・デメリット
さて、せっかくの1人参加ということで、1人参加のメリットとデメリットも書いておこうと思います。
ISUCON9で1人枠が用意されるかはわかりませんが、参加を考えている人は参考にしてください。
メリット
- 自宅から参加できる(いつものPC、いつものキーボード、移動時間0分)
- 本番環境を自由にカスタマイズ可能(zsh, vim)
- 本番環境で直接作業ができる(gunicornをフロントで起動)
- ベンチマーク実行時とかに他の人の確認を取る必要が無い
- 何をやったか、どこまで終わったかが常に把握できる
デメリット
- 手が足りない
- 嵌ったときにグーグル先生にしか頼れない
- 改修してもスコアが出ない時間が続くと気持ちが折れやすい
- 知識のカバー範囲が足りない
- アプリ1人、インフラ1人、計測&方針決定1人のチームが強そう
- 打ち上げがちょっと寂しい