Screaming Loud

日々是精進

ISUCON2017に初参加した

初参加は結果惨敗でした。チーム名は「Ta-da!」 Slackのロード画面で出てきたので、それを使いました。

以下が最後の結果 f:id:yuutookun:20171024145958p:plain

両日では、69位のようですね。 ISUCON7 オンライン予選 全ての順位とスコア(参考値) : ISUCON公式Blog

事前準備

会社のメンバーで参加したので、社内Slackを作成。 計測が大事なので、計測ツールだけ選定しておきました。

  • logの調査:alp
  • slow-query: pt-query-digest
  • Gitリポジトリの作成
  • ISUCONの過去の講評を読む

本番にやったこと

担当割り振りは、インフラ、アプリ、アプリという構成で行いました。 自分がPythonを書けることから、言語はPythonで選定されていました。

序盤

インフラ担当が、ssh周りや地盤を固めてくれてたので、 自分はデプロイスクリプトなどアプリ周りの足回りを固めていました。

【自分の中での失敗】

  1. アプリケーションの挙動の把握にものすごい時間がかかった。 序盤で、2~3時間くらい開発環境を整えるのに時間を食うという失態。 マニュアルを読むべきでした。。。 そもそもsystemctlで起動していたのに、gunicornを直接触ろうとしていた。

  2. ローカルで動かせるようにしていなかった。 これもちょっと修正して、デプロイして動くか確認。という果てしない行動を行っていて、ローカルで動かしていればそんなdebug一瞬だったのにという。。

やっとローカル環境を構築して、開発がちゃんと動き始めたのが、4:30くらいから。。

中盤

やっとおれたちのISUCONが4:00くらいから始まる。

/messagesと/fetchと/iconsが遅かったので、 分担を

  • 自分が/iconsの対応
  • もう一人が/messagesと/fetchの対応

と振りました。 この時点で、よくわからんsleepは消しとこ。ってなってsleepは消してしまった。。。

iconsの対応は

  1. profileで更新したiconをDBではなく、ファイルに吐く
  2. 既存のアイコンを全部引き抜く
  3. read先をファイルのアイコン、なければDB参照

の3ステップで対応しました。

それまでずっと4桁だったのが、この上記3つの対応を終えた瞬間に5万まであがり、さらにnginxの設定でexpiresを変更してから、7万くらいまであがりました。 Maxの値ですね。

あとは、N+1問題を解決するために、メモリに載せ2クエリにしました。

ここで、3台の構成を キャッシュ(nginx)→Web(Python)→MySQL という構成にしました。

終盤

その後ベンチを掛けるたびにスコアがおちていってしまいした。

ただベンチを掛けるとCPUがPythonで詰まってしまい、そもそも毎回userに問い合わせる必要なくね。 となって、20:00くらいからuserをglobalのdictに載っけようということで、作り直したんですが、時間的に間に合わなくデプロイできず。 途中まで作ってもベンチを掛けたらバリデーションでスコアがガタ落ちしたので、戻しました。

まとめ

総じて、面白かったです。 本戦に行けなかったですが、また参加できればしたいと思います。

次回への教訓としては、

「マニュアルをしっかり読む」

ですね。 ありがとうございました。

プロダクトのビジョンを決める

ビジョンとは

企業の経営を行う上で、経営におけるビジョンを設定するということは最近ではごく当たり前のことになっている。

そもそも ビジョンとは何か? 以下コトバンクによると

将来のある時点でどのような発展を遂げていたか、成長していたいかなどの構想や未来像。またそれらを文章などで描いたもの。会社全体の未来像を経営ビジョン、事業の未来像は事業ビジョン、組織は組織ビジョンなどと呼ばれる。また個人の将来像を指してキャリアビジョン、自己成長ビジョンなどということもある。

ビジョン(びじょん)とは - コトバンク

ではなぜビジョンを描くのか? 以下の考察が面白い。

会社のビジョンはなぜ大切なのか – Koichiro Honda – Medium

ただ企業のビジョンの場合、たいていふわっとしていてプロダクトの方向性まで定義できないことが多い。 急成長の理由が分かる?注目スタートアップ23社の洗練されたビジョン・ミッションまとめ | CyberTimes [シバタイムス]

企業のビジョンは決めていてもプロダクトのビジョンまでどうするかまでしっかり考えているところはどれくらいいるのだろうか?

以下の理由から企業のビジョンだけではなく、プロダクトのビジョンも作り浸透させる必要があると自分は考えている。

  • 作っているメンバーの士気を上げる
  • プロダクトの方向性を浸透させる
  • 社内外へのプロダクトのファンを増やす

また、ビジョンの決め方として、自分たちがやりたいことではなく、ユーザ視点でどう価値を提供するかということを言語化するほうがいいと思っている。

メンバーの士気

働く人たちは何をモチベーションにしてプロダクトを作っているのか? もちろんスタートから作っている人たちは、自分のプロダクト大きくしたいとか単純な思考でモチベーションが上がる。 では途中からジョインする人たちにとっての「そのプロダクトをどうして作りたいか?」という視点に立つとどうだろう?

  1. 給料
  2. そのプロダクトが先進的で面白い(成長できるか)
  3. 社会で一番価値を提供できているか(このプロダクトを作る意義)

上記3つはどれも重要だ。ただ1や2は目に見えるものなのでわかりやすく設定できるが、3はなかなか分かりづらい。

しかし3をしっかり規定しなければ、今の時代給料であれば出せばいいし、技術であれば大体導入できてしまう(もちろんそこでの差別化は可能)ので、モチベーションの差別化が難しい。

プロダクトの方向性

またイノベーションという観点でも、ビジョンを策定する必要がある。

プロダクトを作り始める上で、まずターゲットユーザ層を決めるのは当たり前であるし、ペルソナを決めたり、どういうプロダクトにするかを決めるはずだ。

しかし、そのプロダクトが長生きするほど、市場環境やテクノロジーが変わり、当初考えていたプロダクトの方向性から乖離していくということは多くあると思う。

そうなってくると、そのプロダクトの方向性を変えなければいけなくなる。 しかし漫然と作っていると、プロダクトの売上だけを見てしまい、そもそものイノベーションを起こせなくなってしまう。そして、気づけば時代遅れなものになっているということもある。

プロダクトのビジョンを考える上ですごく重要なことは、「使ってもらうユーザに対してなぜこのプロダクトを使ってもらうのか?」ということを決めることだ。

既存の延長線上の思考で単純な機能追加を繰り返していくだけでは、イノベーションは生まれないのである。 そう日本のリモコンのように。

「ガラパゴスリモコン」が示す日本のもの作りの限界~リモコンで飛行機でも飛ばしたいの? – アゴラ

常にそのプロダクトがどうあるべきか?ということを考え続けることこそ、プロダクトが進化していくことに繋がる。

ファンを作る

人間とは、ストーリーに共感するイキモノである。 ビジョンとは企業やプロダクトをどのようにしていくか、言い換えるとどのようなストーリーで作っていくかを定義することである。

日本の場合、外部に向けて共有されていないイメージだが、海外ではビジョンだけでなく、その沿革なども共有し、ファンを増やしているものが多い。

例)Trello

About | What is Trello?

締め

プロダクトのビジョンがまだ決まっていないのであれば、今一度ビジョンをチームで語り合ってみてはどうだろうか。

ScalikeJDBCのInsertで予約語を使う

今更ペルソナ5を始めました。

背景

MySQLのカラムに予約語を使う場合、バッククオートで以下のように囲むことが一般的です。

create table log(id int auto_increment, user_id int, from datetime, to datetime);
insert into log(`user_id`, `from`, `to`) values(1, "2017-08-24 00:00:01", "2017-08-24 23:59:59");

しかし、ScalikeJDBCでQueryDSLを使ってInsert文を書こうとすると、バッククオートが入りません。

注) “org.scalikejdbc” %% “scalikejdbc” % “3.0.1”

対応

以下のようにします。

case class Log(id: Int, userId: Int, from: String, to: String)
object Log extends SQLSyntaxSupport[Log] {
}

DB.localTx { implicit s =>
      withSQL {
        val values = Seq(
          sqls"`user_id`" -> userId,
          sqls"`from`" -> from,
          sqls"`to`" -> to
        insert.into(Log).namedValues(values: _*)
     }.updateAndReturnGeneratedKey.apply()
}

DSL対応誰か作ってほしー(他人任せ

AWScalaでIamRoleのクレデンシャルでクライアントに繋ぎたかった

本題の通りAWScalaを使っていて、IAMRoleを適用したかったんですが、InstanceProfileCredentialsProviderを埋めたS3Clientが作れず、困っていました。

やりたかったこと

local環境ではcredentialKeyを使い、prd環境ではIAMroleを使う ただし、複数のアカウントのS3を見ているため、一部credentialKeyを利用する必要がある。

問題点

単純に空でS3インスタンスを作成すれば、DefaultAwsCredentialsProviderChainから作成できる(以下参照)んですが、 Default empty constructor for AmazonS3Client (and others) · Issue #11 · seratch/AWScala · GitHub
lastUsedのクレデンシャルを使うので、IAMroleとクレデンシャルファイルを混ぜて使うことが出来ない。

対応

以下のように単純に親のSDKを型として指定してあげれば、うまくいきました。

  val credentailName = "hoge"
  protected implicit lazy val s3: AmazonS3 = {
    if (env == "local") {
      val credential = new ProfileCredentialsProvider(credentialName).getCredentials
      // AWScalaでクライアント作成
      S3(credential.getAWSAccessKeyId, credential.getAWSSecretKey)(Region.AP_NORTHEAST_1)
    } else {
      val credential: AWSCredentialsProvider = new InstanceProfileCredentialsProvider()
      val clientConfiguration = new ClientConfiguration
      clientConfiguration.setConnectionTimeout(30000)
      // AWSSDKの生のclientを作成
      new AmazonS3Client(credential, clientConfiguration)
    }
  }

AWScalaのS3はAWSSDKのAmazonS3を継承しているので、こうやって指定することができます。

まとめ

なんか単純なことですが、思考を柔軟にしないとだめですね。。

参考