瑞鳳でMyFleetGirlsが落ちた話

起こったこと

21日の深夜にMyFleetGirlsが接続不能になった。この時点でCPUが100%に張り付き一瞬でT2インスタンスのCPUクレジットを消尽した。

22日の昼に片手間で復旧作業を開始。最初EC2インスタンスの不都合かと思って雑に再起動をかけるが直らず100%に張り付く。このあたりで採掘を疑う(完全に見当違い)。すぐに復旧できなそうなので放置。

仕事中に無限ループの可能性に思い当たり、夜にログを見て調査してみると、起動時のRanking処理で落ちていることが分かる。

→コードを読み返していくとEvolutionBaseという改造元検索アルゴリズムに不都合に思い至る。

→21日の深夜に瑞鳳改二増えてるで

→瑞鳳がわるい!

原因

MyFleetGirlsは艦これとの通信をproxyすることで通信を覗いて、必要なデータをサーバに送る仕組みで、このときMyFleetGirlsの動作に必要なマスターデータも必要に応じてupdateしてもらう。

瑞鳳改二の実装により艦娘のマスターデータが更新されたので、一番最初に接続したユーザから自動でマスターデータを受け取っている。

そのうちの1つに艦娘改造先マスターデータがある。

id aftershipid afterlv name
116 117 25 瑞鳳
117 555 80 瑞鳳改
555 560 80 瑞鳳改二
560 555 80 瑞鳳改二乙

nameは分かりやすくするために付けたがこんな感じである。

で、MyFleetGirlsには改造元を知りたいときが割とあって、艦娘毎の人気とかを知るための集計類は改だろうが同じ娘なので集約してーとかやったりする。なので改造元を計算するEvolutionBaseというclassを置いている。

ここで厄介なのが改二と改二乙で、改造元が循環してしまう問題がある。実際に循環したことがある。なので、進化元を辿るときはidの小さい方を優先するようにしている。(これは今思うと不十分である。後で述べる対応策で解決している)

上の正しいデータが来ていればMyFleetGirlsが落ちてこのblogを書くこともなかったわけだが、一番最初のユーザがマスターに上げてきたデータは以下のようなものである。

id aftershipid afterlv name
116 117 25 瑞鳳
117 0 80 瑞鳳改
555 560 80 瑞鳳改二
560 555 80 瑞鳳改二乙

あとはわかるな?AWSの虎の子インスタンスは永遠に瑞鳳改二と瑞鳳改二乙の間を行き来することだけに全てを費やし始めたのだ。

なんというかありそうなミスではあるが、MyFleetGirlsを殺すには十分な破壊力があった。

教訓

  • CPU使用率が張り付いたら無限ループを疑え
  • 再帰は必ず回数をカウントしろ
  • 自分の管理外のサーバが正しい情報を返してくる前提で事を進めるな

対応策

復旧はデータの修正と再起動だけで片を付けたが、そのあとで再帰カウントを導入した。

宝石の煌き+拡張:都市

はじめに

この記事はボドゲ紹介 Advent Calendar 2017 - Adventarの2日目ですが、大変遅れてしまったので4日目ぐらいに掲載されています。申し訳ない。

宝石の煌き(英題Splendor)と、その拡張、都市について解説します。

勝利条件

宝石の煌きは宝石を集めて発展カードを買っていき、最終的に勝利点15点を集めるゲームです。勝利点を得る方法としては以下の2つがあります。

  • 発展カードを購入する
  • 貴族タイルを獲得する

順番に見ていきましょう。

発展カード

f:id:ponkotuy:20171203231809j:plain

図のように3つの世代に分かれており、後ろの世代になるほど勝利点もコストも大きくなります。左上の数字が勝利点、左下に書いてあるのがコストです。

右上に書いてある宝石は産出する宝石です。購入時に必要な宝石を減らすことができます。つまり、発展カードを買うことによって、高コストなカードを安く買うことができるようになるわけです。

貴族タイル

f:id:ponkotuy:20171203231917j:plain

貴族タイルは左下に書かれた枚数の発展カードを持っていると自動で入手することができます。左上の点数が入ります。勿論早いもの勝ちです。

ターン

このゲームは順番に以下の3つの行動のうち1つを行い、手番を回していくゲームです。

トークンを獲得する

f:id:ponkotuy:20171203231519j:plain

宝石1つ分の価値になるトークンを獲得します。発展カードと違い使い捨てです。

取得する方法は

  • 異なる種類の宝石3つ
  • 同じ種類の宝石2つ(ただしその宝石トークンが4つ以上ある場合のみ可)

の2つです。なお、持てる宝石トークンの数は10までです(重要)

発展カードを購入する

カードを1枚、コスト分の宝石を支払い、手元に公開して置きます。

発展カードを確保する

カードを1枚確保します。コストは必要ありませんが、まだカードの効果も発揮しません。手札として持っておきます。確保することにより、自分のみが対象のカードを購入することができるようになります。もちろん購入する際には宝石を支払う必要があります。

また確保する際に1枚黄金トークンを手に入れることができ、このトークンはオールマイティーな宝石として扱うことができます。便利!

で、どんなゲームなんですか

このように宝石の煌きはおおまかには拡大再生産ゲームですが、購入の場を共有することになるので、自分しか買えないカードが沢山できるようにカードを構築していく必要があります。

あとカジノのチップを流用したコンポーネントがいいです。その分ちょっと値段が張るんですが、それだけの価値はあります。

拡張ルール

拡張は4種類のルール追加があり、好きな拡張ルールを混ぜてプレイすることができます。

都市

f:id:ponkotuy:20171203232333j:plain

拡張パックのタイトルにもなっている拡張です。勝利条件が15点ではなく、最初にランダムで選ばれる都市を購入するルールに変更されます。都市には、勝利点が少ない代わりにカードの枚数が結構必要だったり、逆に勝利点が沢山あればOKみたいな都市もあったりします。

東洋

f:id:ponkotuy:20171203232203j:plain

各世代に2枚ずつ、購入できる特徴的な発展カードを増やす拡張です。既に持っている発展カードのマークをコピーしてその宝石が付いたカードとして扱う発展カード、下の世代のカードをノーコストで入手することができるカード、宝石トークン2枚分として扱うカード、2枚の発展カードを破棄して購入するカードなどがあります。

交易所

f:id:ponkotuy:20171203232251j:plain

5つのパワーが書かれたボードが追加されます。パワーは左に条件(主に発展カード)、右に恩恵が書かれています。条件を満たしたら当該パワーに紋章トークンを置いて示します。

  • 赤3白1 -> 発展カード購入時に宝石トークンを1枚獲得
  • 白2 -> 同じ色の宝石トークン2つ獲得した際に他の色のトークン1つを追加で得る
  • 青3黒1 -> 黄金トークンは1色のトークン2枚分に数える
  • 緑5+貴族タイル -> 5点
  • 黒3 -> 紋章1つにつき1点

城塞

f:id:ponkotuy:20171203232448j:plain

カード購入時に以下の行動のうち、どれか1つを行う必要があります。

  • 公開されている発展カードに城塞を置く
  • 置かれている城塞を移動する
  • 他のプレイヤーの城塞を取り除く

城塞の効果は以下のようなものです。

  • 他のプレイヤーの城塞が置かれているカードは購入できない
  • 他のプレイヤーは城塞を置くことができない
  • 3つの城塞が置かれたカードはターンを消費せずに購入できる(購入時の行動を追加で行う

拡張まとめ

慣れてきて、普通のゲームに飽きたプレイヤーも楽しめるものになってます。宝石の煌き好きな方は是非購入してみては。

個人的なオススメは交易所です。都市も割とどんなゲームに入れても面白いので、デフォルトで突っ込んでしまってもいいかもしれません。

なお、私がプレイしたときは、城塞がやたら不評でした。これ妨害効果強過ぎて割と別ゲーな雰囲気です。東洋とか入れると選択肢が増えて多少はマイルドになるかもしれません。

モデルの共用ダメ説の提唱

はじめに

最近サーバとクライアントを同じ言語にしてみたよ、っていう話を良く聞きます。その理由として「モデルの共用ができる」というメリットが挙がります。これに関して、いやそれ違うだろ、って前から思っていて、もやもやしているので書きます。

本当はQiitaで書きたかったのですが、どう考えてもポエムなのでHatenaBlogにしておきます。

軽い背景解説

「はじめに」が大筋理解できていれば読む必要が無いと思いますが、そうでない人もいると思うので解説します。

所謂Webの世界ではサーバ側とクライアント側で厳密に分けられることが多くなっており、ソシャゲだったら運営側のAPIサーバとスマホアプリ(クライアント)という感じで分けられています。ゲームに必要なデータはAPIサーバから取ってきて、スマホアプリは動きとか絵を管理している感じですね。普通のWebサイトでも単純なAPIサーバからデータを取得してJavaSciprtがレンダリングする仕組みのサイトが増えています。この方がUIの自由度が増すんですね。

で、そのAPIサーバとクライアントの間で必要な通信のデータ構造をモデルとここでは呼んでいます。例えばサーバにPersonという情報があって、Person内にname(文字列)とage(数値)があるとします。Scalaで書けばこんなんですね

case class Person(name: String, age: Int)

クライアントがPersonのデータを欲したら、この形式でJSONのObjectなりMessagePackなりでパックされて送られてくるわけです。

当然この形式になっていることをAPIサーバ側もクライアント側も知っていないといけない訳です。ところが今まではサーバ側とクライアント側で言語の断絶があって、サーバ側はRuby/PHP/Perl/Java、クライアント側はJavaScriptが多かったので、結果的に両方でモデル定義を持つ必要がありました。今までは。

ところが、NodeJSでクライアントの覇者JavaScriptがサーバサイドで書けるようになったり、サーバサイドでも使い勝手良さそうなC#が、Unityとしてクライアントで大々的に使われるようになったところで、モデル定義を1つ書けばいいんじゃないか、という話が出てきたわけです。(Fate/Grand OrderがUnityだからサーバもC#にしているという話がありました)

で、ここでぼくが書きたいのは「モデル定義を本当に共用して大丈夫?」という話です。ようやく追い付きましたね。

本題

モデル定義を共用するのに疑問を持っている理由は「そのモデルが更新されたときの、クライアントとAPIサーバの互換性どうするの」という点に尽きます。

さてサービスが運用に乗ります。機能を追加します。最初に作ったPersonモデルにデータが追加しよう! 良くありますよね?ここでは例でnameとageがあったPersonに、海外展開に備えて言語情報を設定しましょう。めっちゃありそう。langっていう名前の文字列でいいかな。

langを追加するためにはモデルに修正が必要です。共用のモデルなら1箇所にlangを追加すればいいだけですね。さてリリースしましょうか?

このとき、もしクライアントとサーバが同時に変更してリリースが可能であればうまくいきます。それは大変幸運で、そして現代においては稀有なパターンだと思います。1つのAPIサーバに1つのJSクライアントしかなければ、まぁうまくいくかもね?

つまり、APIサーバは運営が自由にアップデート可能なことが多いですが、クライアントはそうではなく、古いモデルでやりとりをすることが多々あります。クライアントがスマホアプリだったら更新サボってる人も多そうですし、APIサーバを公開していて多数のクライアントが付いてる場合だと更に困難ですね。全員に更新が行き渡るのに何年掛かるの?TwitterBasic認証やめるのに何年掛かったっけ?

結論として、APIサーバは最大公約数的なモデル定義をする必要があり、クライアントにその必要はなく、それによる弊害の方が大きいと考えています。APIサーバがクライアントからPersonの投稿を受け付けるときはlangがある場合と無い場合がありえるので、両方のパターンを記述する必要があります。クライアントはサーバが自分の持っているPerson型を受け付けられない可能性を考慮する必要はありません。モデル定義さえ別ならば。langという余計なデータが来ても捨てればいいのです。

モデル定義を共用化するためにクライアントのコードを不必要に複雑にする必要はありません。モデル定義のコストとか多寡が知れてるし、2つぐらい作ったらどうですか、という話です。どうせサービス運用がうまくいって3年とか経てば全くの別物になっているのですから。

MyFleetGirlsの経験について

実際あったかのように語りましたが、実際にあったんです、MyFleetGirlsで、という話です。

MyFleetGirlsという自作の艦これツールがありまして、ScalaサーバとWebクライアントとScalaクライアントに分かれています。艦これの通信をMyFleetGirlsのサーバに横流しするのがScalaクライアントの仕事で、サーバと同じ言語なので、この通信に使われるモデルは共用化されています。安易に共用化しました。

結果として、後から追加されたモデルデータは全てOptional、存在するか分からない型として処理されるか、古いクライアントからのアクセスを拒否する仕様になりました。サーバが古いクライアントと通信する可能性があるからです。Optionalになった場合、クライアントは常に値があることが保証されているにも関わらずOptionalを強要されるため、コードからのスメルは強烈なものになりました。古いクライアントからのアクセスを拒否する仕様のために、強制的にクライアントをアップデートする仕組みを1から作るハメになりました。

蔵王キツネ村探訪2017/9/16

大分前になってしまったがきつね村に行ってきたのでひたすらもふい写真を貼る。

f:id:ponkotuy:20170916101635j:plain

入口。檻が無い…というより檻の中に入れる動物園なので、色々免責事項が多い。

f:id:ponkotuy:20170916102212j:plain

入口の安全地帯(突然キツネに攻撃されない的な意味で)にはうさぎとかヤギとか馬がいる。

f:id:ponkotuy:20170916102354j:plain

f:id:ponkotuy:20170916102407j:plain

f:id:ponkotuy:20170916102550j:plain

f:id:ponkotuy:20170916102422j:plain

f:id:ponkotuy:20170916102510j:plain

f:id:ponkotuy:20170916102633j:plain

f:id:ponkotuy:20170916102716j:plain

f:id:ponkotuy:20170916102834j:plain

こっから先はキツネが生息するだだっぴろい空間。

f:id:ponkotuy:20170916103236j:plain

f:id:ponkotuy:20170916103200j:plain

f:id:ponkotuy:20170916103250j:plain

f:id:ponkotuy:20170916103345j:plain

f:id:ponkotuy:20170916103132j:plain

f:id:ponkotuy:20170916103436j:plain

f:id:ponkotuy:20170916103530j:plain

f:id:ponkotuy:20170916104157j:plain

f:id:ponkotuy:20170916103754j:plain

f:id:ponkotuy:20170916103639j:plain

f:id:ponkotuy:20170916104220j:plain

f:id:ponkotuy:20170916104306j:plain

f:id:ponkotuy:20170916104452j:plain

f:id:ponkotuy:20170916104536j:plain

f:id:ponkotuy:20170916105005j:plain

f:id:ponkotuy:20170916104411j:plain

f:id:ponkotuy:20170916105119j:plain

f:id:ponkotuy:20170916111311j:plain

放し飼いにされていた子山羊

f:id:ponkotuy:20170916111845j:plain

f:id:ponkotuy:20170916111715j:plain

f:id:ponkotuy:20170916112301j:plain

f:id:ponkotuy:20170916112507j:plain

f:id:ponkotuy:20170916111929j:plain

おしまい。入場料1000円でそこそこリーズナブルだけど場所が本当にひどいところにあるので新幹線代金とレンタカーorタクシー代を片手に来訪されることをお勧めする。

なお私は現地でタクシーを駆使して色々行くつもりだったのだが、残念ながらお金を引き出さずに蔵王高原に入ってしまい、泣く泣く歩いてキツネ村から駅まで戻りました。

そこらへんの顛末はTwitterでどうぞ

twilog.org

FactorioRecipeリリース

FactorioRecipeというFactorioの組立機の比率や材料の数が分かるツールを作りました。

FactorioRecipe

まぁ良くあるFactorioのアイテム作成チェーンを見るツールの1つなわけですが、最大のウリはゲーム内のluaファイルを直接読む機能が付いているので、特に面倒なことしなくても最新版に追従できるという点です。ので、現在α版のv0.15に対応していて、今後も速攻対応できる感じです。自動化サイコー。

Factorioは不時着した未知の惑星で工場を作るゲームで、プログラミングみたいにどんどん自動化を進めつつ、高機能かつ複雑なアイテムを大量に作っていくのが面白いです。

まぁこれ見るのが早いと思います

www.youtube.com

サーバサイドのアプリケーションはScala + Playframework、DBはPostgreSQL。View側はCoffeeScript + VueJS。インフラは自宅サーバのArchLinuxの上のDockerで動いてます。

今までやったことが無いのはLuaの読み込みですが、最近使ってる言語はリッチなものばかりなので面倒くさかったですね。あとJavaからLuaを実行できるluajのLua内オブジェクトをJavaのオブジェクトに割り当てる機能も貧弱で厳しい。

あと今回は初めてPostgreSQLを使いましが、やはり色々設定まわりとか違うので最初は手間は掛かりますね。ただ`create table`でもtransactionが効くので、開発中のmigrationテストで失敗してもロールバックされて、DB修復しなくていいのは楽ですね。(MySQLにはこの機能が無い)個人的にPostgreSQLを使うモチベで最大のものはMaterialViewですがまだ試してないです。そういえばcreate table内でunique indexとか張れない気がしたけど何か間違ってたかな。謎

CrucialのSSD(MX300) 525GB買った

仕事マシンは自作PCになることが多い。(これは大体ぼくの我侭が原因であって会社のPC支給に問題があるわけではないのだが)そのPCのSSDが壊れたらしいのでアキバに買いに行ったときの話。

購入したいSSDはどちらかというと安定性重視のSATA接続のやつ。とはいえ鯖用の高いのを買う気はないので、コンシューマ向けで評判良さそうなの買えばいいかな、ぐらい。多分必要な容量は100GBだと思ってて、ただ最近はSSD安いので200GBぐらいでいいかなぁみたいなノリでアキバへ。

んでSSDのメーカーどこがいいのかTwitterに聞いてみたら、やっぱりIntelの評判が良くて、次点でPlextorSamsungあたりだろうか。実際手元にあるSSDもそこら辺が多い。壊れたSSDIntelなのが気掛りだけど、まぁIntelかなぁと思いつつ物色。

ところが、実際の店舗に行ってみるとIntelSSDはほぼ全部品切れになっており、Plextorも在庫無さそうという感じ。Samsungはちょいちょい在庫ある、とかそんなんで、大体どの店もADATA、Trancend、CFD、WesternDigital辺りを売れ筋にしたい(せざるを得ない?)感じだった。Twitterで聞いてた感じと随分違うので戸惑ってかなりウロウロしてた。

ただ色々考えてみると、安物が売れ筋になる商品って、大体どのメーカでもスペック十分で安定してる状態なのでは、と思ったのが1つある。

SSD黎明期、HDDよりランダムアクセスがアホみたいに早くなるので、かなり高いけど下手にCPU買うよりよっぽどいいぞ、とかSDカードをn枚でRAID0した方が安い!とかアホみたいな事をやってた時期は、実はマトモに動くSSDが殆ど無くて、プチフリが多発していた。ので、「SSDのあのメーカー・コントローラはプチフリしずらいぞ」っていう情報はすごい飛び交っていた。

そんな頃にSSDを5〜10台調達したぼくの脳味噌はその時の気持ちがあまりアップデートされておらず、Twitterでオススメされた商品が、店だとそれが少数派だったという状況に、時代の変化を感じたわけである。

冷静に考えてみると、SSDはここ4年以上ずっとSATA3.0の6Gbpsがネックになる時代が続いており、スペック上がりようがない上に、ハイスペックなやつはM.2やPCIeに移行しており、USBメモリみたいな、容量さえあればいい、みたいな市場になっていたのである。つまり安いのでこまらん。好きなメーカーを買えというわけだ。

あとIntelは付加価値の高い商品しか扱わないから実態としてほぼ撤退してるんだろうな、という感じ。実際スペックで高付加価値付けられるM.2やPCIeではまだ人気だ。

というあたりがCrucialを買った理由である。容量の割に安いのと、流石にTrancendのSSDはなーとか思ったとか、Twitterで勧められたのもある。(あとSATAの限界内でも速度というのは無いでない)

100GBで十分な人間が525GBにした理由も説明しておこう。ぼくの環境、稼働率の高いPCで大変SSDが壊れやすい。単に使い方がハードなのかなーと、今まであまり気にしてなかったのだが、容量に余裕が無いとSSDは壊れやすい、という指摘を食らうまでウッカリ忘れていた。

これも昔から言われていたんだけど、SSD高いのでぽんこつさんは低容量な奴買うことが多くてカツカツになってることが多かった。SSDを使い切るのが良くない、というのは昔も今もあんまり変わってないらしい。

つまりすぐに壊れて欲しくないのであれば、信頼性の高いメーカーにお金を払うのではなく、容量にお金を払うべきだ、というのが結論である。適当なメーカーでもいいので大容量品を買うべきなのだ。最近のPCはついウッカリ50GBとかぐらいなら消費してしまうので、500GBぐらいまでなら容量増やした方が良いことが多いとおもう。

余談だが光学ドライブも買った。最初8000円のが目に付いてそんなもんだよねーと思ってあまり気にしなかったのだが、下の方に2000円の光学ドライブがあって「ファッ!?」ってなった。これDVD非対応なドライブかと一瞬思ってしまったが勿論そんなことはなかった。8000円の方に目線戻したらBD対応で、BD対応ドライブのあまりの安さに眩暈がした。光学ドライブとか5-6年買ってないからね…。

ちなみにぼくはBDドライブの購入はお勧めしない。BD(それはGB単価でHDDより高い)にデータを焼くことはもう既に無く、使うとしたらブルーレイのアニメぐらいだろうがあれは馬鹿にみたいに高い再生ソフトを買わないと見ることはできない(そして往々にして不便である)。ましてそれがLinux対応なんて望むべくもない。素直にPS3で再生するなりTVに繋ぐ専用の再生機(それならなんと5000円で買える)を買おう。

VAIO ZでArchLinuxが動いた話

はじめに

VAIO ZでLinuxが動かなかった話 - ponkotuyのブログ

の続きになります。なんとか動きました。

何がわるかったのか

詳しくは分からないけど、EFIだと4.7.6以降のKernelでブートしなくなるのが問題のようです。

VAIO Z で Arch LinuxとWindows 10をデュアルブートする - Qiita

ArchLinuxをインストールした - ふれめも

きちんとコメント含めて読んでいくと書いてありますね。ちゃんと読め。

補足

基本的には2つのリンク先のようにやれば良いです。ただし彼等は既にインストール済の状態で問題に遭遇しているため、最初から問題ありKernelでやらないといけない場合補足が必要です。

まず先にも問題になっていたKernelの問題はarchisoにも適用されます。つまりインストールに必要なarchisoがブートしません。なのでインストーラブートローダが起動したらまずeを押して起動オプションを変更します。最後にnoefiを付けるだけです。この状態であれば起動します。

勿論この状態でefivarsなどを参照してもEFIモードではありませんが、普通にsystemd-bootをEFIで起動するように設定することはできます。私はWindowsEFIパーティションをそのまま流用してブートできました。勿論このときもnoefiを付けるのを忘れずに。

ちなみに`bootctl install`した際、エラーが出てこまりましたが、エラー放置して進めても全く問題はなかったです。ここは今でも良く分かってないです。

最後に

TwitterFacebookでアドバイスしてくださった方々ありがとうございました。