WonderPlanet DEVELOPER BLOG

ワンダープラネットの開発者ブログです。モバイルゲーム開発情報を発信。

キャラクターに込められたコンセプトやテーマについて

こんにちわ!

デザイナーの渡辺です。 

 

主にキャラクター指示書やゲーム内背景の指示書の作成及び

赤入れの制作などを行っております。

 

今回は指示書作成において超重要な部分である

「コンセプト」「テーマ」について、

実際にどのような内容で指示書を作成したかを

具体例やちょっとした裏話も兼ねてお話ししたいと思います!

 

キャラクターの指示書が出来上がる過程につきましては、

同じくデザイナー伊藤さんの記事

クラッシュフィーバーのキャラクター指示書ができるまでをぜひご覧ください!

 

コンセプトとテーマとは

伊藤さんの記事で触れていた「ユーザー様に届けたい価値・個性」にあたる部分です。

 

少し前までの指示書では、指示書の説明文にキャラの個性や価値を文言で

説明していましたが、よりクリエイター様に完成系のイメージが伝わるように

コンセプトに加えてキャラクターごとに「テーマとなる文言」をそれぞれ用意し

指示書に記載するようになりました。

 

今回は実際に私が指示書を担当した中から

「ギルガメッシュ」「ガンバンテイン」「ストレングス」

3キャラのテーマやコンセプトなどご紹介致します!

 

 

・・・「ギルガメッシュ」の場合

■R6ギルガメッシュ

f:id:wp-watanabe:20170609155634p:plain

テーマ「チェスの兵士・残虐・少年」

 

史実では神格化されたりした人物ですが、

同時にとてもわがままな暴君であったという話から

「頭が切れるが、ワガママで、子供の残虐性を持った少年」キャラクターとしました。

 

自らは武器を振るわず、チェスで戦術を練りつつ徹底して部下に攻撃を行わせる姿で

余裕のある感じを狙っています。

 

実は頭に浮かんでいる王冠は、ALICE内で相当な金額のかかるアイテムのイメージで付けてもらいました。

ギルガメッシュががんばって手に入れて、自分が偉い王様だと見せびらかすために

いつも装備しているような・・頭は切れるけど、ちょっと年相応なかわいい子供っぽい部分も覗かせているイメージです。

 

 

 

・・・「ガンバンテイン」の場合

■R5のガンバンテイン

f:id:wp-watanabe:20170609155615p:plain

テーマ「癒し・魔法少女・たまご」

 

癒し担当の女の子で、

ライトノベルに出ていそうな妹系のロリロリな魔法少女がコンセプトです。

 

ガンバンテインは、あらゆる魔法を無効化する杖という元ネタから

補助を得意とする回復系のキャラクターとし、

また、補助・防御に優れている・無効化するというイメージから

杖には綺麗なたまご(母性や保護の象徴)のモチーフを使用していただきました。

たまごは、「魔法少女のたまご」という意味合いも兼ねています。

 

R6の姿に覚醒した際、アニメの魔法少女のようにガラッと姿が変わっているのは

実はこのテーマに沿っていたからなんですね。

 

■R6でのガンバンテイン

f:id:wp-watanabe:20170609155838p:plain

ユーザー様の中でもこの「魔法少女」のテーマに気づいている方がおり、

気持ちが伝わったようでうれしくなりました。

 

 

 

・・・「ストレングス」の場合

■R6ストレングス

f:id:wp-watanabe:20170609160307p:plain

 テーマ「ゴシックビーストテイマー・ライオン・不気味な少女」

 

ストレングスはタロットカードの「剛力」が元ネタです。

タロットカードでは白いワンピースを着た女性がライオンの口を押さえて

服従させているという、どこか神秘的で謎めいた内容だったので、クラフィでは

「何を考えているのかよくわからない、ちょっと不気味な女の子ビーストテイマー」

というコンセプトで行くことにしました。

ビーストテイマーというと、大抵毛皮の獣っぽい衣装やサーカス等を思わせる

服装を思い浮かべると思いますが、クラフィではあえて世界観にあった

現代的でゴシック風のセクシーなデザインとすることで個性的な女の子になるよう

狙ってみました。

 

他にもリボン風のゴシックなアイパッチや、女の子自身にもライオンっぽい部分を

入れてもらうなど、個人的なフェチズムが全開の内容となっています・・・(笑)

 

ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

 

 

今回は「ギルガメッシュ」「ガンバンテイン」「ストレングス」をご紹介させていただきましたが、いかがでしたでしょうか?

 

クラッシュフィーバーでは、キャラクターのデザインに

「クラッシュフィーバーらしさ」を求められており、

できるだけありきたりだったり、見ていて退屈にならないように

デザイナー班やスタッフ一同で奮闘しております。

 

今後新しいキャラクターが出てきた時に、

何のテーマで作ったのか考えてみると面白いかもしれませんね。

 

それではお読みいただき、ありがとうございました!

 

 

シルエット素材を作ってみよう

こんにちは。

グラフィックデザイナーの大鹿です。

私の主業務はクラッシュフィーバーのアプリ内外で使われる

「バナー」制作ですが次いで頻繁に作るモノがあります。

それは「シルエット素材」です。

 

シルエット素材は文字通りキャラクターイラストをシルエット化したものです。

最高難易度クエストのバナーやお知らせ記事内でよく使用されます。

今回はそのシルエット素材を作る行程をご紹介したいと思います

 

1.シルエット化するイラストpsdを用意

f:id:ooshika:20170606193028p:plain

今回、解説用にシルエット化するのは最高難易度ボスの一人「織田信長」です。

デザイン、性能ともにユーザー人気の高いキャラクターです。

 

2.光彩エフェクトを取り除く

 

f:id:ooshika:20170606193136p:plain

クラッシュフィーバーのキャラクターイラストは

すべてのフチに「光彩エフェクト」が施されています。

これらはシルエット化にあたり輪郭がボケてしまうので取り除きます。

上図はキャラクターやエフェクトの周囲にあった「光彩エフェクト」を

取り払ったものです。

 

3.余分なエフェクトイラストを取り除く

f:id:ooshika:20170606193150p:plain

キャラクターの周りに張り巡らされるエフェクトイラストは

動作感や空気感を表現する大事な部分です。

とはいえ、シルエット化するとキャラクターの輪郭が隠れてしまうため

一部を残して取り除きます。

 

4.シルエットのベースカラーを配置する

f:id:ooshika:20170606193219p:plain

キャラクターのレイヤーを統合し、上からグラデーションレイヤーを重ねます。

クリッピングマスクでグラデーションレイヤーを切り抜いたら

乗算もしくは不透明度90%程度に設定して少し元絵が見えるようにします。

ついでに横線パターンを追加して「走査線」っぽく見せたりします。

また、キャラクターのシルエットをより目立たせたり

全体のバランスが崩れないようにエフェクトの一部はシルエット化せずに残します。

 

4.顔部分に濃い色を配置して隠す

f:id:ooshika:20170606193318p:plain

ベースカラーの上に新規レイヤーを作成します。

円形グラデーションツールでキャラクターの顔を中心に

不透明度100%のグラデーションを配置します。

色は黒だったり、ベースカラーをより濃くした色を使用します。

これで明度を上げられたりしてもキャラクターの顔だけは隠し通すことができます。

さらに奥行き感も演出できます。

 

6.目を光らせる

f:id:ooshika:20170606193345p:plain

シルエット化させるキャラクターは大半が最高難易度ボス。

強敵感を演出するためにも、目を光らせます。

場合によっては口も光らせたり、目の残像を描き入れたりもします。

 

7.隙間を塗りつぶす

線画と塗りの間など、キャラクターイラストには

拡大しないと見えないような隙間がたくさんあります。

普段は光彩エフェクトやサイズ感のおかげで目立たないのですが

色を載せてシルエット化すると、隙間が白い筋となって見え始めます。

 

f:id:ooshika:20170606193513p:plain

↑隙間どころか穴が開いているケースも...

f:id:ooshika:20170606193524p:plain

↑よく見ると武器周辺にも隙間がたくさん...

 

f:id:ooshika:20170606193410p:plain

手間ですが、下側に新規レイヤーを作成して塗りつぶします。

隙間を全部埋めれば、シルエット素材の完成です。

 

最後に...

シルエット素材はクラッシュフィーバーがスタートしてから

小さく地味な改修を重ねて今に至ります。

「元絵を少し見せたほうが、顔が気になって期待感が上がるかもしれない」

「走査線っぽいエフェクトがあったほうが世界観にあっている」

「エフェクトを少し残したほうがシルエットがもっと目立つ」

ただのベタ塗りでも良かったのかもしれません。

しかし、クラッシュフィーバーのデザイン感とマッチするように

ユーザーの目にもっと留まるように、面白そうと思ってもらえるように。

なんてことのない素材の一つですが、キチンとこだわって作ることが

大事なのだと信じて、作成しています。

 

もし気が向いたらお知らせ欄にいるシルエットを眺めて

どんなキャラクターなのかを妄想していただけると幸いです。

図を継続的に管理するためのベストプラクティス

こんにちは。サーバエンジニアの桐島です。

今回は、図(フローチャート、シーケンス図など)をチームで継続的に管理するための個人的なベストプラクティスを紹介したいと思います。

図の有用性と、継続的な管理の必要性

図って便利ですよね。

以下の様な図があると、チーム内での認識合わせを正確に素早く行うことができます。

  • サーバ構成図
  • アプリ-サーバ間処理のシーケンス図
  • APIプログラムの複雑なロジックのフロー図
  • ER図

ただ、プロジェクトのドキュメントに含まれる図がすべてメンテナンスされ、最新の仕様と図がマッチし続けているケースは少ないのではないでしょうか。

図は有用なのですが、管理し続けなければその有用性を失い、いずれ削除される運命にあります。

図の継続的管理への課題

では、図が管理されない原因は何でしょうか。 具体的なケースを幾つか挙げてみます。

  • 再編集できないフォーマットで図が作られている
    • ホワイトボードに書いた図を撮影した写真を共有する
    • 再編集できない画像ファイルとして共有する
  • 再編集できるフォーマットで作られているが、閲覧・編集するために特殊なツールが必要となる
    • 専用ツールのインストールが必要となる
    • インストールに手間が掛かる
    • Mac と Windowsでツールの動作が異なる
    • ツールの学習コストが高い
  • 図の存在が知られていない(図が散在している)
  • 知らない間に図の内容が古くなっている

これらケースから考えると、大きな原因は以下の2点にありそうです。

  1. 図の閲覧、作成、編集がハイコスト(特に編集)
  2. 図を作成するタイミングが決まっていない

この課題をクリアし、図を継続的に管理するための方法を考えたいと思います。

継続的画像管理のアイデア

先に結論を書くと、以下方法が良いと考えています。

  • SVG形式で図を扱う
  • draw.io と GitHub で図を作成、編集する
  • 図の変更をPullRequestに含める

f:id:s-krsm:20170529121549p:plain

この方法のメリットは以下となり、上述の課題を解決できそうです。

  • チームメンバ全員が簡単に同じ方法で図を閲覧、作成、編集することが可能
    • 図の閲覧、作成、編集のローコスト化
  • プログラムと図を紐付けてバージョン管理することが可能
    • 図の作成、更新タイミングの明確化

次に、具体的な手順を見ていきたいと思います。

具体的手順1(図の作成)

1. draw.ioで作図

draw.io で図を作ります。

f:id:s-krsm:20170529121446p:plain

2. SVGとしてexport

SVGファイルとして保存することで、draw.ioで再編集可能となります。

f:id:s-krsm:20170529121718p:plain

export実行します。

f:id:s-krsm:20170529121801p:plain

3. export先として GitHubを選択

f:id:s-krsm:20170529121834p:plain

draw.ioとGitHubを連携するためには認証が必要です。

連携したGitHubアカウントがアクセス可能なリポジトリ一覧が表示されます。

f:id:s-krsm:20170529121911p:plain

4. export先のリポジトリ・ブランチ・ディレクトリを選択

f:id:s-krsm:20170529121944p:plain

commit メッセージを書き、OKボタンを押すとcommit完了です。

(SVGファイルが指定リポジトリに追加されます)

f:id:s-krsm:20170529122019p:plain

具体的手順2(図の編集)

1. GitHub上のファイルを開く

f:id:s-krsm:20170529122151p:plain

作成時と同様の手順でGitHub上のsvgファイルを選択します。

(リポジトリ・ブランチを選択可能です)

2. 変更をcommit

GitHub上のファイルを編集した場合、編集後に「Unsaved changes. Click here ti save.」というボタンが表示されます。

f:id:s-krsm:20170529122232p:plain

これをクリックすると、commitメッセージを書いてcommitすることができます。

(commit先は、ファイルを開く時に指定したブランチとなります)

f:id:s-krsm:20170529122307p:plain

具体的手順3(図の差分確認)

PRのレビュー時に画像の差分を確認しますが、GitHubのrich diffツールが素晴らしいです。

SVGファイルの文字列差分では変更箇所は分かりませんが、rich diffツールを使うと画像の変更箇所を素早く把握することができます。

2-up で差分確認した場合

f:id:s-krsm:20170529122354p:plain

Onion Skin で差分確認した場合。

f:id:s-krsm:20170529122404p:plain

具体的手順の紹介は以上となります。

ブラウザだけで図の作成、git commit/push、レビューまで完結できていることは驚きですね。

まとめ

図を継続的に管理するための個人的なベストプラクティスを紹介しました。

ただ、図の扱いはチーム(規模、構成、状況等)により、メリットもデメリットも異なると思います。

例えば、リモートワーカーが居るチームでは図を作成し共有することによるメリットが大きいですが、小さなチームの開発初期段階では、作図コストのデメリットが大きいかもしれません。

また、必要となる図の対象・粒度もチームにより異なると思います。

今回の記事が、チームに最適な図の共有方法を考える参考になれば幸いです。

バグを生まないために気をつけたいコードの書き方

こんにちは。アプリエンジニアの大橋です。

今はそれほどではないのですが、少し前まで仕事の大半をコードレビューに費やしていた時期がありました。
どちらかというと自分で実装する方が断然好きですが、
それはさておき、いろんなコードを見るなかで、
「このコードの書き方だと、正常に動作してはいるけど、後々不具合を生みやすそうだなぁ」
と感じることがあったりするので、
そういうコードのパターンをいくつか取り上げさせてもらおうかなと思います。
自分自身も気を付けたいという意味も多分に含んで。

というわけで、さっそくひとつめ。

変数名や関数名が処理内容と違う

基本的なことではありますが、たまにやってしまいます。

コードを読むとき、変数名を見て「こういうことに使ってる変数かな?」と想像して読んだりしますが、
実際は違った使われ方がされてると、コードの理解の妨げになりますし、
誤解したまま別の人がその変数を使ったりすると不具合の原因になってしまいます。

関数名やクラス名もまた然り。
ちゃんと処理内容にあった変数名や関数名を付けましょう!!

あと余談ですが、自分が実装するとき、変数名や関数名の名前に結構悩みます。
的確な名前を付けたいと思うのですが、英語が得意というわけでもないので、
なかなかこれだっていう名前が付けられないときがたまにあって、
そういうときは大抵、辞書を引いてニュアンスとかを考えだしたりして、深みにハマります……
英語が得意じゃないプログラマーは、英語圏のプログラマーより生産性がかなり落ちるんじゃないかと 常々思うところです……

あと、これに関連してですが、
耳慣れない単語を使うと後々困ります……

単語の意味が合っているからといって耳慣れない単語を使うと、

  • 他の人がコードを把握しようとしたとき単語の意味が分からないので辞書を引かなければいけない
  • 読み方を忘れるので会話するとき困る

ので、わかりやすい名前を付けましょう!!

そしてふたつめです。

public関数に暗黙の使用条件がある

ついついやってしまうのですが、気をつけたいなと思うことです。

例えば
「ある関数Aを実行するときは、その前に別の関数Bを実行しておく必要がある」
といったことがあると思います。

もし前提条件の関数Bを実行せずに関数Aを実行してしまった場合の
エラーハンドリングがちゃんとできていれば大丈夫かとは思うのですが、
エラーハンドリングもされず、その関数やクラスのコメントにも関数Bをあらかじめ実行しておく必要があることが 書かれていない(=暗黙の条件)状態だと、
後から別の人がその関数を使ったり修正したときに不具合が発生する危険が増しますし、
コードを把握するための時間もかかってしまいます。
実装した本人でも忘れてしまいますし。

あまり関数を使うための前提条件をつくらない方がベストな気がしますが、
やむおえない場合はきちんとコメントに書いておきたいところです。

ということでみっつめ。

関係なさそうなところで影響し合っている

「ある関数の処理内容を変更したら、実は他の場所でその関数の処理内容に依存した実装があり、不具合が発生した」
というようなことがよくあるような気がします。

特に、あまり関係なさそうな処理同士が依存していると、
後から関連処理を修正するときに見逃しやすく、処理を把握するのも大変。
処理の依存関係はできるだけ小さい範囲でまとめたいところです。

まぁ、テストを書け、ということかもしれませんが、
依存関係が散らかってないコードを書ける人は尊敬します。

そしてラスト。

難解すぎて何をやってるかわからない

凝ったコードでも他の人が理解しやすいコードはいいのですが、
なにをやっているか理解しづらい難解なコードは避けたいところです。

他の人が読み解くのに時間がかかりますし、
完全に把握できていない状態で変更を加えられたり、コピペして使われたりすると危険です。

コードを短くするために凝ったコードを書くより、
ある程度長くなっても理解しやすいコードのほうが良いんじゃないかなと自分は思います。
ムダに冗長なコードは避けたいですが。

最後に

この記事を書いていて思いましたが、
不具合を生みにくいコードを書くことで、「不具合を生まない」ということだけでなく、
後々の生産性の向上にもなるような気がしました。

自分自身も、
ついついめんどくさがって、あまり後々のことを考えずに簡単に実装できるコードを書いてしまいますが、
後々のことを考えて、できるだけ不具合が生まれにくいコードを書いていきたいものです。

ゲームプランナーになるには、どんな能力が必要なの?

ゲームプランナー&レベルデザイン担当の程塚と申します。

ゲームプランナーについて、つらつら書きたいと思います。

 

どんな方向性 のゲームにしたいのか、

作っていく途中で どんな問題 があり、どう解決 すれば良いのか。

それを 発案 する、または、他から発案を引き出して、リードする役目

面白いアイディアが思い付いて、且つ、

それを 具体的にゲームに落とし込む実現力 がある人。

それがゲームプランナーです。

 

① 情熱・やる気・根気
→ ゲームに対する自分なりの考えがある
→ 言われた事だけやるのではなく、自発的に学ぼう とする
→ 嫌なことがあっても逃げない
→ 好きだけでは続けられない、好き以上の気持ち が必要

 

② 感性・センス・発案力
→ 何かを真似るだけに留めず、アレンジしたり、より良くしたり、新しさやオリジナリティを考え葛藤する こと
→ ゲームだけでなく、他の遊びや芸術などの広い視野があったり、友達との思い出や恋愛経験など、色々な引き出しがあること、もしくは作ろうと努力すること

 

③ 客観的判断・論理的思考・会話力
→ 物事を 客観的に見れる
→ 自分の意見を論理的に正しく説明できる
→ 相手の意見を正しく理解する事ができる
→ 論点を明確にし、ぶれた話を起動修正しながら話す ことができる
→ 感情的になったとしても話の筋を見失わず、個人的な感情よりもそのゲームを良くする事が大事であるからと、冷静に話を分析、判断できること

 

愛情がある
→ ゲームという表現への愛情がある
→ プロジェクト自体、または、そのゲームへの愛情がある
→ チームの仲間への愛情がある
→ わざわざ 自分の人生の時間を費やして、そのゲームを遊んでくださるユーザー様への感謝の念 を常に持つ

 

絶対はない

自分を信じる事
→ ただ感覚的に自分の考えは面白いとか正しいと思い込むのではなく、自分の考えが知識やノウハウやデータから見て、客観的に正しいことを示す事が大事である。ただ現実では、それを受け取る上司や仲間にも能力が必要なので、仮にプランナーが死ぬほど頑張ったとしても、必ずしも良いものが出来るとは限らない。逆もしかり。

自分を疑う事、他人を認める事
→ 自分の考えは間違っているかもしれない。自分の考えより良い考えがあるかもしれない。他の人の考えを正しく判断し、取り入れる力が必要である。


ダメなプランニング例 〉
① 全体の各機能の関連性と役割をちゃんと見渡せていない ( 現状の問題認識が不十分 ) のに、足せばいい的に細かい枝をどんどん付けていき、まとまりのないものにしてしまうもの
② 目的や大枠ばかりを気にして、細部のバランス調整がしっかりできていないもの
③ 長い間それを使った際に将来的にどうなるか ( 各機能の消費による時間的な変動 ) を想定していないもの

 

現実と対峙する
① 利益を出さなければならない
② スケジュールに間に合わなければならない
③ 技術的にできないこともある
④ チームの連携が上手く行かない
など、他にも色んな現実の壁とぶち当たるから、それと対峙しなければならない

 

〈 やり込み 〉
プランナーたるや、そのプロジェクト内で誰よりもそのゲームを遊び、誰よりも内容に詳しくなり、たくさん記憶し、色んなものを一瞬で引き出して比較、判断できるようにしておくこと


突っ走って書きましたが、以上です。

読んでくださった方にとって何か参考になれば幸いです。ありがとうございました。

エフェクト制作におけるSpriteStudioデータのフォルダ構成

アートディレクターの榊原です。

SpriteStudioでエフェクト制作するにあたって、データのフォルダ構成で悩んだので一例として辿り着いたものを紹介したいと思います。
使用しているSpriteStudioのバージョンは5.7.0となります。

何にも考えないでデータを作ると下記のような感じになりました。
f:id:wp_sakakibara:20170511224318p:plain
見づらい・・・し、エンジニア側も色々と困りそうです。

そこで下記の要件を満たすように見直しました。

  • 整理されて見易くしたい
  • できるだけエンジニア側の実装を容易にしたい(実装するエフェクトの数が多いと馬鹿にならないようです)

f:id:wp_sakakibara:20170511224324p:plain
ポイントは主にこちらのようになります。

  • commonフォルダに各プロジェクトファイル共通のデータ(画像ファイル、ssceファイル、ssaeファイル)を置く
  • プロジェクトファイル名と同じ各フォルダにはプロジェクト固有のデータ(画像ファイル、ssceファイル、ssaeファイル)を置く(例外もけっこうありますが)
  • プロジェクトファイル内で最初に再生してもらいたいメインのssaeファイルの名前は"play.ssae"とし、再生するアニメ名は"play"とする

こうしておくと威力差分や属性差分等の差分制作エフェクトのように共通の画像でいくつもプロジェクトファイルを作成する場合でもフォルダ構成を見ればどんな構造になっているかわかりやすいですし、エンジニア側はとりあえず"play.ssae"の"play"アニメを再生すれば良いので実装し易い(らしい)です。
現状手掛けているSpriteStudioで作るエフェクトは基本このような構成にし、モノによって派生パターンを作っています。(実際はもっと細かなルールが設けてあります)

用途によってベストなフォルダ構成は違うと思いますが、私のように悩んだ時の参考の1つになればと思います。
基本的に画像素材は共用で使うものとし、ルート的な場所に共用画像用フォルダを作り様々なエフェクトが共用で画像を参照する構成にした方が賢い場合もありそうです。
f:id:wp_sakakibara:20170511225638p:plain


ちなみに今回紹介したフォルダ構成を見直し前 → 見直し後に後から変更しようとすると正当な方法ではかなり手間のかかる手順を踏む必要があります。

  1. エクスプローラー上で移動したいファイルをコピーし、移動先のフォルダに貼り付ける
  2. SpriteStudio上で移動先のファイルを追加する(既存ファイルの追加)
  3. 追加したssaeの参照セルを変更する
  4. 必要なくなった昔のssaeとssceを削除する

・・・なんて大変!
今の所SpriteStudio上ではフォルダ構成やフォルダ名を変更する機能は無いようです。そのためフォルダ構成ははじめのうちにキッチリ決めてしまっておいた方が良いと思います。

余談

SpriteStudioのデータは実装用にコンバートするとプロジェクトファイル単位のデータに変換されます。ssaeファイル毎にデータが作られるんだと勝手に思い、ssaeやssceまで共有化できるなんてスバラシイ!思っていましたがそうウマい話では無いようです。
このためエフェクト単体毎にできるだけ負荷を減らそうと考えると差分制作エフェクトであってもssaeではなくsspj単位で分ける必要があります。
ちなみにsspjファイルを同時に複数開く機能やsspjを跨いでコピー/ペーストする機能は現状無いので、sspj単位にファイルを分けて制作することは思った以上に手間がかかったりします。

GunicornのUNIXドメインソケットが喪失するバグへの対応

エンジニアの原です。

弊社内のいくつかのPythonを使用したWebサービスでは、アプリケーションサーバーとしてGunicorn を使用しています。

先日サービス全体には大きな影響がなかったものの、そのGunicornのバグを踏み、一部のサービスが不安定になったことがあったのでその事例紹介をします。

環境

  • Python 3.4.2
  • Gunicorn 19.6.0
  • Nginx 1.12.0

現象

特に負荷のかかる時間帯にもかかわらず、任意のWebサーバーのnginxからクライアントに502レスポンスが返されていました。 nginxのログ的に、Gunicornがリクエストハンドリング用に生成しているUNIXドメインソケットが喪失したようです。

nginxのupstreamとして稼働しているGunicornのログには、以下のようなスタックトレースが出力されていました。*1

level:ERROR      time:2017-02-14 00:00:00 (JST)        process:100001     name:gunicorn.error   message:Exception in worker process
Traceback (most recent call last):
  File "/var/www/example/venv/default/lib/python3.4/site-packages/gunicorn/arbiter.py", line 557, in spawn_worker
    worker.init_process()
  File "/var/www/example/venv/default/lib/python3.4/site-packages/gunicorn/workers/gthread.py", line 109, in init_process
    super(ThreadWorker, self).init_process()
  File "/var/www/example/venv/default/lib/python3.4/site-packages/gunicorn/workers/base.py", line 132, in init_process
    self.run()
  File "/var/www/example/venv/default/lib/python3.4/site-packages/gunicorn/workers/gthread.py", line 240, in run
    s.close()
  File "/var/www/example/venv/default/lib/python3.4/site-packages/gunicorn/sock.py", line 123, in close
    os.unlink(self.cfg_addr)
FileNotFoundError: [Errno 2] No such file or directory: '/var/run/sockets/gunicorn.sock'

CPU稼働率、メモリ使用率等のシステムリソースには特異点はありませんでした。

原因

同様の問題に関するissueがありました。

github.com

issue内のコメントでも言及されていますが、原因は19.6.0で入ったこの変更だと思われます。

github.com

該当箇所は以下です。

-    def close(self, locked=False):
-        if self.parent == os.getpid() and not locked:
-            os.unlink(self.cfg_addr)
+    def close(self):
+        os.unlink(self.cfg_addr)
+        super(UnixSocket, self).close()

本来ならば、UNIXドメインソケットはarbiterプロセスのみによってファイルunlinkされるはずですが、workerプロセスによってunlinkされるようになっていました。
このcloseメソッド内ではプロセスIDからarbiterプロセスであるかの判定が必要なのですが、その判定が当該コミットで削除されています。
どうやらcloseメソッドを呼ぶプロセス自体がarbiterプロセスのみになるため削除したらしいのですが、19.6.0ではまだworkerプロセスでcloseメソッドが呼ばれてしまっているようです。

対策

この現象は、GunicornをUNIXドメインソケットでバインドさせた際に発生する問題なので、 UNIXドメインソケットではなくループバックアドレスに未使用ポートでGunicornをlistenさせることで解決しました。

- bind = 'unix:/var/run/sockets/gunicorn.sock'
+ bind = '127.0.0.1:8080'

なお、このバグは2017/3/4にリリースされたGunicorn v19.7.0で修正されています。

github.com

closeメソッド自体が削除され、別の場所でunlinkされるようになったようです。
バージョンアップしたいところでしたが、内部の実装が大きく変わっていたため、緊急性と安定性を鑑みてバージョンアップは見送りました。

まとめ

UNIXドメインソケットを使用する場合は、v19.6.0以外のバージョンを使用するようにしましょう。
非常にニッチなテーマで恐縮ですが、誰かの助けになれば幸いです。

*1:ログ日時、ファイルパスなどは実際のものとは異なります