Quantcast
Channel: サイバーエージェント 公式エンジニアブログ
Viewing all 161 articles
Browse latest View live

ソーシャル系Webサービスのデータマイニングで社会科学をしてみたい

$
0
0

こんにちは、技術本部 秋葉原ラボのデータマイニングエンジニア の高野(@mtknnktm)です。弊社で運営しているゲームやコミュニティなどのソーシャル系Webサービスをより良くしていくためのデータ関連のあれこれを主な業務としています。そんな日々の業務の中で、ソーシャル系Webサービス上での現象や課題が、社会科学系の研究と関連してるんじゃないかなーと思ったので、その関連についてつらつらと書いてみました。最近、ソーシャル系Webサービスのデータを使った社会科学研究は非常に盛んで、SocInfoCOSNSocialComIC2S2などなど、それを含む Computational Social Science をテーマとした新しい国際会議も数多く開催されています。本記事で取り上げるものは、私が主に興味のあるものを挙げたため、かなり偏りが有るかと思いますが、その他にもこんな興味深いトピックがあるよ! というものがありましたら教えていただけますと幸いです。また、各トピックに関する不足・誤りなどもご指摘いただけますと幸いです。
本記事でご紹介するトピックは以下です。
  • 協調行動
  • 社会的グルーミング
  • 性選択(性淘汰)
  • 内集団バイアス
  • ペドフィリア検出
ソーシャル系Webサービスの「ソーシャル」の分析
ソーシャル系Webサービスを含む、Web系のサービスのデータ分析の基本的な流れは、第一にサービスの目的に対する現状を表現する指標(Key Performance Indicator: KPI)を設計し可視化すること、第二にそのKPIを向上させるためにサービスのデータを分析し、施策に結びつけることだと思います。例えば以下の様なイメージです。
こういった分析の多くはユーザ個人の行動や属性に着目して行われるかと思います。例えば、「◯◯という行動をした人は継続してサービスを使い続けてくれる、つまり、その行動はサービスを継続して使用していただくような良さを知っていただくために重要であるはず。そのため、その行動をユーザにしていただきやすい作りにサービスを改善しよう。」と言った感じです。私の普段の業務もこういった分析が中心です。
一方でソーシャル系Webサービスはその名の通りーザ間の社会的なやりとりがサービスの重要なポイントです。例えばソーシャルネットワーキングサービス(SNS)ならば、ユーザ間のコミュニケーション、ソーシャルゲームだったらユーザ間の協力と競争などです。このようなヒトの社会的な側面について、社会心理学、進化心理学、理論生物学、進化生物学、人工知能、複雑系/人工生命など多くの分野で研究されいます(私も大学院で複雑系/人工生命の分野で社会性の進化についてシミュレーション研究をしていました)。こういった分野の理論・実験・調査研究をソーシャル系Webサービスと比較すると、ソーシャル系Webサービスは実際にヒトが自分の意志でサービスを利用し、サービスの仕組みの範囲内で任意のタイミングで任意の行動が可能であるため、理論的・実験的な先行研究のようにモデル化された環境よりも自由に振る舞うことができます。そして比較的小規模なものでも数万人以上の多くのユーザの社会的相互作用であるため、非常に大きな集団サイズを仮定することの多い理論研究(数理解析・シミュレーション)との対比がしやすくもあります。また、サービスの仕組みにより調査研究が対象としている実社会よりはユーザの行動は制限されるため、現実の社会よりも理解が容易、かつ、ユーザの行動はログとして記録されるためより詳細な分析が可能になります。弊社ではユーザの行動ログはHadoopを基礎とした大規模データ解析基盤 Patriot [善明13] に格納されるため、非常に大規模なデータ分析も手軽に容易に可能です。
したがって下図のように、先行研究の上にソーシャル系Webサービスのデータ解析を位置づけることができます。このように位置付けることで、非常に多く存在する先行研究の知見や枠組みは、ソーシャル系Webサービスのユーザの行動理解に利用でき、サービスをより良くしていくために有用なはずです。また、ヒトの社会性に対する定量的な研究において、ソーシャル系Webサービスのデータ分析は強力な手段であり、ヒトの社会的行動に関する知見を得ることができるはずで[Bainbridge07Szell10, Arnaboldi13a]。以下では、具体的にどのような社会科学のトピックがソーシャルサービスに関連するかについて述べていきます。

図: ソーシャル系Webサービスのデータマイニング研究の位置付け

協調行動
相互の協調はヒトをはじめとして多くの動物に見られる現象であり、社会を形成する上で重要な要素です [Fehr03, Smith00]。しかし、他個体に協力する利他的な個体は利己的な個体と相互作用すると搾取され、利己的な個体だけが高い利益を得るため相互の協調状態は不安定なはずです [Axelrod06]。それにもかかわらず我々は社会的生活を営む上で相互に協調し合っています。したがってヒトは進化の過程において相互の協調関係を維持するメカニズムを獲得してきたはずです [Barkow95]。
このようなヒトやその他の動物の協調行動を説明するために非常に多くの理論的・実験的研究が為されてきました [Nowak06, Rand13]。そのため、安定した相互の協調状態を実現するにはどういった仕組みが必要か? それを促進するような環境はなにか? といった知見が非常に多く得られています。そういった知見をサービスの仕組み作りに活かしたり、また、サービス内でのユーザ同士の協力関係について分析することで、ヒトの協調行動についての知見が得られるかもしれません。協調行動の研究は、自分は損をしても相手に利益を与えるという協調行動を定義するために、個体間の利害が明示的に存在するモデルを作り、それの数理・数値解析や心理学実験をするという研究が多く存在します。したがって、ソーシャル系Webサービスの中でも複数のユーザの協調と競争要素が明示的にゲームの仕様に盛り込まれているソーシャルゲームは協調行動の研究と相性がいいと考えています [高野15]。
例えば、協調行動の維持には、協調するか否かといった協調行動に関する戦略と共に、どの相手と相互作用をするかというパートナー選択が重要であることが、多くの理論研究 [Santos06, Ichinose08, Chen09, Damore11, Chen12]、実験研究 [Fehl11, Rand11, Wang12] で示されています。我々は弊社で提供しているソーシャルゲーム ガールフレンド(仮)における協調行動とパートナー選択行動について分析し、グループ間移動(ガールフレンド(仮)では部活をやめて別の部活に入る)ができることで、協調的なユーザが、今所属しているグループに不満があったときに他のグループに移ることができ、それが協調行動を促進していることを示しました [高野15]。
また、TwitterやFacobook、Google+のようなSNSにおける、情報提供(コメントの投稿)とそれに対する反応(リツイートやいいね)に対して、メタ規範ゲームという枠組みを適用することで、協調行動として扱えるようにした理論研究 [鳥海12, Hirahara14] もあり、明示的な競争と協調という要素が存在するソーシャルゲームだけでなく SNS にもアプローチすることができるかもしれません。

社会的グルーミング
社会的グルーミングとは、複雑な社会での仲間関係などの社会関係の構築や確認の手段として機能している社会的行為です [Wikipedia - Social Grooming]。ヒト以外の霊長類では社会的グルーミングは毛づくろいとして観測されています [Nakamura03]。一方で、我々はそういった毛づくろいをほとんどしません(親子や恋人など非常に親しい関係でのみ [Nelson07])。それは、ヒトのグループのサイズは他の霊長類よりも非常に大きいために、毛づくろいという時間や手間が掛かり、かつ、一対一でしか実行できない行為によって社会関係を構築することは難しいからだと言われています [Kobayashi97, Dunbar04]。最もヒトに近いチンパンジーのグループサイズが数十程度である一方、ヒトは150人程度と推定されています [Dunbar00]。この150人という数値はダンバー数と呼ばれています。この数値はオフラインの集団 [Zhou05] だけでなく、Facebook [Arnaboldi13b] やTwitter [Gonçalves11] というインターネット上での社会関係データを使った分析でも確認されています。ヒトはこのような多くの相手と社会関係を構築するために、時間や手間がかからない低コストな社会的グルーミング手段として、視線 [Kobayashi97] や一度に複数人に実行可能なうわさ話 [Dunbar04] といった社会的グルーミングの手段が進化したと言われています。
SNSで考えると、例えばFacebookのいいねは最も低コストなタイプの社会的グルーミングと言えるでしょう。このような社会的グルーミングの性質を知ることで、そのサービスが狙いとする社会的関係の濃さに適切なコミュニケーション相手の人数を推定する、または、コミュニケーション相手の人数をある範囲内で制限することで狙いとする濃さの社会的関係を実現するといった形でサービス開発・運営に役立てられるかもしれません。弊社で提供しているサービスで言うとアメーバピグ755などのコミュニティサービスのデータ分析によってアプローチできそうです。
また、我々は ガールフレンド(仮) のデータを分析することによって、相互に協調し合うような協力関係を構築・維持するためには簡便なメッセージ(ガールフレンド(仮)では "かわいいね")を相互に送り合うことが重要であることが示され、これも社会的グルーミングの一種ではないかと考えています [高野15]。また、Twitter上での数年に渡るコミュニケーションデータを分析することで、ヒトのオンライン(SNS)上での社会的関係の構築・維持の仕方とオフライン(インターネット外)でのそれが異なることが示されています [Arnaboldi13a]。
社会的グルーミングと社会的グループサイズの研究は、ヒトの脳が他種に比べて極端に大きいことを説明する有力な仮説「社会脳仮説」とも深いつながりが有り [Dunbar00]、ヒトの知性の起源に関する興味深いトピックだと言えます。
我々の社会におけるオンラインでのコミュニケーションが占める割合は、今後、より高まっていくと考えられます。しかし、150人程度のグループという環境でオフラインなコミュニケーションをして進化してきたヒトの社会が、オンラインコミュニケーションを獲得することによってどのように変化するか? はまだ十分な研究がされておらず、その影響を把握することはヒトの社会の未来にとって重要であると言えます [Arnaboldi13a]

性選択(性淘汰)
性選択とは進化生物学における重要な理論の一つで、異性をめぐる競争を通して起きる進化のことです。この理論によって生物種の奇妙な形質が進化した理由を説明できる場合があります。有名な例ではクジャクの雄はなぜ美しい? [長谷川05] という話題でしょう。クジャクの羽は非常に美しいですが、その派手さ故に天敵にみつかりやすい、大きいため機敏な動きがしづらい、など生存競争において多くのデメリットがあります。そのようなデメリットがあるにも関わらず、なぜこのような派手で大きな羽を持つようになったか?(同時に、なぜメスがそんな生存に不利なオスを選ぶか? )をメスがそのような羽を好み、メスに選ばれるためという異性による選択で説明しようとするものが性選択理論です。
我々も有性生殖により繁殖をするので、当然、ヒトの性的嗜好もこの性選択が関わってくるはずです。ヒトの性的嗜好に関しても様々な研究がなされており、それらをダンバーが一般向けの著書 友達の数は何人?[Dunbar11] の7章 今夜、ひとり? でわかりやすく紹介しています。例えば、ヒトでは「ヒトは異性に対して自分の何をアピールするか?、そして、ヒトは異性に対して何を求めるか? 能力か? 美貌か? 財産か? 若さか? 性格か?」について知るために、恋人募集広告を分析した研究 [Douglas92] などが紹介されています。それを含めたダンバーが著書で紹介した研究の結果をまとめると、男性は自分の子供をより多く増やせそうな受胎能力の高そうな女性(若く健康的な女性)を求め、女性は自分の子供の生存率が高くできそうな基盤(つまり財産、および財産を増やせる能力)を持った男性を求め、そしてそれぞれ、それを相手にアピールしていた(男性は学歴や財産、女性は美貌や若さ)そうです。なんだか身も蓋もないですが、遺伝子を多く残すための進化的に適応的な戦略と言えるでしょう。
上記の研究は恋人募集広告を手動で分析した例ですが、Webサービスでいうと婚活サービス・出会い系サービスが類似したものと言えます。そのようなサービスのデータを分析することができれば、上記の研究をより多くのデータを使ってより詳細に分析することができると考えられます。また、既存研究やそこで得られた知見をサービスに活かすこともできると考えられます。例えば、各ユーザ属性や行動に基づく異性獲得戦略について知ることができれば、それを元にした双方が満足するような高精度のマッチングや、異性獲得戦略の定義・分類によって、婚活サービス(まじめに出会いを探している人のためのサービス)なのにそうではない出会いを求めるユーザのフィルタリングなどに活かせるかもしれません。

内集団バイアス
内集団バイアスとは内集団ひいきとも呼ばれ、自分の所属するグループ(内集団)のメンバーに好意的な態度を取り、他のグループ(外集団)のメンバーを卑下する態度を取るよな行動傾向のことです [柿本97]。ここで言うグループは国家、性別、人種、民族、学歴、会社、方言、所属部署、仲の良しグループ、喫煙者/非喫煙者、好きなスポーツ、世代、服の趣味などなど様々な大きさ・概念があり得ます。また、より詳細な傾向としては、グループの地位とグループ内の地位に依存してグループ内 / 外の人に対する評価の傾向が変わるという傾向があることが指摘されています [杉浦15]。この研究では高地位グループ内の低地位者は、同グループの高地位者よりもグループメンバーを高く評価するひいきせず他のグループを卑下しがちであり、低地位グループ内の高地位者も他のグループを卑下しがちである傾向が強いことが示されています。この結果は高地位グループ低地位者は他のグループメンバーを評価するとグループ内の地位差がより開いてしまうため、低地位グループ高地位者は他のグループとの地位差を埋めるためという、社会的な戦略の結果であることを示唆しています。霊長類においてグループ内の地位の高さ(いわゆるボス猿とか)は生殖活動においても極めて重要です。このような内集団バイアスを示す傾向も進化的に獲得された形質であると言えます [小野田13]。
内集団バイアスによる外集団卑下は人種差別・部落差別・いじめなど深刻な差別にも関連するため重要な課題です。インターネットには大量の有用な情報・手軽で楽しいコミュニケーションと共に、炎上やクソリプを言われるような相手を見下すような発言が少なからず存在します [Yardi10ソーシャルメディアで炎上する原因:ミクダス仮説に関する議論 - Togetterまとめ]。また近年ネットいじめと言われる嫌がらせも大きな問題になっています [Homa14, Wikipedia - ネットいじめ]。その中には内集団バイアスにより外集団卑下に起因するものも存在するでしょう。こういった問題は弊社や他社の多くのコミュニティサービスで発生しており、各社解消のために力を入れています(弊社の取り組み例: [健全なサービス運営のための取り組み])。
したがって、既存研究の内集団バイアスに関する知見のネットいじめ・炎上・クソリプの緩和への応用ができるかもしれません。また、オンラインでのいじめ・炎上・クソリプはオフラインな場で行われる差別的な行為よりも、発言者や被発言者のデータを集めやすく処理も比較的容易です。例えば、発言のテキストだけでなく、発言者・被発言者の相互作用ネットワークやそれのダイナミクスに関するデータも得ることができる場合があります。それによって、内集団バイアスというヒトの形質が生み出す現象に対して、オフラインデータを使った研究とは異なった側面からのアプローチができるため、新たな知見が得られるかもしれません。
一方で、内集団バイアスは外敵から身を守るためにグループ内での協調を促進する基盤としても働いている可能性があり[小野田13]、グループ間の競合が強いほど、グループ内の協調は増加したという報告もあります [Gneezy11]。そのため、例えばソーシャルゲームなどでグループメンバーが互いに協力するなど、よりチームワークを楽しめるサービス作りとも関連は深いと考えています。

ペドフィリア検出
警視庁の調査「コミュニティサイトに起因する児童被害の事犯に係る調査結果(平成25年下半期)」によると、児童の性犯罪被害数は出会い系サイトがやや減少傾向に有り、コミュニティサイトが増加しているようです。コミュニティサイト経由での犯罪被害に遭った児童は平成25年の1年間で1,293人(前年比20.2%増)です。弊社もコミュニティサイトを複数運営しており、それらのサービスの健全性を保つために力を入れています [健全なサービス運営のための取り組み]。
ペドフィリア(のうち未成年に性的被害を及ぼす有害な人の)検出としてオンラインチャットユーザのうち、未成年ユーザを成人による性的被害から守ることを目的として、オンラインチャットログの分析研究がされています [Gupta12Cano14] 。これによると未成年ユーザにアプローチするペドフィリアの振る舞いは、複数の段階に分けられ、彼らの特徴ある振る舞いは割と早い段階から現れる傾向があることが示されています。つまり、(実際に会おうとするなど)具体的な行動に移すかなり前に目星を付けられるかもしれないということです。もし、早い段階でそういったユーザの検出がある程度可能になれば、従来のフィルタリング [福田15] だけでなく、さらに効果的な対策が可能であると考えられます。

まとめ
上記で述べた5つのトピック以外にも多くのソーシャル系Webサービスと関連する研究が存在し、例えば情報拡散というトピックでは社会ネットワーク上での拡散の理論的研究 [Kawamoto13松原13] 、TwitterなどのSNSのデータを使用した研究 [Shu10] 、デマ拡散防止 [梅島11白井12] や炎上防止 [調和技13] などの研究・応用がなされています。SNSでの書き込みなどの情報からコンテンツのヒット度合いを予測するヒット現象の数理 [Ishii12] など興味深い研究が多くあります。また、弊社秋葉原ラボでは他にも弊社サービスの膨大な会話ログを利用した雑談対話システムの研究開発 [牧田15] をしていたり、博士課程在籍中の同僚も金融工学の関連でいろいろと考えているようです [アキバ系社会人ドクターのすすめ]。
ここまで述べてきたように、弊社のようなソーシャル系Webサービスを持つ企業には社会科学研究に深い関連がある興味深いデータが多く存在しています。我々はまだ十分な成果を出せた状態ではないですが、サービスへの貢献とともに論文・国際会議への投稿も積極的にしていきたいと考えています。今後はより上記のトピック(やそれ以外の多くの興味深いトピック)に関する調査・研究を進め、それらの知見をサービスへ適用することで楽しい / 健全なサービスづくりへと活かし、また、社会科学研究への貢献ができたらいいなぁとか考えています。つらつらと書いてみた本記事ですが、ソーシャル系Webサービスのデータ分析に少しでも興味を持っていただければ幸いです。

参考

GraphQLについて調べてみた

$
0
0
こんにちは、秋葉原ラボの鈴木(@brfrn169)です。
普段は、ログ解析基盤のインフラ部分や分散DB(主にHBase)周りをやっています。

今回は、先月の2015年7月にFacebookがRFCドラフト案を公開した「GraphQL」について紹介します。
執筆時点の情報をもとに書いておりますが、GraphQLは現在ドラフト段階なので、今後、変更があるかもしれませんのでご注意ください。

概要

GraphQLは、クライアント・サーバ間でのデータのやりとりを記述するためのクエリ言語です。
GraphQL自体は2012年からFacebookで開発されており、先月の2015年7月にRFCドラフト案を公開しました。

GraphQLの文法は直感的で柔軟であり、学習コストが小さいことが特徴となっています。

百聞は一見にしかずということで、まず以下のクエリをご覧ださい。
user(id: "1") {  name  friends {    name  }}
このクエリの意味は、idが"1"のユーザの名前とその友達の名前を取得するというものです。
このクエリのレスポンスは以下になります(Jsonフォーマット)。
{  "user": {    "name": "User One",    "friends": [      {        "name": "Friend One"      },      {        "name": "Friend Two"      }]  }}
なるほど、直感的な気はします。
クエリとJsonで返ってきたデータが同じ構造となっていますね。

GraphQLはあくまでもクエリ言語であり、特定のストレージやDBの実装ではありません。
これはSQLと同様だと思いますが、GraphQLのような共通のクエリ言語があることで、アプリケーション開発やツール作成などが容易になるというメリットがあります。

詳細に入る前に、なぜFacebookでGraphQLが開発されたのかについて簡単に説明します。

Facebookでは、ソーシャルグラフにアクセスするためにGraph APIというRESTのAPIが用意されています。これはシンプルで良いのですが、複雑なクエリを書くことが難しいという欠点があります。
また、FacebookではFQLと呼ばれるSQL似た文法でソーシャルグラフにアクセスするインターフェースもあります。ただし、これもJoinのようなことをすると複雑で理解しづらいものになってしまいます。
そこで、より直感的で柔軟なクエリを記述することのできるGraphQLが開発されました。

それでは、GraphQLについて、更に詳細に見て行きましょう。

クエリ

まずは、GraphQLのクエリについて説明します。

以下のクエリをご覧ください。
{  me {    name    age  }}
これのレスポンスは以下になります。
{  "me": {    "name": "Toshihiro Suzuki",    "age": 31  }}
meは例えば現在ログインしているユーザになります。
上記クエリは、ログインユーザの名前と年齢を取得するものになります。

以下のようにログインユーザではなく、idを指定して取得するようにすることもできます。
{  user(id: 3) {    name    age  }}
次は少し複雑な例になります。
{  me {    name    age    profilePicture {      width      height      url    }  }}
このクエリは、ログインユーザの名前と年齢と、プロフィール画像の情報を取得するものになります。
結果は以下のようになります。
{  "me": {    "name": "Toshihiro Suzuki",    "age": 31,    "profilePicture": {      "width": 50,      "height": 50,      "url": "https://abc.com/abc.jpg"    }  }}
クエリとレスポンスの構造が一致してるので分かりやすいですね。

次は変数を使ったクエリになります。
{  me {    name    age    profilePicture(size: 300) {      width      height      url    }  }}
profilePictureのsizeに300を指定して取得しています。
レスポンスは以下になります。
{  "me": {    "name": "Toshihiro Suzuki",    "age": 31,    "profilePicture": {      "width": 300,      "height": 300,      "url": "https://abc.com/300.jpg"    }  }}
また、以下のようにprofilePictureを複数取得したい場合も、エイリアスを付けることで可能となっています。
{  me {    name    age    lilPic: profilePicture(size: 50) {      width      height      url    }    bigPic: profilePicture(size: 300) {      width      height      url    }  }}
レスポンスとしては、エイリアスとして付けた名前で返ってきます。
{  "me": {    "name": "Toshihiro Suzuki",    "age": 31,    "lilPic": {      "width": 50,      "height": 50,      "url": "https://abc.com/50.jpg"    },    "bigPic": {      "width": 300,      "height": 300,      "url": "https://abc.com/300.jpg"    }  }}
次は、階層構造を表すクエリの例になります。
{  me {    name    age    friends {      name      age    }  }}
このクエリは、ログインユーザの名前と年齢と、その友達の名前と年齢を取得するものになります。
レスポンスは以下です。
{  "me": {    "name": "Toshihiro Suzuki",    "age": 31,    "friends": [      {        "name": "Ryota Nishio",        "age": 30,      },      {        "name": "Ichiro Fukuda",        "age": 31,      },      {        "name": "Masahiro Yasuda",        "age": 30,      }    ]  }}
このように、SQLではJoinを使う必要があるので多少複雑になってしまうクエリも、GraphQLでは比較的直感的に書くことができます。

最後にfragment機能を紹介します。
fragment機能はクエリの一部をfragmentとして切り出すことができる機能です。
{  me {    name    age    friends {      name      age    }  }}
上記クエリをfragment機能によって以下のようにすることができます。
fragment userFragment on User {  name  age}{  me {    ...userFragment    friends {      ...userFragment    }  }}
このように、name、ageなどの共通部分をfragmentとして切り出すことができます。

これ以外にも機能がたくさんありますので、ご興味のある方は参考文献[1]をご覧ください。

型システム

次にGraphQLの型システムについて説明します。

先程からクエリについて説明してきましたが、
本来GraphQLを使う場合には、まずスキーマを定義する必要があります。

以下が、これまで説明してきたクエリのスキーマになります。
type Query {  me: User  user(id: Int): User}
type User {  name: String  age: Int  profilePicture(size: Int = 50): ProfilePicture  friends: [User]}
type ProfilePicture {  width: Int  height: Int  url: String}
順を追って説明していきます。

まず、Queryは一番上位レベルの型で、先ほどのクエリでmeやuser(id: 3)と指定していた部分に当たります。userはidというint型のパラメータを受け取ります。これらの結果としてはそれぞれUser型が返ります。
次のUserは、名前(name)とプロフィール画像(ProfilePicture)と友達(friends)を持ちます。
それぞれ、String型、ProfilePicture型、User型という定義になっています。
最後にProfilePictureですが、幅(width)、高さ(height)、URL(url)をそれぞれint型、int型、String型で持つ定義となっています。

例えば以下のようなクエリがあったとします。
{  me {    name    age    profilePicture {      width      height      url    }    friends {      name      age    }  }}
meが返すのはUser型です。なので、そこで指定できるのはname, ageとprofilePictureとfriendsのどれかと決まります。
更に同様に、profilePictureはProfilePicture型で、friendsはUserのリスト型なので、指定できるものが決まりますね。
このように、スキーマを定義することで発行できるクエリを定義することができます。

ここで指定した型以外にも、Float型やBoolean型、列挙型やオブジェクト型などを指定することもできます。
更に詳細については参考文献[1]をご覧ください。

実際にGraphQLを動かしてみる

GraphQLはGraphQL.jsというリファレンス実装が用意されており、簡単に試すことが可能となっています。

まずは、npmでGraphQL.jsをインストールします。
$ npm install graphql
今回は、先程のスキーマを少し簡単にした以下のスキーマを定義してみましょう。
type Query {  me: User  user(id: Int): User}
type User {  name: String  friends: [User]}

こちらのソースコードは以下に貼りました。

https://gist.github.com/brfrn169/f8b8e57bb3a79540aace

簡単に解説すると、1~8行目で必要なものをimportしています。

https://gist.github.com/brfrn169/f8b8e57bb3a79540aace#file-graphql_example-js-L1-L8

10~36行目は今回使用するデータとなります。
今回はDBなどは用いず、メモリ上のデータに対してクエリを発行しています。

https://gist.github.com/brfrn169/f8b8e57bb3a79540aace#file-graphql_example-js-L10-L36

38~83行目は、本題のスキーマ定義のコードになります。
Queryのスキーマに対応するのは変数queryTypeに代入している部分で、Userのスキーマに対応するのは変数userTypeに代入している部分です。ポイントはresolveです。ここに指定した関数の中で実際のデータを取得し返しています。

https://gist.github.com/brfrn169/f8b8e57bb3a79540aace#file-graphql_example-js-L38-L83

最後に85~124行目で、クエリを発行しています。
この例では以下の3つのクエリを発行してます。
{  me {    name  }}
{  me {    name    friends {      name    }  }}
{  user(id: "2") {    name    friends {      name    }  }}
その結果として以下のJsonが返ってきます。
{  "me": "Toshihiro Suzuki"} 
{  "me": "Toshihiro Suzuki",  "friends": [    {      "name": "Ichiro Fukuda"    },    {      "name": "Ryota Nishio"    }  ]}
{  "user": "Ichiro Fukuda",  "friends": [    {      "name": "Toshihiro Suzuki"    }  ]}

https://gist.github.com/brfrn169/f8b8e57bb3a79540aace#file-graphql_example-js-L85-L124


イメージとしては、スキーマとそれに対するデータへのマッピングを指定していく感じでしょうか。
今回の例は非常に簡単なものでしたが、比較的理解しやすいのではないかと思います。

また、GraphQLでデータを取得するクエリと、データを操作するクエリを定義できます。
この例では、データを操作するミューテーション系のクエリについては触れませんでした。
ミューテーション系のクエリは以下を参考にすると良いでしょう。

https://github.com/RisingStack/graphql-server/blob/master/src/server/schema.js#L79-L142

まとめ

今回はGraphQLについて調べてみました。
クエリとそのレスポンスのJsonの構造が一致するというのはとても直感的で分かりやすいと思いました。
また、スキーマ定義も比較的直感的に書くことができたので、良いのではないかと思いました。
(今回の例が簡単すぎただけかもしれませんが、、)

今回は触れませんでしたが、GraphQLにはイントロスペクション機能がありスキーマの情報をGraphQLの文法で取得可能です。
こちらを用いることで、クエリのバリデーションやコードジェネレーション、IDEインテグレーションやドキュメントの自動生成などが可能となります。ご興味のある方はこちらも調べてみてはいかがでしょうか。

参考文献

自動購読課金について【iOS編】

$
0
0

はじめに

AWAサーバサイドエンジニアの辻(jun06t)です。

今回はiOSとAndroidの月額課金のための実装について書かせていただきます。
形式として読み物と言うよりドキュメントっぽくなっています。
理由は私が実装しようとした際に実装方法についてまとめて書かれた記事が少なく、「検証時に使えるフィールドはどれだろう?」「昔はこうだったけど、今は違う?」「Androidではできるけど、iOSではできない(逆も然り)」など、色々と分からない部分が多くとても困ったためです。

やや長い記事となったため、iOSの実装を前編、Androidの実装を後編として説明させていただきます。

注意事項

※1:開発中にプラットフォーム側の仕様変更があったなど、記載している内容は情報が古い可能性があります。
※2:記載している動作は十分に調査できていないものも含んでいるため、内容が不正確である可能性があることをご了承ください。

対象環境

目次

  1. Apple公式ドキュメント
  2. iOSでの購読登録処理の流れ
  3. データフォーマット
  4. レシートの検証フロー
  5. 購読期間
  6. 自動更新手順
  7. レシートの復元
  8. 二重購読
  9. 実装していて困ったこと
  10. まとめ
  11. 謝辞

Apple公式ドキュメント

iOSでの購読登録処理の流れ

おおまかに以下の流れになります。
左半分はクライアントサイドで閉じており、右半分はサーバサイドで閉じてます。

ios_flow

以降はサーバ - AppStoreAPI間の検証処理について述べていきます。

iOSのデータフォーマット

RequestURL

AppStoreAPIのエンドポイントにはSandbox用と本番用があります。

それぞれ使うレシートが違うため、間違った方に送信すると後述するエラーコード2100721008が返ります。
Appleの審査中はSandboxレシートを使用するため、本番サーバでは両方共扱える実装になっている必要があります。

例)必ず最初本番にレシートを投げ、21007が返ってきたらSandboxのエンドポイントへ投げ直す。

RequestBody

上記エンドポイントに対して以下のbodyでリクエストします。

{  "receipt-data": "MIIu0QYJKoZIhvcNAQcCoIIuwjCCLr4CAQExCzAJBgUrDgMCGgUAMIIeggYJKoZIhvcNA...",  "password": "hogehoge3ddad5a2f2c06fe47fcdf22e"}


ResponseBody

正しいレシートだと以下の結果が返ってきます。
※iOS7以降のフォーマットです。transaction_id等はダミーです。

{  "status": 0,  "environment": "Sandbox",  "receipt": {    "receipt_type": "ProductionSandbox",    "adam_id": 0,    "app_item_id": 0,    "bundle_id": "your_bundle_id",    "application_version": "1",    "download_id": 0,    "original_application_version": "1.0",    "in_app": [      {        "quantity": "1",        "product_id": "your_product_id",        "transaction_id": "900200162803342",        "original_transaction_id": "4002002162812828",        "is_trial_period": "false",        "app_item_id": "",        "version_external_identifier": "",        "web_order_line_item_id": "3300000022116144",        "purchase_date": "2015-07-09 08:19:17 Etc/GMT",        "purchase_date_ms": "1436429957000",        "purchase_date_pst": "2015-07-09 01:19:17 America/Los_Angeles",        "original_purchase_date": "2015-07-09 08:17:27 Etc/GMT",        "original_purchase_date_ms": "1436429847000",        "original_purchase_date_pst": "2015-07-09 01:17:27 America/Los_Angeles",        "expires_date": "2015-07-09 08:24:17 Etc/GMT",        "expires_date_ms": "1436430257000",        "expires_date_pst": "2015-07-09 01:24:17 America/Los_Angeles",        "cancellation_date": "",        "cancellation_date_ms": "",        "cancellation_date_pst": ""      },      {        "quantity": "1",        "product_id": "your_product_id",        "transaction_id": "4500000152802828",        "original_transaction_id": "4002002162812828",        "is_trial_period": "false",        "app_item_id": "",        "version_external_identifier": "",        "web_order_line_item_id": "3300000022116145",        "purchase_date": "2015-07-09 08:14:17 Etc/GMT",        "purchase_date_ms": "1436429657000",        "purchase_date_pst": "2015-07-09 01:14:17 America/Los_Angeles",        "original_purchase_date": "2015-07-09 08:14:18 Etc/GMT",        "original_purchase_date_ms": "1436429658000",        "original_purchase_date_pst": "2015-07-09 01:14:18 America/Los_Angeles",        "expires_date": "2015-07-09 08:19:17 Etc/GMT",        "expires_date_ms": "1436429957000",        "expires_date_pst": "2015-07-09 01:19:17 America/Los_Angeles",        "cancellation_date": "",        "cancellation_date_ms": "",        "cancellation_date_pst": ""      },    ],    "latest_receipt": "MIIu0QYJKoZIhvcNAQcCoIIuwjCCLr4CAQExCzAJBgUrDgMCGgUAMIIeggYJKoZIhvcNA" // 最新レシートのBase64文字列  }}

重要そうなものだけ説明します。

エラーコード


21006が取り消し線なのは、現在は期限切れでもstatus: 0が返るためです。
なので毎回期限をチェックする必要があります。

レシートの検証フロー

クライアントでの検証はセキュアではないため、基本的にはサーバを経由した検証を推奨します。

receipt_verification

AWAはこの通りではありませんが、一般的なレシート検証の場合、最低限このような検証が必要になります。

iOS購読期間

設定可能な期間

現状では6種類あります。

  • 1週間
  • 1ヶ月
  • 2ヶ月
  • 3ヶ月
  • 6ヶ月
  • 1年

Sandboxの場合

Sandboxでは、時間が早回しで進みます。

Sandbox上の自動更新は6回までで、1ヶ月だと、半年(6回)で自動更新しなくなるので注意してください。
また本番では設定から購読の停止ができますが、Sandboxでは設定が無く停止できないので待つしかないです。

iOSの自動更新手順

iOSはAndroidと違って毎回レシートを送信する必要があります。
以下の流れで購読期限を更新します。

  1. 期限日の24時間前にApp Storeで購読の自動更新を開始
  2. クライアントで更新されたレシートをサーバに送信
  3. サーバからAppleへ送信
  4. レスポンスをサーバで検証し、expires_dateを更新

購読したプロダクトのレシート復元

自動購読を利用する際はレシートによる復元機能が必要になります。ない場合、審査時にリジェクトされます。
ユーザの使用しているAppleIDが同じであれば、どの端末でも同じレシートを再生成することができるため、その再生成したレシートを使って課金履歴と一致するユーザに再ログインさせます。

リストアは以下のメソッドで行います。

[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];

トランザクション結果は、以下のデリゲートメソッドで受け取ります。

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;

レシートを再生成できたら、先ほどのレシート検証フローで「履歴のuserIdと一致する」場合、該当ユーザの情報を返却すれば良いでしょう。

二重購読

現在AWAではlite, standardの二種類の購読プロダクトがあります。lite->standardへのアップグレード(二重購読)も可能です。また二重購読状態でstandardを解約すれば、standardの期限後に自動的にliteにダウングレードします。

リリースするまでこのような二重購読を実装しているアプリはAppStore上で見当たらなかったため、そもそも審査に通るのか不明でした。
※Evernoteなど、有名な購読アプリでのプラン変更はお問い合わせベースで対応だったため。

WWDCでAppleのエンジニアにもヒアリングしてみましたが、彼らも「大丈夫だと思うが、審査チームがOKかは提出してみないとわからない」と言った回答でした。

結論としてはAWAがリリースできているので二重購読はAppleとしてもOKということになります。

二重購読の場合、アップグレードやダウングレードの処理であったり、複数のレシートをチェックする処理などがありやや複雑になります。しかし「今すぐ上位プランに変更したいのに下位プランをキャンセルして期限まで待たないといけない」「今すぐ変えるためには必ずお問い合わせをしなきゃいけない」といったユーザにとって不利益な実装にはしたくなかったため、今回この対応をしました。

iOSで実装していて困ったこと

テストがしにくい

App内課金機能の開発中は、Sandbox環境に接続して課金操作を検証する事になります。
この時に使用するAppleIDは専用に発行するSandboxアカウントになるのですが、Sandboxアカウントは機能が制限されているため本番アカウントであればアクセスが可能な管理/設定画面等にアクセスできません。
そのため、「テストしたいのに出来ない」ケースが度々ありました。

具体的にテストが出来ず困ったのは以下の機能です。

購入の承認機能(ファミリー共有機能の一部)

子供が購入しようとした時、親のAppleIDに対して請求される仕組みがあるのですが、この機能の一部がSandbox環境ではテストできませんでした。
本来は子供のアカウントで購入の承認を求める操作を行うと親のアカウントにプッシュ通知が届くのですが、これが何故か届いてくれません。
(親のアカウントはクレジットカード情報を設定する必要があるために本番アカウントを使用しなければならなかったので、それも関係しているかもしれません。)

子供側の端末に親のアカウント情報を入力して直接承認するケースのみ、テスト可能でした。

自動購読の解約操作

Sandboxアカウントでは購読管理画面にアクセスできず、解約操作が行えません。

TestFlightの仕様が開発途中で変わった

6月頃まではTestFlight環境では本番環境用のAppleIDを利用できる仕様だったのですが、7月頃からSandboxアカウントしか使えなくなりました。
また、同時に購読の自動更新の更新感覚もそれまでの「12時間」から「5分」に変わってしまいました。

仕様変更前はTestFlightで本番アカウントが利用できていたため、テスターは手持ちのiPhoneで普段使いをしながらテスト出来ていたのですが、仕様変更後はTestFlightでの購入操作時にSandboxアカウントのAppleIDにログインしなおす必要が出てきてしまい、日常的に利用しながらのテストが不可能なケースが出てきてしまいました。

レシート周りの挙動がTestFlightとAppStore版のアプリで異なる

TestFlight環境では、購入操作を行うまではレシートが存在しないため「レシートがない=課金操作を行ったことがない」とみなして処理を進めることができました。
しかし、AppStoreからダウンロードしたアプリではインストール直後の時点で既にレシートがローカルに存在するようで、この条件が成り立たなくなってしまいました。
最終的に、上記の条件を前提に設計していたアーキテクチャを見直す必要がありました。

まとめ

iOSの自動購読課金の実装をする上で「実装時に知りたかった」と思っていた情報をまとめてみました。レシートのフィールドはドキュメントにも書いてないフィールドなどがあったりなど、どれが正しいのか分からずとても苦労しました。
今後iOSアプリで自動購読を導入する方にとって少しでも参考になれば幸いです。

謝辞

AWAの課金実装および今回の記事を書くにあたってAWAのiOSエンジニアである岐部さん(@beryu)には非常にお世話になりました。本当にありがとうございます。

自動購読課金について【Android編】

$
0
0

はじめに

AWAサーバサイドエンジニアの辻(jun06t)です。

前回の続きで今回はAndroidの月額課金のための実装について書かせていただきます。
基本的な流れは前回と同じになってます。

注意事項

※1:開発中にプラットフォーム側の仕様変更があったため、記載している内容は情報が古い可能性があります。
※2:記載している動作は十分に調査できていないものも含んでいるため、内容が不正確である可能性があることをご了承ください。

対象環境

目次

  1. Google公式ドキュメント
  2. Androidでの購読登録処理の流れ
  3. 署名の検証
  4. データフォーマット
  5. レシートの検証
  6. 購読期間
  7. 自動更新手順
  8. アップグレードとダウングレード
  9. 実装していて困ったこと
  10. レシート検証用ライブラリの紹介
  11. まとめ
  12. 謝辞

Google公式ドキュメント

Androidでの購読登録処理の流れ

Androidでの流れです。AndroidはGoogleが署名を発行してくれるのでiOSよりもセキュアに検証できます。

android_flow

レシートと書いてありますが、実際は後述するsubscriptionId,tokenというフィールド名で扱われます。
また署名検証をする場合は決済時の全フィールドをサーバ(上図ではAWAサーバ)へ送信してください。

署名の検証

署名を検証することで、クライアントから送信されるレシートが改竄されていないか確認することができます。

SHA1でハッシュ化された署名なので、golangの場合以下のように検証します。
署名の復号に使う公開鍵はGooglePlayDeveloperConsoleで確認できます。

const (        base64EncodedPublicKey = "--- your app's public key ---")func verify(receipt interface{}, signature string) (bool, error) {        // prepare public key        decodedPublicKey, err := base64.StdEncoding.DecodeString(base64EncodedPublicKey)        if err != nil {                return false, fmt.Errorf("failed to decode public key")        }        publicKeyInterface, err := x509.ParsePKIXPublicKey(decodedPublicKey)        if err != nil {                return false, fmt.Errorf("failed to parse public key")        }        publicKey, _ := publicKeyInterface.(*rsa.PublicKey)        // decode signature        decodedSignature, err := base64.StdEncoding.DecodeString(signature)        if err != nil {                return false, fmt.Errorf("failed to decode signature")        }        // generate hash value from receipt        b, err := json.Marshal(receipt)        if err != nil {                return false, fmt.Errorf("failed to JSON marshal")        }        hasher := sha1.New()        hasher.Write(b)        hashedReceipt := hasher.Sum(nil)        // verify        if err := rsa.VerifyPKCS1v15(publicKey, crypto.SHA1, hashedReceipt, decodedSignature); err != nil {                return false, nil        }        return true, nil}

署名検証するレシートのフィールドは以下の通りです。

Androidのデータフォーマット

次はサーバ - GooglePlayAPI間の検証処理について述べていきます。
GooglePlayAPIへは以下のリクエストを投げます。

RequestURL

RequestParameters

ResponseBody

レスポンスは以下の様な情報が返ります。

{  "kind": "androidpublisher#subscriptionPurchase",  "startTimeMillis": 1437567760835,  "expiryTimeMillis": 1445631222776,  "autoRenewing": true}

また失敗時は以下の様なエラーが返ります。

エラーステータス

レシートの検証

iOSと違って前述の署名検証とGoogleへのリクエストが成功していれば正しいレシートです。

ただし別ユーザが不正にその正規レシートを送信した可能性を考慮して、レシートのdeveloperPayloaduserIDを埋め込み、リクエストを送信したユーザのuserIDと一致するかを検証する必要があります。

Androidの購読期間

以下の4種類あります。

  • 1週間
  • 1ヶ月
  • 1年
  • 季節ごと(季節の終わりで停止し、来年の季節が始まると再開)

Androidの自動更新手順

購読時に発行されたtokenはキャンセルするまで変わりません。したがって毎回クライアントからレシートを送る必要はありません。サーバだけで検証できます。

  1. 期限日にGoogle Playが購読の自動更新を開始
  2. 保持しているpurchaseTokenを用い、サーバからGoogleの検証APIを叩く
  3. レスポンスのexpiryTimeMillisを見て購読期限日を更新

iOSと異なり最初に送信されたレシートを使えばいつでも購読状態を確認できるので、クライアントでは特に処理は入れずサーバで1日1回程度チェックすれば良いでしょう。

アップグレードとダウングレード

AndroidではGooglePlayがアップグレード、ダウングレードの機能を提供しています。変更後は変更前の購読状態が自動でキャンセルになります。ですのでこの機能を用いればiOSと異なりユーザが二重購読する状態にはなりません。

ただし実装する上で、以下のように請求金額および購読期間の変化があるため注意が必要です。

Androidで実装していて困ったこと

期限切れの検証期間が長い

テストアカウントだと24時間で期間が切れます。
iOSのSandbox環境と違って短くはならないため、翌日になるまで待つ必要がありました。

アップグレード、ダウングレードがドキュメントにあるが、Androidのライブラリにない

これはどうしようもなかったためAWAのAndroidエンジニアである沖本さんが自作しました。以下のStack Overflowでgistリンクを貼っています。

How to upgrade/downgrade subscriptions in Android InAppBilling?

テストアカウントではダウングレードしても期間が伸びない

先に説明したように、ダウングレード時は先に余分に支払ったお金の分、購読期間が延長されます。
しかしテストアカウントでのダウングレードでは期間は延長されませんでした。

購読キャンセルをしても、autoRenewingの状態がすぐには変わらない

GooglePlayAPIのレスポンスにはautoRenewingという自動購読状態かどうかのフラグがあります。
AndroidのPlayStoreなどからキャンセルした後はこのフラグがfalseに変わりますが、15~30分ほど経つまで変わりませんでした。
ユーザとしてはキャンセルしたはずなのに、GooglePlayAPIから返る値は未だキャンセルされていない、とみなされるため、アプリ内でキャンセル済みか表示する場合は定期的にautoRenewingの状態をチェックする必要があります。

orderIdは保持しておこう

レシートの検証ではorderIdは特に使用しません。しかしながらGooglePlayの課金レポートではorderIdベースで課金情報が登録されるため、ユーザサポートなどで必要になったりします。

レシート検証用ライブラリの紹介

AWAのサーバはgolangで実装されており、golangでのレシート検証用ライブラリが古いものしかなかったためこちらも自作しました。AppStoreAPI、GooglePlayAPIの両方に対応しています。

dogenzaka/go-iap

正規レシートを公開できないためテストコードは不足していますが、現在AWAで使用していますので動作自体は問題ないと思います。プルリク歓迎してます。

まとめ

手探りしながら導入した自動購読の課金処理ですが、色んな問題に直面した分きちんとした実装ができたと思っています。
今後ネイティブアプリで自動購読を導入する方にとって少しでも参考になれば幸いです。

謝辞

AWAでのAndroid課金実装、そしてこの記事を書くにあたって、Androidエンジニアの沖本さん(cre8ivejp)には非常にお世話になりました。本当にありがとうございます。

Flexible Blue Green Deploymentのススメ

$
0
0

どうもこんにちは。@stormcat24です。前回寄稿した記事から1年半ぶりになります。

主な仕事は業務中のTwitterで、その傍らでAmebaFRESH!というサービスを絶賛開発してたりしています(この記事が公開される頃にはリリースしてるかしら?)。何かネイティブやりに意気揚々と異動してきたんですが、いつの間にかサーバサイドエンジニアになってました。まあサーバサイドといっても、自分はかなりWebオペレーション寄りなんですけど。

で、今回はFlexible Blue Green Deploymentの仕組みを作ったよっていうお話です。

そもそもBlue Green Deploymentとは

Blue Green DeploymentとはImmutable Infrastructure(不変なインフラストラクチャ)思想の一貫で、サーバの内容やアプリケーションを更新したい場合に、稼働しているサーバ群を変更するのではなく新規にまるっとサーバ群ごと作りなおして切り替えるという手法です。

そのためにはサーバ群が2系統必要なので2系統をそれぞれBlueとGreenと呼び、それを更新の度にBlueとGreenを切り替えるのでBlue Green Deploymentと呼ばれています。この手法だとロードバランサーを切り替えるだけで稼動系を変更できるので、ゼロダウンタイムリリースのテクニックとしても有用です。リリース後に問題があった場合に旧稼動系に戻すといったことも容易にできるようになります(DB変更がある場合は問題は複雑ですが)。

Immutable Infrastructureを支える技術

かつてサーバを構築する作業というものはそれなりの時間とコストを伴うものでしたが、AWSやGCP等のクラウドプラットフォーム全盛時代である今日では、サーバを作ったり破棄したりという作業がカジュアルにできるようになりました。

Blue Green Deploymentを実現する上においての重要な要素は、このImmutable Infrastructure思想に合致する要素を一つでも多く満たすということに尽きます。
  • インフラはプログラムによって全て構築可能であること
  • インフラの構築時間が短いこと(数分)
  • インフラは自動でスケールアウト・スケールインできること
  • インフラはいつでも破棄されても良いように、消失してはいけないデータを残さないようになっていること
  • アプリケーションはポータビリティ性が高く、かつスケールする仕組みであること
この要素を満たすためにAmebaFRESH!では以下の技術を採用しています。

Terraform

はHashicorp社が開発しているオーケストレーションツールで、インフラの構成を独自のDSLによって定義し、インスタンスの破棄や作成等を行ってくれます。AWSであればCloudFormationでも同様のことができますが、Terraformの方は特定のプロバイダに依存しない仕組みになっています。

Docker

AmebaFRESH!ではDockerをかなり積極活用しています。ってか、むしろFull Dockernizedされています。

Dockerのメリットはそのポータビリティの高さにあります。イメージさえ作ってしまえば、Dockerホスト上に乗せるだけ。コンテナ型仮想化技術によって論理的に独立した空間であるため、ホスト環境に依存した問題が発生しにくく、そして起動が早いというメリットがあります。

これまでは環境を作る上でChefやAnsibleでのProvisioningが効率化の上で必要不可欠なことでした。しかし、Dockerの場合はアプリケーションもミドルウェアもコンテナとなんてポータブルなので、実際のホスト環境にProvisioningを施す必要性があまりありません。そのため、今回はAnsibleは利用せずにcloudinitだけで対応しています。WebサーバやGoで書かれたアプリケーションサーバ、バッチサーバや各種エージェント等諸々全てがDockerコンテナとして稼働しています。

EC2 Container Service(ECS)

ECSはEC2のインスタンス群をDockerのクラスタにしてしまおうというサービスです。ECS上のEC2ではecs-agentというECSクラスタ上でコンテナやリソースを監視するエージェント(実はこれもDockerコンテナ)が稼働しており、クラスタ内のどのインスタンスにコンテナを割り当てるか?等の制御を行います。簡単に言うとDockerのスケジューラーです。

td-agent(Fluentd)

サーバに残ってしまうものの代表格で、かつ消失が許されないものといえばログです。保持しておくべきログはtd-agentによって然る場所に転送されます。このtd-agentもDockerコンテナとして稼働させます。転送したいログはDockerホストに各コンテナからマウントされたものをtd-agentコンテナから任意の場所に転送します。

ちなみにDokcer1.8ではFluentd Logging Driverがサポートされました。この機能を利用すればtd-agentコンテナを立てることなく、任意のコンテナから直接ログを転送することが可能です。

Ameba FRESH!のBlue Green Deployment

AmebaFRESH!でのBlue Green Deploymentの構成は以下のようになっています。これはわかりやすくした図ですが、実際は複数のMicroservicesで構成されておりこれのセットがPublic/Internal問わずいくつか存在しています。

AutoScaling Group + Lambda

AmebaFRESH!ではAWSを利用しているので、AutoScaling Groupによってインスタンスの数を容易に変更することができます。ただ、負荷が高騰し、AutoScalingでのインスタンス増加が発動してもECSクラスタ上のタスクの数までは変わりません。インスタンスの数とともにタスクの数も一緒にスケールさせてあげないといけません。

そこでECSのタスクの数をコントロールするためにLambdaを利用しています。LambdaはNodeやJavaで書かれたジョブを、稼働させた分だけしか料金がかからないサービスで、常にEC2を稼働させて同じようなことをさせるよりも効率的です。AutoScalingでの増減が発生したら、LambdaでEC2のDesiredCount(稼働させたいECSタスクの数)も変更してあげましょう。 

Elastic Load Balancing(ELB)

AWSなのでロードバランサーにはELBを利用しています。ELBはAutoScaling Group単位での付け替えが可能なので、スケールアップ・スケールインしやすいBlue Green Deployment構成を実現することができます。

ecs-formation

今回はECSのDockerクラスタやコンテナ構成を定義して管理するためにecs-formationというツールを書きました。

docker-compose互換のYAMLファイルでECSのTask Definitionsを定義し、Task Definitionsの反映やECS Serviceの更新、ECSクラスタ単位でのBlue Green Deploymentをサポートしています。

旧稼動系を柔軟に縮退させる

Blue Green Deploymentはとても旨味のある仕組みですが、2系統のサーバ群が必要になるので単純にやるとコストが2倍になります。そこで今回はAutoScaling Groupを利用することでその旨味を活かしながらも、コスト面にも気を配った構成になっています。これをFlexible Blue Green Deploymentと勝手に呼んでいます。

Blue Green Deploymentでは新しい稼動系がリリース後安定的に稼働していてロールバックの必要が無いようであれば、旧稼動系をずっと置いておく必要はありません。AutoScaling Groupであれば負荷がないので勝手にスケールインしていきますが、ゼロにしちゃってもいいよってケースもあるのでそこは柔軟に制御できるようにしてます。 

ちなみに以下のようにカジュアルにやってます。ウチはChatOps推進なので、Jenkinsでポチポチなんてやりません。以下のように指示すると・・・


こんな感じでbotがAutoScalingのMaxSizeを調整してくれます。(ちなみにkirikoというのはウチのチームのBotです)

逆に新しいアプリケーションに更新する場合は、次に新系統となるクラスタをあらかじめウォームアップしておくこともできます。

旧稼働系の考慮すべきこと

Blue Green Deploy後に旧稼働系となったクラスタですが、そのまま放置しているとシステムに思わぬ副作用を及ぼすこともあります。例えば、以下のような考慮が必要でしょうか。
  • 他のサーバへの不必要な通信を止める
  • ジョブキューへのロングポーリングを止める(旧稼働系にメッセージを吸われるので)
Blue Green構成を構築する際の重要なチェックポイントになると思いますので、十分に副作用の可能性を検討しておきましょう。

まとめ

Blue Greenをやってみた感想ですが、やはりデプロイへの安心感が全然違います。Blue Green Deploymentは富豪的な印象があるかと思いますが、Immutable Infrastructureを実践すれば十分コストは抑えることが可能です。今後も柔軟な運用を目指しつつも、カジュアルにコストを抑えた運用を目指していきたいと思います。

ママエンジニアのワークライフ

$
0
0

こんにちは。現在フロントエンドエンジニアへ転向中の神谷(@fuzzy31u)です。 このブログに登場するのは2回目。前回執筆時はAndroid開発をやっていたんですねー。

…あれから3年。 大学院修士課程修了、結婚、出産、産休/育休と怒涛の日々を経て、現在はAWA株式会社でサーバでもフロントでもjsを書く毎日を送っています。

そんな育休明け半年の私が再びエンジニアブログを執筆することになりましたので、今回はママエンジニアとしてどういったワークライフを送っているのかをテーマに筆を執らせていただきます。

ワークスタイル

リモートワーク

AWAでのワークスタイルはとても柔軟です。
子どもが風邪で保育園をお休みしないといけない時や、予防接種などで小一時間抜けなければならない時には在宅勤務が可能です。


こちらは夕会風景です。

Slackで/roomと打つだけでビデオミーティングが開始できるRoom/hangoutGoogle Hangoutで行います。

もともと福岡に開発陣がいることもあり、AWAでは席にいても基本Slackで会話をする文化が定着しています。
場所を問わず働けることはママエンジニアとしては大きなアドバンテージではないでしょうか。

TDD(定時-Driven-Development)

最も産前と変わったことはこれ。
いわゆる定時ダッシュを基本とし、日々19時には一区切りつけることを意識して開発をしています。
"19時以降は作業できない”ので業務中はかなりの集中力を必要とします。基本的には精神とテクの部屋に篭り、メールやチャットも連絡事項以外は見ていません。
これはママにもエンジニアにも限った話ではないですが、定時駆動開発はとても健全で仕事のパフォーマンスも上がり、良いサイクルを実現できています。

メールやチャットは通勤中

前述の通り、コアタイムは開発にコミットしているので、メールチェックや実業務に関係するチャネル以外は業務時間外に回します。 それゆえ業務中に溜まったSlackのタイムラインを追いかけながら帰宅するのが日課です。

キャリアチェンジについて

復帰にあたって心配なことが一つありました。サーバサイドエンジニアとしてサービスを運用をしていく以上、休日夜間問わず、緊急対応はつきものです。仕事と子育てを両立する上で、子どもが高熱の時に対応もできず、自分の首を締めるようなことだけは避けたいと思っていました。

またもともと目に見える画面の開発をしたいという想いは入社当初からあったこともあり、復帰のタイミングでフロントエンドエンジニアへ転身しました。

もちろんフロントエンド開発に緊急対応がないわけではないですが、バックエンドのそれと比べ致命的なシーンは少ないです。

このようにライフステージに応じてキャリアチェンジを行うことで、環境を変えていくこともママには必要だと考えています。

仕事内容について

そんな私がAWAで携わっているのは「レーベル様向けダッシュボード」の開発です。

AWAというと対ユーザ向けアプリのイメージが強いですが、その裏には実際に楽曲を提供してくれているレーベルさんたちがいてサービスが成り立っています。
このツールは再生数や視聴者数、再生数ランキングの統計や速報値をグラフィカルにレーベル様へフィードバックすることで、楽曲提供の側面からもAWAに価値を見出してもらうことを目指しています。

こちらは簡単なシステム構成要素です。本稿では深くは触れませんが、Google BigQueryから大量のログデータを取得し最終的にグラフとして表示するので、ここの処理をいかに最適化するかがアプリケーションのパフォーマンスの肝となります。

AWAチームはユーザ向けプロダクトに携わっているメンバーがほとんどなので、1人異色な開発を行っていると言えます。
しかし初めての技術領域にも関わらず、フロントからインフラ(オーケストレーションツールによるEC2インスタンス、AMIの構築、ミドルウェアの設定変更など)まで触ることができる上に、主席エンジニアの名村に直接レビューをしてもらえるというありがたい環境ですので、惜しみなくスキルアップに精を出しています。

ライフスタイル

リフレッシュの時間を意識的に設ける

例えばランチは基本的に外で美味しいものを食べるようにしています。
朝から子どもを追いかけ回して保育園へ送った後、20分かけて通勤、午前の開発と、走り続けてやっと訪れる休息なのでランチの時間は重要です。授乳中のため家ではあまり飲めない濃い目のコーヒーを必ず飲み、リフレッシュの時間を意識的に設けています。
また月に1,2回は飲み会にも参加し、大好きなお酒も嗜んでチャージします。
充実したワークライフを送るためにはメリーとハリーが重要です。

家では子どもとの時間を大事にする

至極当たり前のような話ですが。 
仕事を定時で切り上げたとしても平日夜に子どもと過ごせる時間は3,4時間。 (一緒に過ごすというよりはお風呂や寝かしつけによる戦争ですが…)
時間はどうしても短くなってしまう分、家では極力スマホをいじらず一緒に過ごす時間の濃さに重きをおくようにしています。
時間は有限ですのでチェックするSNSの数も絞りました。

まとめ

ポイントとしてはこんな感じでしょうか。

  • 自分の首を締めるような働き方はしない
  • 子どもと接する時は子どもとの時間に集中し、濃密な時間を過ごす
  • ワーク/ライフだけでなく自分の時間も大切にする

フルタイムで仕事を続けつつ子育ても楽しむためには多少はわがまま言ってもいいと思います。 そしてライフステージにあわせて自らの手で環境を変えていくことも、仕事と子育てを両立する上では重要です。

あんまり気負わず、ちゃんと睡眠時間も確保し、仕事でも子育てでも最高のパフォーマンスを出すことが充実したワークライフを送る上では一番大事。そう私は考えています。
柔軟なワークスタイルを選択できるエンジニアは、子育てしながらでも仕事を続けやすい職業のひとつなのではないでしょうか。

AWS re:Invent2015参加レポ

$
0
0

技術本部の須藤(@strsk)です。前回から約1年ぶりの投稿です。
部署名は変わりましたが、相変わらずAmebaのソーシャルゲーム全般のインフラとプラスでピグも担当しています。いろんな理由でコラ画像を作る機会は減ってきました…。

さて、もう既に1ヶ月が経とうとしていますが、AWSが毎年ラスベガスで開催しているカンファレンス、re:Invent2015に参加してきたのでそのレポートになります。社内勉強会でも発表していてスライドはアップしたんですが、残念ながらアメブロにはembedできないのでリンクだけ貼っておきます。技術系のブログを書くには辛い仕様ですね!

re:Invent2015参加レポ // Speaker Deck

今回の記事では印象に残っているセッションについて詳細を記しておきます。(※英語の解釈に間違いがあるかもしれません(・_・;))

基調講演


Keynote/基調講演(YouTube)

スピーカーは上級副社長アンディー・ジャシー氏。"Freedom"をテーマに、クラウドがもたらす7つの自由(アドバンテージ)について語りながら新サービスを発表します。参加者は1万9000人?だったらしく、横浜アリーナぐらいの大きさのホールで行われる演説はなかなか見応えがありました。とはいえ同時通訳のトランシーバーに集中していて、本人の声とかほとんど聞いてないですが…。
新サービスについては既に発表されているので割愛しますが、ひとつ選ぶとすればAWS Database Migration Serviceが気になっています。

Netflixのセッション


セッションは企業の事例を中心に回っていたんですが、Netflixのセッションがとても印象的でした。部屋も毎回大きく、世界的にも注目度が高い企業の1つだと思います。
オペレーショナル・エクセレンスという考え方を初めて知ったんですが、Netflixとしてのゴールを達成するための開発側の指針も一貫性があって、自分たちのインフラを考える上でのフレームワークとして参考にしたいなと考えているところです。

Engineering Netflix Global Operations In The Cloud/
クラウドでのエンジニアリング Netflix グローバルオペレーション
(YouTube/SlideShare)
  • 会員6500万人
  • マルチAZ、マルチリージョンのアーキテクチャ(欧米3リージョン)
  • 運用上の課題
    • 成長しつづける規模の中での品質維持と改善
    • 可用性と開発速度のトレードオフ
  • Operational Excellence
    • 課題を解決するために目指しているもの
    • 競争優位性になるほどオペレーションが洗練されている状態
    • 品質と開発速度のトレードオフの差を小さくする(変化率のカーブをシフトする)
  • Operation Engineering
    • オペレーショナル・エクセレンスであるためのエンジニアリングの文化
  • Spinnaker
    • Netflix製クラウドマネジメントツール、自動化のプラットフォーム
    • リージョンをまたいだクラウドの管理ができる
  • Stash, Gradle, Ubuntu, Jenkins, Spinnaker
  • 洞察とリアルタイム解析
    • O(bserve)O(rient)D(ecide)A(ct) loop
    • 時系列データ(Observe)を4つのアルゴリズムで解析(Orient)、投票し(Decide)アクションを決める(Act)
    • これらを自動化することでリカバリまで6分~8分かかっていたものが30秒で完了
  • Kepler
    • Netflix製のマシンラーニングで例外を検知するシステム
      • density-based clusteringアルゴリズムを使っている
    • Eメールやページで通知、OOS、デタッチ、teminateまで実行可能
  • カオスエンジニアリング
    • 様々な障害に耐えるためのシステムを構築するための実験の規律
    • Xenの脆弱性対応で200台中20台のCassandraが再起動失敗したときもリカバリまで自動化していたため問題なかった
  • Flux
    • Netflix製トラフィック可視化ツール
    • 3リージョンへのリクエスト状態を見ることができる
    • リージョン障害のリカバリを1分程度で実行できる(シミュレーション時)
  • レバレッジを効かせるために
    • 運用ツールをプロダクトとして作る
    • モジュラーコンポーネントとして開発し、統合する

How Netflix Handles Up To 8 Million Events Per Second/
Netflixのキーストーン:Netflixが1秒あたり最大800万イベントのデータストリームを処理する方法
(YouTube/SlideShare)
  • Netflixが解析している"数値"
    • 5,500億イベント/日
    • 8,500万イベント+21GB/秒(ピーク時)
    • 1PB増加/日
    • 100以上のイベントの種類
  • アーキテクチャ
    • 以前はChkuwaで収集しEMRで解析
    • 現在はさらにKeystoneというシステムを構築
  • Keystone
    • ジョブマネージャのControl Planeと解析するData Planeで構成
    • Kafkaクラスターは優先度(中・高)で分離
    • Control PlaneのSamzaが各解析ツールへルーティング
      • Amazon S3、Elasticsearch、Kafka
    • リアルタイム処理にSpark Streaming
      • 映画の再生情報やABテストの解析など
    • Auditor、Winston、KaffeeでKeystoneをモニタリング
  • 今後やること
    • イベントディスカバリと可視化
    • Auditor/Kaffeeのオープンソース化

The Life of a Netflix Engineer Using 37% of the Internet/
インターネットの37%を使用するNetflixエンジニアの1日
(YouTube/SlideShare)
  • COREチーム(Critical Operations and Response Engineering Team)所属のオペレーションエンジニア
  • COREチームのゴール
    • カスタマー・エクスペリエンスを守る
    • ユニークな失敗
      • イノベーションに失敗は付き物
    • コンスタントな改善
  • Netflixについて
    • 顧客の喜びと真実の瞬間の獲得
    • 2009年にクラウドへの移行を開始し2015年に完了
    • 欧米3リージョンに展開
    • 100個のマイクロサービス
    • 1,000回/日の本番環境への変更
    • 10,000台のインスタンス
    • 100,000回/分の顧客とのやりとり
    • 1,000,000人の顧客
    • 1,000,000,000個のメトリクス
    • 10,000,000,000時間のストリーミング
    • 10人のオペレーションエンジニア(No NOC)
  • どうやって実現しているか?
    • DevOpsの文化
      • コードやデプロイへのオーナーシップ
      • 24x7の対応
      • インシデントのレビュー
      • 正直でオープンなフィードバック
    • オーナーシップを楽に
      • サービスディスカバリ
      • ツール同士の連携
      • 継続的デプロイ
      • 永続的なデータ
    • 洞察
      • メトリクスや運用の洞察
    • クラウドとして考える
      • データセンターでの考えは使わない
    • 驚きをなくす
      • ステートレスなアプリケーション
      • データの冗長性
      • 障害の投入
        • Chaos Monkey
        • Chaos Kong
  • クラウドが保証すること
    • インスタンスは死ぬ
    • リソースは共有する
    • アーキテクチャは変わる
    • もう光(ランプ)を見ることはない
  • Make things better

その他


Turbine: A Microservice Approach to 3 Billion Game Requests/
Turbine:1日あたり30億のゲームリクエストに対するマイクロサービスのアプローチ
(YouTube/SlideShare)
  • コンシューマゲーム(WBG)はモノリシック
  • モバイルゲーム(MG)はマイクロサービス
  • 複数のゲームをAWSでどう管理するか
    • ゲームごとにアカウントを1つ
    • 環境ごとに1VPC
    • コアサービス以外の環境とは接続しない
  • メトリクスはstatsD->Librato
  • アプリケーションレイヤーのスケールポイントが多い(WBG)
    • シングルインスタンスにまとめてスケールさせる→SLICEと呼んでいる
    • リソース効率は悪くなるが構成シンプルになって運用しやすい
  • イベントデータの収集はKafka
    • r3.xlarge,10TB GP2のbroker6台で25万メッセージ/秒を処理
  • データストアに利用しているMongoDBのスケール問題
    • バージョンは2.6.9
    • r3.2xlarge,2TB GP2,3AZ構成
    • データが大きすぎて既存のバックアップが使えない
    • バグFIXやパッチを当てて解決
  • MongoDBのスケールの歴史
    • write lock問題
      • 読み込み時にスパイクする
      • Linux kernelの更新とシャードを倍にすることで解決解決(12shard->24shard)
    • プロセスストールによるフェイルオーバー
    • CPUのsystemがスパイクしてmongodがストール
    • RAMのサイズが大きすぎてLinuxのメモリコンパクションに時間がかかるのが原因
    • インスタンスサイズを下げて解決
  • 選択的な性能劣化
    • キャッシング
      • 2つのエンドポイントをキャッシングしたことによりアプリレイヤーの50%のネットワークスループットを抑制
    • 絞り
      • 読み込みを優先するために書き込み数を制御
      • システム影響はあるが顧客への影響が少ないリクエストをブロック
      • 絞りはさまざまな問題を引き起こす
  • 今後やること
    • さらなるマイクロサービス化
    • immutablilityを取り入れる
    • さらなるチームを越えた協力
    • さらなるAmazonサポート

最後に


初めて海外のカンファレンスに参加しましたが、わかりやすく技術力と英語力の欲望を掻き立てられて帰ってきました。弊社でもクラウド化は進んでいるものの、まだ物理の考え方が抜け切れていない部分もあり課題だと思っていたタイミングだったため凄く刺激になりました。
カジノで負けた額が僕を育ててくれるのだと信じて引き続き精進していきたいと思います。

AWS re:Invent2015参加レポ(2)

$
0
0

re:Invent2015


Ameba統括本部CTOなICHIROです.
数年どころじゃなくて5年ぶりくらいに,このブログでのエントリを書いています.
もともと秋葉原ラボでHadoop回りをやっていたりするので,いわゆるBigData関連のセッションと動画が好きなので動画関連のセッション中心に書いていこうかなと思います.

BigData関連
1日目のKeynoteではQuickSightというブラウザベースのBIツールが紹介されました.
データの置き場としてはS3とRedshiftあたりが想定されているようです.
今までRedshiftはあるものの,簡便に分析やダッシュボード共有ができないという点がありましたが,それを解決する一手法になりそうです.
データの投入もKinesis Firehoseの登場で容易になりそうです.

また,既に大量のデータを持っていることを想定してSnowballも登場しました.
セキュリティの確保されたデバイスで,宅配業者を使ってデータを輸送するという,なんとも功利的な手法です.
たしかに,大量データをどうやって転送するかという話題では,「UPSで送ればいいんだよ」という回答は目にしたことがありますが,実際にサービスとして提供してくるとは驚きです.

2日目のKeynoteではAmazon Kinesis Analyticsが紹介され,ストリームデータを処理する方法の幅と簡便さが広がりそうです.
さらにLambdaなどと組み合わせて,いわゆるIoT分野での活用も意図しているようです.
また,X1インスタンスという非常にハイスペックなインスタンスも登場し,分析用途などインメモリデータベースで力技での解決ということもできそうです.

KeynoteからもBigData,IoT分野での活用を推し進めるためのサービスを一気に揃えてきたなという印象でした.
Keynote動画
https://www.youtube.com/watch?v=D5-ifl7KJ00(1日目)
https://www.youtube.com/watch?v=y-0Wf2Zyi5Q(2日目)


ブレークアウトセッションでもAWSを活用したBigData関連のセッションが多くありました.

Netflixの事例では特に顕著でしたが,データはS3に集約するという事例が多くありました.
そこにHadoop(もしくはEMR),SparkやPrestoといったミドルウェア,フレームワークを使ってデータ分析につなげるという形です.
また,Kinesisを使いストリームデータ処理を実現する事例も増えてきている印象でした.
ただ,個人的にはHadoopを使っているとS3にデータを置いておくのは,データローカリティの観点からあまり効率的ではない印象があります.
これもSparkなどを使うとあまり影響しないとかいうこともあるのかもしれませんね.
AmebaでもAWS上でのHBaseやSparkクラスタという事例はありますので,そのあたりは幅広い観点で見ていかないといけない時期になっているのかもしれません.

BDT317 - Building a Data Lake on AWS
http://www.slideshare.net/AmazonWebServices/bdt317-building-a-data-lake-on-aws
BDT303 - Running Spark and Presto on the Netflix Big Data Platform
http://www.slideshare.net/AmazonWebServices/bdt303-running-spark-and-presto-on-the-netflix-big-data-platform
BDT310 - Big Data Architectural Patterns and Best Practices on AWS
http://www.slideshare.net/AmazonWebServices/bdt310-big-data-architectural-patterns-and-best-practices-on-aws
BDT403 - Best Practices for Building Real-time Streaming Applications with Amazon Kinesis
https://www.youtube.com/watch?v=JFfvD2cw2IE

動画関連
Amazon Videoの事例ではユーザ側のエラー率やリバッファリング率をきっちり見ていくことから始めて,CDNの最適化を行っていくという話がありました.
VODサービスでは不人気の動画がキャッシュに乗らないため,一般的なCDNではエラー率やリバッファリング率が高くなるとのことでしたが,CloudFrontでは先読みなどを効果的に使い効率よく配信できるようになったそうです.
また主要なISPとのDirect Peeringも行っているようですし(CDNとしては普通なことな気もしますが),エッジに大きいオブジェクトが置けるような状態になっているようなので,VODサービスでのCloudFront活用も検討できそうですね.

動画変換処理についてはECSの活用が有効そうでした.EFSを経由して,ECSにファイルを渡すのが良いという話だったような気がします.
動画変換はコンテナなど柔軟に可変させられるインスタンスの活用として分かりやすく典型的な例でしょう.
動画サービスが広がりを見せる中,ますますの活用事例が増えることでしょう.

同時視聴数制限などでLambdaやDynamoDBを利用する例もあり,AWSを使った動画サービスの展開は非常にやりやすい環境になってきているという印象でした.

SPOT209 - Raising the Bar on Video Streaming Quality Using AWS: Amazon Video Case Study
http://www.slideshare.net/AmazonWebServices/spot209-raising-the-bar-on-video-streaming-quality-using-aws
CMP405 - Containerizing Video: Creating the Next Generation Video Transcoding Pipeline
http://www.slideshare.net/AmazonWebServices/cmp405-containerizing-video-the-next-gen-video-transcoding-pipeline
ARC303 - Pure Play Video OTT: A Microservices Architecture in the Cloud
http://www.slideshare.net/AmazonWebServices/arc303-pure-play-video-ott-a-microservices-architecture

全体的なところ
オンプレからの移行促進,IoT,モバイル,セキュリティというところが大きな発表のあったところになるかと思います.
かなり機能が充実してきていて,「それAWSでできるよ」と言えるところばかりになってきています.
ただ,移行促進材料は出てきており,よりAWSを使ってサービス提供がしやすくなったとはいえ,Amebaサービスは長く運用しているサービスもあり,経済性などを考えて動かないといけない部分もあるかと思います.
また,パブリック・クラウド隆盛の時代ではありますが,テーゼがあればアンチテーゼもあり,どちらもバランスよく検討はしないといけないとも思います.

パブリック・クラウド活用機会が増えるのは必然的なことですが,だからと言って全てを鵜呑みにして動くことはできません.眉に唾をつけて聞く必要があります.
新サービスを中心にAWSに乗るものが増えてきていますし,この流れでAWSにオールインという賭けも選択肢として出てくるのかもしれませんし,別の何かが出てくるのかもしれません.
今後も注目していかなければならない領域であることは間違いありませんね.

ただ,いずれにしても技術的に貢献すべきところはしていきますし,そもそもサービスとしてきちんとしたものを提供していくことが大前提になっていきますので,そこを見失わないよう気をつけつつ取り組んで行こうと思います.

【番外編】
開催地がラスベガスということでカジノに初挑戦したわけですが,ブラックジャック(ディーラーのいないVideo Blackjack)はダラダラとやってられますが勝てないですね.
そこそこ負けていて,まぁこんなもんかと思っていたところで,ホテルをチェックアウトした帰り際にルーレットにストレートで賭けたら当たってしまって,慌てて換金するという展開に.

ATM的な機械でカジノチケットを換金するのですが,換金した100ドル札の1枚がちょっと破れていて,帰国してからの両替で面倒なことに.両替所では両替できず,銀行の支店に行って,鑑別機に通してもらってやっと両替できました.

AWS re:Invent2015参加レポ(3)

$
0
0

サーバーサイドエンジニアの田中です。ずっとソーシャルゲームやってましたが最近動画系に異動になりました。

re:Invent2015に参加してきましたが、自分が参加したセッションの中ではAPI GateWay / LambdaといったAWSサービスを使ったマイクロサービス、サーバーレスに関するセッションが多かったかなと思いますので、そのあたりをピックアップして書いていきたいと思います。

ちょうどAPI Gatewayの東京リージョンでの利用開始やLambdaの新機能発表もこのタイミングであり、Scheduled Eventなど嬉しい機能もあって、おお!と思ったのを覚えています。

参加セッション



The Serverless Company Using AWS Lambda / AWS Lambdaを使用しているサーバーのない企業(YouTube/SlideShare)

  • インスタンス -> コンテナ -> サーバーレスへの流れ
    • アプリケーションコード以外は気にしたくない

  • AWS Lambda
    • イベントドリブンでサーバーインスタンス不要
    • スケールはAWSが自動で行う
    • イベントによる従量課金(実行されない間は課金されない)

  • データプロセスアーキテクチャ
    • with Servers
      • データ・ソース(S3, Dynamo, SNS,,,)の変更を監視
      • 変更をキャッチしworkerに処理させるためにキューイング
      • wokerが後続処理を実行(アプリケーションコード部分)
      • その他、Load Balance、CrossAZ、AutoScaleなどの考慮も必要

    • without Servers
      • アプリケーションコードのみ(Lambda)
      • データソースのListening/polling、キューイング、Load Balance、AutoScaleなどはLambdaが実施

  • PlayOn!による事例
    • 高校スポーツをストリーミング配信するサービス
    • EC2(Wowza)など多数のAWSサービスをベースにしたアーキテクチャを、Lambdaを中心とするアーキテクチャに変更
    • 異なる解像度のTrancecode処理、サムネイル作成、QOS解析などをそれぞれ行うLambda Functionをカスケードさせて使用している
      • 新しい機能が必要になったら新たなLambda Functionをカスケードに追加するだけ

  • リアルタイムデータプロセッシング アーキテクチャパターン例
    • File Processing Workflow
      • S3 -> Lambda -> S3/DynamoDB
      • S3へのファイルアップロードをトリガーとし、加工をしてS3にファイルを戻したりDynamoDBにデータを保存など

    • Stream Processing Workflow
      • Kinesis -> Lambda -> Redshift / SNS

    • DB Triggers Workflow
      • DynamoDB -> Lambda -> DynamoDB / Redshift
      • Dynamoへのデータ更新をトリガーに分析用にRedshiftに流すなど

    • CRUD Backend Workflow (API Gataway)
      • API Gateway -> Lambda -> S3 / DynamoDB

    • その他のトリガー
      • Echo Skills
      • Lambda Scheduled Events
      • IoT Actions
      • Cognito Sync Triggers
      • CloudFormation Custom Resources
      • SES Actions
      • SWF Tasks


Using Amazon API Gateway with AWS Lambda to Build Secure and Scalable APIs / Amazon API GatewayとAWS Lambdaを使ったセキュアでスケーラブルなAPIの構築(YouTube/SlideShare)

  • Key takeaways
    • API Gateway + Lambda でのフルマネージド構成。スケールも自動
    • IAMによるアクセス制御
    • SwaggerによるAPI定義サポート(Swagger Importer)

  • AWS サービスの活用例
    • Lambda: ビジネスロジックの実行
    • Cognito: temporary AWS credentials発行による認証
    • DynamoDB: データストア

  • pet store アーキテクチャ(sample)
    • Cognitoを利用したログインAPI
    • IAM roleによるアクセス制御


From Monolithic to Microservices: Evolving Architecture Patterns in the Cloud / モノシリックからマイクロサービスへ:クラウドで進化するアーキテクチャ(YouTube/SlideShare)

  • GILT(ファッション系のECサービスみたいです)のアーキテクチャ変遷
    • 初期(2007年)
      • Rails/Postgres/memcached/job worker
    • 2011年
      • モノリシックなJavaアプリケーションの投入
      • ビジネスラインごとのチーム構成
    • 2015年
      • Play/Scalaによるマイクロサービス化
      • 約156のマイクロサービス

  • 1サービス当たりの構成
    • container(docker)
    • JSON/HTTP endpoint
    • フレームワーク,、モニタリング、ロギング
    • アプリケーションコード
    • データストア

  • サービス間連携
    • ZooKeeperでのendpoint lookup
    • ELB -> 利用サービスへのRESTfull call

  • 組織構成
    • モノリシック
      • UI / App / DBA など技術面でのチーム構成

    • マイクロサービス
      • ビジネスごとのチーム構成(チームごとにUI / APP / DBA)
      • 技術選定、開発、品質、デプロイ、サポート

  • サービス利用者/提供者の考慮点
    • サービス利用者
      • エラー制御
      • 適切なリトライ処理などで、提供者側に負荷をかけない
      • キャッシング

    • サービス提供者
      • メトリクス送信
      • 実装を意識させない
      • 後方互換

    • API Gatewayの活用
      • スロットリング(トラフィック制御)
      • キャッシング
      • モニタリング
      • バージョニング
      • アクセス制御

  • データマネジメント
    • DBはサービス単位(共用しない)
      • どのdata storeを使うかの選定もサービス単位
      • スキーマ変更の影響も少ない

    • トランザクション管理
      • pessimistic model
        • 利用者側での制御
        • トランザクションマネージャ活用
        • そもそもトランザクション管理が必要にならないような設計

      • optimistic model
        • 結果整合性の許容
        • 冪等性担保の上でのリトライ


最後に


マイクロサービス化に向けて、サービス分割の粒度であったりデプロイ/テストなどの運用方法、管理方法などなど検討する部分も多く、ノウハウをためていく必要はあると思います。 いきなりの既存サービスの置き換えはハードルが高いかもしれませんが、新規サービスなどで検証込みで小さく初めていくにあたり、JAWSなどのフレームワークも出始めていることもあり、API Gateway / Lambdaの活用は十分に検討する価値があるのではないかと感じました。 LambdaがVPCサポート(今年後半利用可能予定のようです)すれば更に活用方法は広がるのではないでしょうか。

初の海外カンファレンス参加で英語力の低さに愕然としましたが、現地での熱的なものも感じられベタにモチベーション上がって帰ってきました。

おまけ


ラスベガスから帰ると、だいたい「(カジノの結果は)どうでした!?」みたいに聞かれます。個人的にカジノはそんなに興味なかったのであまりやってないと答えると、「あー...(つまんねー奴だなぁ)」、「そうなんだ...(空気読めよなぁ)」、「なるほどですね~(この田舎者が)」みたいな空気になりました。

次行く機会があれば、嘘でも「いやー、ボロ負けして飯も食えないっすわー wwww」って答えようと思います。何かのご参考になれば幸いです。

女だらけのエンジニアLT大会レポート

$
0
0

こんにちはマリオ pnskです。前回から1年ちょっぴり経ったエントリー。

先日、CaFeLaTeでLT大会をやってきたので、レポートですダッシュ

CaFeLaTeとは
サイバーエージェントグループ全体の有志の女性エンジニアたちが、「ゆるく楽しく」をモットーに、そのとき楽しそうと思った事をやるグループです。

名前の由来は、個人的にカフェラテと元素記号が好きだったので・・もごもごGためいき
スペル間違えてるのか?と言われたりするけど、わざとです。。

ロゴは、Amebaのデザイナーさんが作ってくれました。
「頭の双葉の部分は、何か素敵なものが生まれますように♪という意味がこもっています。」とのこと。素敵ですキラキラ




そんなこんなで、色々集まってきたのですが、今回はLT大会をやりたい衝動にかられ、みんなでLT大会をしてきました。

↓今回のLTのタイトル画像を優しいデザイナーさんがまたしても作ってくれました


LT大会のタイトルをbeshari(べしゃり)と勝手につけてたんですけど、関西人にしか通用しないのかなんなのか、「べしゃりってなんですか??」と聞かれてしまいました。ローカルな言葉だったんですかね。。


さてはて。

テーマは自由で発表を募集したところ、本当にとても自由で楽しい発表をきくことができました(`・ω・´)
※社外秘多めのためざっくり内容

LOVEAmebaのエンジニアと開発体制の歴史
LOVESlack活用術
LOVEポケモンとセキュリティーの脆弱制診断やインフラのお話
LOVEアドテクのシステムのお話
LOVE全社システムの成り立ちやサポート体制について
LOVEアドテクのデータ分析のお話
LOVEフィジカルコンピューティングのお話
LOVEAmeba画像基盤の中身の話
LOVEリーン開発のお話
LOVEウエディング業界のIT系あるある
LOVE海外ソフトウェアライセンスの交渉術
LOVEウエディングサイトのアクセスビッグウェーブをいかに予測するかのお話


以下、beshariのフォトログ


好準備の様子好

会場は文房具カフェをお借りしましたいえー

何人かの人たちが早めにきて、準備のお手伝いをしてくれ・・・・るとみせかけてお買い物をされていました






むー受付の様子むー

彼女は受付です。
キーボードを叩くスピードが受付とは思えないほどでしたが、受付でした。
ターミナルが見えたりすることもありましたが、受付に違いないはずでした。



ぶー発表前の様子ぶー


LT大会が始まる前に、みんなお酒やお料理を食べて談笑してましたいえー










テヘッLT大会の様子テヘッ


みんな準備ができたところで開始~


みんな思い思いの発表をしていました!

5分の発表時間を、平均的に超え・・(´・ω・`;)



みんな真剣に聞いてますね








らぶ2最後に集合写真らぶ2




普段仕事で関わる人も、そうでない人もいましたが、
みんな楽しそうに話を聞いたりコミュニケーションを取っていて、LT大会やって良かったです。

何より、運営メンバーの私たちがとても楽しかったべぇぇ♪♪

「女性エンジニア」とういう軸は
楽しく気軽に何かやるのにちょうどいいスケールで、とてもいいきらきっかけきらだなと思っています。

これからも、何か楽しい事を思いついたら、みんなでやっていきたいですねふっ

おまけ

翌日の反省会。

「思いつきのわりに、楽しかったね~」とか言ったり言わなかったり・・・Gためいき

CA エンジニア Advent Calendar 2015 + 公式エンジニアブログの紹介

$
0
0

2015年もCyberAgent エンジニア Advent Calendar やるよ!

ということで、
この記事は CyberAgent エンジニア Advent Calendar 2015 の1日目の記事です

初日は、基盤インフラチームの @kakerukaeru が担当します
厚かましくもエンジニアブログの宣伝&AdventCalendarやるよ!の告知です。

CyberAgent 公式エンジニアブログ is 何

CyberAgent 公式エンジニアブログでは、
隔週木曜日更新でCyberAgentのエンジニアの技術や文化、環境の発信をしています。

@principia_ca でも更新情報を呟いたりつぶやかなかったりしていますので、ぜひぜひフォローしていただければと!アカウント名のprincipiaの由来はよくわからないです。ニュートン・・・?

記事の内容自体は、CyberAgentのエンジニアの技術や文化、環境等の内容であれば、基本的には何でもオッケーのゆるい運用でやっております。

一例を上げると、

AmebaFRESH!の @stormcat24 が執筆した 
Flexible Blue Green Deploymentのススメ

AWA株式会社の @fuzzy31u が執筆した
ママエンジニアのワークライフ

秋葉原ラボのKazumi が執筆した
アキバ系社会人ドクターのすすめ

などなど!様々な内容があります。
少しでも記事を通して弊社の雰囲気が伝わればと思います。


CA エンジニア Advent Calendar 2015
さて、今年もいつものエンジニアブログの更新とは別で、エンジニアブログ運営チームの呼びかけで集まってくれたエンジニアの方々で、公式エンジニアブログや個人のブログを用いてAdvent Calendarに参加していきます。

内容はいつものエンジニアブログと同じで、CyberAgentのエンジニアの技術や文化、環境の事であればなんでもOKのスタイル。
adventarのページがメインとはなりますが、コチラのエンジニアブログでも後追いで記事へのリンクをまとめていこうと思います。

ちなみに、去年のAdventCalendarのリンクはコチラです。

なんでもありの精神に乗っ取り、新しいDBの検証記事や実務に即した記事から会社紹介だったり飲み屋を紹介するだけのクソ記事もいたりして、いろんな記事が詰まってるのでコチラも併せてお読みいただければと思います。


日付担当者内容(予定)
12/1@kakerukaeru
CA Advent Calendar 2015 + 公式エンジニアブログの紹介
12/2magie_pooh

12/3principia_ca

12/4gomachan7

12/5blackenedgold

12/6kaelaela
12/7stormcat24
12/8kuro_m88
12/9k_enoki
12/10principia_ca
12/11toguri
12/12matsuokah
12/13yudppp
12/14huydx
12/15chohey
12/16sitotkfm
12/17principia_ca
12/18strsk
12/19ceeflyer
12/20nghialv
12/21k66dango
12/22taizo
12/23sambaiz
12/24principia_ca
12/25kakerukaeru



それでは今年も、
クリスマスまで CyberAgent エンジニア Advent Calendar 2015をよろしくお願いします!


新卒入社2年目エンジニアがGitHubにAndroidのライブラリを公開してみて感じたこと

$
0
0


はじめましてー。 サイバーエージェント入社2年目のAndroidエンジニアな@magiepoohです!
業務ではもっぱらAndroidを書いています。(楽しい!)

@kakerukaeruさんに続き、アドベントカレンダー2日目を担当させていただきますーヽ(=´▽`=)ノ

現在、僕はAmebaFreshという動画サービスのAndroid版を開発中で、言語はJavaではなくKotlinを使っています。 Kotlinという言語について書き出すとアメブロの最大記事本文文字数(全角20,000文(半角40,000文字))を超えそうなので、Kotlinに関しては @satorufujiwaraさんや@AAkiraあたりがKotlinアドベントカレンダーに書くことを期待しつつ、全く別のお話を!!

今回はAndroidのライブラリを開発して感じたことや社内制度について、ざっくりと紹介できればなと思います!よろしくお願いしますー!

GitHubスターインセンティブ

サイバーエージェントにはGitHubスターインセンティブという制度があります。

GitHubスターインセンティブとは、エンジニアが自身のコードをGitHub(github.com)にオープンソースとして公開し、リポジトリのスター数に応じてインセンティブが得られる制度です。

インセンティブ内容としてはGitHubのスモールプランが会社負担になったりします。(さらに、スター数によってはもっといいことがあったり・・・!?)
個人的にインセンティブがあることによって、会社がGitHub活動を公に推奨してくれていることはとてもありがたい!と感じています。ヽ(=´▽`=)ノ

ライブラリを作ろうと思ったきっかけ

そもそもライブラリを作ろう(&公開しよう)と思うまでも、かなりのハードルがある気がします。僕の場合は今年の3月に会社の若手数人で行った14ピュアネイティブ強化合宿というものがきっかけです。

すごいスター数が付いているライブラリを公開している@wasabeefさんや@ogaclejapanさんを目指し若手でもなにか作ろうぜ!!というノリのものでした。

が・・・!!!
僕自身その時作ったものはとてもひどいもので本気で闇に葬りたいものができまして、、、完全な黒歴史というやつで惨敗でした、、、ほんとに(´;ω;`)

もちろん、参加者の中には2泊3日で素敵なライブラリを作った人もいましたので、一応チラッと紹介しておきますw
SAHistoryNavigationViewController
Transporter

ここで重要なのは、だいたい最初のアウトプットは闇ばっかりということですw
はじめから完璧なものを作りきろうとすると途中で投げ出したくなるかもしれないし、なかなか完成はしませんし、結局アウトプットができません。僕みたいに一度闇を味わってもいいじゃないですか!!w

とにかく、この合宿のおかげでライブラリを出すというハードルは個人的にはかなり下がりました。

自分が使いたいライブラリを思いつく

闇を生み出してから月日は流れ、とある実装をしていたときによりスタイリッシュに、より簡単に実装したいなという欲求が生まれました。
具体的には、RecyclerView(リストの行間)に線を引くときにデフォルトではできないし、指定した箇所だけさくっと線を引きたいというものでした。

そもそもライブラリってある問題に対してのアプローチ方法を提案するものだと思うんです。「〇〇が超絶めんどくさいから簡単にできるようにしてみたけど、どうかな?」くらいの。そういう点で自分の中でもっとこうしたいと思えるものを発見するだけで、ライブラリの種は見つけることができそうです。

公開してみた

で、さくっと作って公開してみました。

RecyclerItemDecoration

詳しくはREADMEに書いてあるのですが、各々のViewTypeに対して線を指定してやることができます。 個人的には問題点に対してコンパクトに解決できたライブラリだと感じています。

RecyclerView.ItemDecoration decoration = ItemDecorations.vertical(this)                .first(R.drawable.shape_decoration_green_h_16)                .type(DemoViewType.LANDSCAPE_TILE.ordinal(), R.drawable.shape_decoration_cornflower_lilac_h_8)                .type(DemoViewType.LANDSCAPE_ITEM.ordinal(), R.drawable.shape_decoration_gray_h_12_padding)                .type(DemoViewType.LANDSCAPE_DESCRIPTION.ordinal(), R.drawable.shape_decoration_red_h_8)                .last(R.drawable.shape_decoration_flush_orange_h_16)                .create();

demo

公開してみてよかったこと

ライブラリの公開方法

ライブラリの公開方法を学ぶことができます。ここでもbuild.gradleとの格闘が続きかなりハマりました・・・。
現在はかなり簡単になっているようなので、そこまでハマることはないかもしれません。

インタフェースを意識してコードを綺麗に書こうとする

一番大きいのはこれですね!!
ライブラリを使う人がどうやって使ってくれるかなということを想像して実装することによって、より綺麗なインタフェースを提供しなければいけないというプレッシャーが生まれます。 (普段の業務でももっと意識しろよといろいろな方に怒られそうですが・・w)

やる気が出る

僕が作ったライブラリにはIssueが1つしかついてませんが(笑)、そこでも感謝されるととてもありがたいものです。
作ってよかったなと感じることができます。

副次的によかったこと

先ほど、インタフェースを意識するとありますが、他のライブラリの実現方法がより気になりだしたりします。 たとえば、@kgmyshinさんのGoreinu(ライブラリ名とアイコンが素敵w)を見ていると

Goreinu.install(this);

と書くだけで動作します。

こういうライブラリを見るとどうなってるんだろ、自分だと思いつかないなーとかいろいろな感動を得ることができます。

そして、これ、超絶おすすめなんですけど、よくライブラリをウォッチしてスターしている人をフォローする!例えば、弊社のAndroidな人でいうと@wasabeefさんや@ogaclejapanさんをフォローしておくと自動的にキュレーションされるので、面白いライブラリを見つけやすくなりますw

まとめ:まだまだひよこなエンジニアだからこそ、どんどん公開していくべし!

コードの書き方を意識したり、情報に敏感になれるのでとりあえず小さいライブラリでも公開してみるのがまずはいいかなぁと! 最初から完全なものを作る必要もなさそうという感じでやってみると楽しいことに出会えます!


ってことで!つらつらと書いてきましたが、明日は@principia_caさん! (・・・・公式ブログってこと・・?ここのブログに誰かが書くってことかな??) あんまりよくわかってませんが!よろしくお願いします!!w

それでは、みなさん、よいエンジニアライフを~ @magiepoohでした~~ ヽ(=´▽`=)ノ

Responsive Image as Serviceへの取り組み

$
0
0

こんにちは、森野耕平(@kohei_april20)と申します。

最近は社内向けのResponsive Image as ServiceとしてHayabusa(https://hayabusa.io/)というものを開発・運用しています。今回はそのResponsive Image as Serviceとその取り組みについて紹介させて頂きたいと思います。

背景

近年、スマートフォンなど接続デバイスが急増してきたことに加え、リッチなユーザー体験のニーズの高まりによって、ウェブサービスの開発・運用の複雑さが増してきいます。多くの場合ウェブページにおけるデータの大半を占めているのは画像で、この画像を効率よく最適な形で配信することが重要になってきます。

そのためにはデバイスに応じて解像度別の画像や、フォーマット別の画像(例えばwebpが利用可能なデバイスにはwebpを使うなど)を生成したり、更に減色や圧縮といった様々な処理を行ったりした画像群を用意する必要があります。その上で、更に接続デバイスを検知し最適な画像を選択して配信する仕組みを整えなければなりません。

実際私が過去に担当していたプロジェクトでも、解像度別の画像を生成したり複数の圧縮プログラムを通した画像群をリリース前に事前に生成するような仕組みを用意して行っていました。扱っていた画像が多かったこともあって、運用中に追加分の画像を処理するだけでも結構な時間がかかり、素早いリリースが難しく苦労をしていました。

Responsive Image as Serviceというソリューション

この問題を解決する手法としてResponsive Image as Serviceというものがあります。Responsive Image as Serviceとは、画像に動的な操作をするための情報をURLのパラメータなどから取得し、オンデマンドでレスポンシブ画像を生成・配信をサービスとして提供するものです。オリジンに存在する画像をマスタとして使い、要求に応じて画像処理を行いレスポンシブ画像を生成する、画像プロキシのように動作します。

このようにサービスとして画像関連の煩雑な手続き、変換にかかる負荷、キャッシュの取り扱いなどを担うことで、これらの問題を気にすること無く開発・運用ができる体勢を築くことができ、効率化を図ることが出来ます。

操作に関する情報について

URLから次のような情報を取得します。

  • 画像のファイルパス
  • パラメータ(Query String Parameters、独自セパレータによるパラメータ)

画像のファイルパスからオリジナル画像を特定し、パラメータからその画像に行う処理に関する情報(リサイズ、クロップ、圧縮、フォーマット変換など)を取得します。

例)

Query String Parametersの場合
http://<server>/image.jpg?width=300&height=200&format=webp
ドットセパレータによるパラメータの場合
http://<server>/image.w300.h200.jpg

他にもクッキーやヘッダーからの情報を用いる場合もあります。ヘッダーは次のようなものを利用します。

  • Accept:利用可能なファイルフォーマットを検知
  • User-Agent:デバイス判定

また、Http Client Hintsという、クライアントにとって最適なコンテンツを配信するために必要な情報を入れるヘッダがドラフトとして上がっているので、将来的にこのヘッダからwidth、height、DPRなどの情報を取得できるようになっていくと思います。

サービスの例

Hayabusaについて

Hayabusaはオープンソース化を視野に入れて社内で開発しているResponsive Image as Serviceの実装で、現在一部の自社サービス向けに機能を提供しており、現在半年ほど運用実績があります。

使用例

ドットセパレータ方式によるパラメータ指定を採用していて、例えば次のようにURLを指定すればそれぞれそれに対応した画像が得られます。
オプションなし

https://hayabusa.io/test/abema.png

100x50リサイズ(中心でクロップ)

https://hayabusa.io/test/abema.w100.h50.fitcrop.png

2色に減色

https://hayabusa.io/test/abema.pngquant(color2).png

JPEGにフォーマット変換

https://hayabusa.io/test/abema.jpg

メインモジュール

Node.jsで実装をしていて、次のようなメインのモジュールから構成されています。

  • hayabusa
  • レスポンシブ画像の変換と配信を行うためのExpress互換Node.jsミドルウェアで、プラグイン形式で画像処理機能を追加していく設計
  • hayabusa-server
  • hayabusaを使ったExpressベースのwebアプリケーション

hayabusaモジュールはResponsive Image as Serviceとしての機能を汎用的に実装したもので、hayabusa-serverモジュールがこれを利用して社内ユースに特化する形で実装したウェブアプリケーションになっています。

プラグイン

画像処理機能にあたるプラグインは次のようなものがあります。

  • リサイズ
  • クロップ
  • フォーマット変換とauto拡張子指定での自動フォーマット選択
  • 最適化(圧縮)
  • PSDレイヤーとスライス切り出し
  • など

これらの機能は基本的に裏で様々は画像処理プログラムを利用するラッパーのような役割をしていて、リサイズ・クロップ・フォーマット変換は主にImageMagick、GraphicsMagick、最適化ではpngquant、optipng、zopfli、gifsicle、jpegrecompressなどを利用しています。

フロー

処理のフローは下図のように、クライアントが画像のファイルパスと処理内容を含んだリクエストを送り、hayabusaが受け取ったURLやヘッダ情報から処理対象のオリジナル画像と処理内容を判別、オリジナル画像を処理するための画像処理プログラムをアレンジして順に実行し、最終結果画像をクライアントへ返すという流れになっています。

architecture

アーキテクチャ

下図はアーキテクチャを簡易的に表したものです。https://<hayabusa-server>/foo/img1.webpにユーザがアクセスすると、fooという文字列にマッピングされたオリジンサーバ<origin-foo>に置かれているimg1.*となる画像をオリジナル画像として処理した結果を得ます。

オンデマンドで画像を処理するため、どうしてもHayabusaサーバ側でオリジンから画像をダウンロードする時間とそれを処理する時間がかかってしまいます。そのため、配信を極力速く、そして画像処理の負荷をむやみに増やさないために、CDNとキャッシュサーバの二段構えでできるだけキャッシュが効くように構成しています。

architecture

課題

サービス上の画像利用特性の違い
現在の仕組みでは初回アクセス時に変換処理が走り、その後はキャッシュが利用されるようになるので予めキャッシュを作っておきやすいUI用の画像など再利用性の高い画像については非常に効果的ではある一方で、ユーザ投稿画像のように多数で画像がアップロードされた後に必要になるような画像は、画像処理は画像がアップロードされた瞬間にトリガーされた方が良く、今後このような用途にもパフォーマンスを高めて行けるような仕組みを整えていきたいと考えています。
利用プログラムのライセンス
様々な画像処理プログラムを利用する上で、場合によっては有料でかつサーバで動作させることが想定されていないようなものがあります。ライセンス上使えなかったり、サーバ上での使用を前提としたライセンス契約がしづらかったりして、ローカルで使っていた機能をそのままHayabusaで利用可能にするのが難しいケースがあります。

今後の展望

今後の展望として次のような機能拡張を予定しています。

  • フルPSDレンダラ
  • オリジナル画像としてPSDファイルをそのまま利用できると、レイヤー構造を保ったままのマスタ画像さえあればよくなり、より制作フローの効率化が実現できるのでサーバサイドでレンダリングできる機能を実現したいです。現在は暫定的に統合された画像のみレイヤーとスライスの指定に対応しています。
  • 9-slices
  • UI画像ではウィンドウ的な画像の場合、角の四隅、上下左右の辺、中心部のスライス画像を利用してサイズが可変となるものがあり、対応が煩雑になりがちなところをURLの文字列のみで簡単に画像を作れるように。
  • スプライトシート/アトラス
  • スプライトシートやアトラスも製作時、パッキング処理や管理が煩雑になりがちなので、これをサーバサイドで巻きとっていきたいです。
  • ローカル実行用のCLI
  • 現在はNode.jsのExpress互換モジュールとしての実装にとどまっていますが、これをローカル環境CLIで実行できるようにします。
  • ローカル実行用のGUI(フロントエンド開発向け)
  • 開発時にフロントエンドを実装する場合に開発環境がサーバに依存するよりもローカルで完結していた方が勝手が良いので、GUIを整えてローカル環境に簡単に導入できるようになればより開発効率の向上が見込めます。
  • Unity assets
  • スマホアプリは画像を都度配信する訳ではなく、アプリ内にバンドルされるのでサーバ配信型では使えませんが、ローカルでの実行ができればこちらも対応していけると思います。
  • サウンド、動画、フォントサポート
  • 現在は画像のみの機能しかありませんが、同じ基盤上でサウンド・動画・フォントなどの対応も可能なので、サポートをしていきたいと考えています。

ネットワーク初心者の新卒がDockerでネットワークの勉強をしてみた

$
0
0

この記事はCyberAgent エンジニア Advent Calendar 2015の8日目の記事です

タイトルは5日目の「Scala初心者の新卒が頑張ってLispを作ってみた」のパクりです。

こんにちは!サイバーエジェント アドテクスタジオ新卒の黒崎 (@kuro_m88) と申します。
Dynalystというチームに配属され、一人前のサーバサイドエンジニアになるべく修行をしています(`・ω・´)最近はScalaを書くことが多くて、Sparkで大量のログを集計するバッチの開発をしています。ほぼ100%AWSで構成されているプロダクトなので業務でネットワークの運用もしませんし、構成の事を意識する事はあまりありません。
そんな中でネットワークの事が知りたくなったのは、広告の配信に関わる開発をしてみて、広告の配信の仕組み自体も技術的にめちゃくちゃ面白いんですが、それと同時に自分たちのサーバから広告が表示される端末までの間がどうなってるのか気になってしまったのがきっかけです。学んでいくにはやはり手を動かすのが一番ですよねo(((^^)))o

ということで手軽にネットワーク(特にルーティング)について勉強できそうな環境を作ったので、その紹介をします
今回Dockerを使ったのは、気軽に実験しようと思うと実機はもちろん用意できませんし、ノートPCでVMを立てるにしてもメモリの都合上ルータを10台立てるとかは厳しいけど、最近流行りのコンテナならいけそうな気がしたからです。

環境構築
仮想マシンを用意する
Ubuntu15.10を使いました。
私の場合はノートPC上にvagrantでVMを用意しました。
VMに割り当てるリソースは、CPU 1~2コア、メモリは1GBあれば足りると思います。

dockerをインストール
vagrant@vagrant-ubuntu-wily-64:~$ wget -qO- https://get.docker.com/ | sh
バージョンはサーバ、クライアントともに1.9.1でした。

open vSwitchをインストール
open vSwitchをパッケージからインストールします。
vagrant@vagrant-ubuntu-wily-64:~$ sudo aptitude install openvswitch-common openvswitch-switch

バージョンは2.4.0が入りました。

これだけで環境構築は終わりです。簡単ですね!

作りたいネットワーク

こんな感じのネットワークを構築します。

作りたいネットワーク


ルータを用意する

vyOSというオープンソースのルータOSがあって、今回はこれを利用しています。
DockerコンテナはDocker Hubに用意しました
vyOSが動くDockerコンテナの作り方がきになる方はこちらをご覧ください
4台欲しいので、vyOSのコンテナを名前を変えて4個作ります。
NICは手動で追加するので、--net=noneをつけます。

vagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router1 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/initvagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router2 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/initvagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router3 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/initvagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router4 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/init
docker psコマンドを打つとコンテナが4つ立ったのが分かります。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker ps
CONTAINER ID        IMAGE                 COMMAND             CREATED             STATUS              PORTS               NAMES
99a121b7984a        kurochan/vyos:1.1.6   "/sbin/init"        2 seconds ago       Up 2 seconds                            router4
3599cf751e0c        kurochan/vyos:1.1.6   "/sbin/init"        8 seconds ago       Up 8 seconds                            router3
035e17a8fd43        kurochan/vyos:1.1.6   "/sbin/init"        15 seconds ago      Up 14 seconds                           router2
66bb97a046c5        kurochan/vyos:1.1.6   "/sbin/init"        21 seconds ago      Up 20 seconds                           router1

スイッチを用意する
ルータのNIC同士を接続するために、スイッチを用意します。
物理機材であれば1つのスイッチに接続してVLANでセグメントを分けたりするのかなと思いますが、仮想スイッチなので、セグメントの数だけ用意してしまいます。

vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch1vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch2vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch3vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch4
ルータ同士を接続する
さて、ルータとスイッチ用意できましたが、まだルータは接続はおろかNICすら持っていないので何もできません。
図にするとこんな感じでしょうか(笑)

現状


ここでopen vSwitchのパッケージに含まれている、ovs-dockerというコマンドを使います。
このコマンド、実体としては約300行程度のシェルスクリプトなのですがとても便利で、Dockerコンテナに対してNICを追加すると同時にIPアドレスとサブネットマスクが設定できて、さらにはvSwitchに接続するところまでできます。
各ルータにスイッチとの接続の設定をしていきます。

vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch1 eth0 router1 --ipaddress=10.0.1.1/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch2 eth1 router1 --ipaddress=10.0.2.1/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch1 eth0 router2 --ipaddress=10.0.1.2/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch3 eth1 router2 --ipaddress=10.0.3.1/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch2 eth0 router3 --ipaddress=10.0.2.2/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch4 eth1 router3 --ipaddress=10.0.4.1/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch3 eth0 router4 --ipaddress=10.0.3.2/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch4 eth1 router4 --ipaddress=10.0.4.2/24

間違えてNICを追加してしまった場合はdel-portサブコマンドでNICの削除ができます。

pingを打ってみる

router1からrouter2(10.0.1.2)に向けてpingを打つには、

vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 ping -c 2 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_req=1 ttl=64 time=0.227 ms
64 bytes from 10.0.1.2: icmp_req=2 ttl=64 time=0.058 ms

pingが通りましたね!
では、router1からrouter4(10.0.3.2)にpingを打ってみましょう。

vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 ping -c 2 10.0.3.2
connect: Network is unreachable
pingが通りませんね(´・ω・`)

関係をまとめると、以下のようになります。

router1 => router2(10.0.1.2): o
router1 => router3(10.0.2.2): o
router1 => router4(10.0.3.2): x
router2 => router3(10.0.4.1): x
router2 => router4(10.0.3.2): o
router3 => router4(10.0.4.2): o

現状ではお隣さんにしかpingが飛ばないようです

ルーティング
ルータ同士はお互いに経路を知らないため、何かしらの方法で教えてあげないといけません。
はじめてのルーティングと言えばstaticルーティングをしてみるのが一般的だと思うのですが、今回は省略します。
ちなみにstaticルーティングは新卒研修でひたすら入力して散々な目に遭いました…手作業って事故ると大変ですよね(´;ω;`)
今回はOSPFというプロトコルを使うように各ルータに設定を打ち込んでいきます!
ルータはコンテナなのでdocker execコマンドを使って、コンテナ内で直接vbashというシェルを立ち上げることで設定をします。
最後に設定を反映させるためにcommitしてから設定が消えないようにsaveするのが大切です。
router1に設定するときの例です。

vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 /bin/vbashvbash-4.1# su - vyosvyos@vyos:~$ configure[edit]vyos@vyos# set interfaces loopback lo address 1.1.1.1/32[edit]vyos@vyos# set protocols ospf area 0 network 10.0.0.0/16[edit]vyos@vyos# set protocols ospf parameters router-id 1.1.1.1[edit]vyos@vyos# commit[edit]vyos@vyos# saveSaving configuration to '/config/config.boot'...Done[edit]vyos@vyos# exitexitvyos@vyos:~$ exitlogoutvbash-4.1# exitexit
以下、同様にして他のルータにも設定を入れますが、長くなってしまうのでsetコマンドの部分だけを列挙します。

router1
set interfaces loopback lo address 1.1.1.1/32
set protocols ospf area 0 network 10.0.0.0/16
set protocols ospf parameters router-id 1.1.1.1

router2
set interfaces loopback lo address 2.2.2.2/32
set protocols ospf area 0 network 10.0.0.0/16
set protocols ospf parameters router-id 2.2.2.2

router3
set interfaces loopback lo address 3.3.3.3/32
set protocols ospf area 0 network 10.0.0.0/16
set protocols ospf parameters router-id 3.3.3.3
router4
set interfaces loopback lo address 4.4.4.4/32
set protocols ospf area 0 network 10.0.0.0/16
set protocols ospf parameters router-id 4.4.4.4

ルーティングテーブルを見てみる

OSPFを使ってルータ同士が経路を交換し始めていれば、ルーティングテーブルになにかが表示されているはずです。
show ip routeコマンドで確認できるようなので、確認してみましょう。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 /bin/vbash
vbash-4.1# su - vyos
vyos@vyos:~$ show ip route
WARNING: terminal is not fully functional
Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,
       I - ISIS, B - BGP, > - selected route, * - FIB route

C>* 1.1.1.1/32 is directly connected, lo
O   10.0.1.0/24 [110/10] is directly connected, eth0, 00:05:53
C>* 10.0.1.0/24 is directly connected, eth0
O   10.0.2.0/24 [110/10] is directly connected, eth1, 00:05:53
C>* 10.0.2.0/24 is directly connected, eth1
O>* 10.0.3.0/24 [110/20] via 10.0.1.2, eth0, 00:02:23
O>* 10.0.4.0/24 [110/20] via 10.0.2.2, eth1, 00:01:33
C>* 127.0.0.0/8 is directly connected, lo
それっぽい項目が表示されていますね。

再びpingを打ってみる

さきほどpingを打って返ってこなかったケースで試してみます。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 ping -c 2 10.0.3.2
PING 10.0.3.2 (10.0.3.2) 56(84) bytes of data.
64 bytes from 10.0.3.2: icmp_req=1 ttl=63 time=0.363 ms
64 bytes from 10.0.3.2: icmp_req=2 ttl=63 time=0.091 ms
おっ!今度はpingが帰ってきました!
念のためさきほどと同じ組み合わせをやってみましょう。

router1 => router2(10.0.1.2): orouter1 => router3(10.0.2.2): orouter1 => router4(10.0.3.2): orouter2 => router3(10.0.4.1): orouter2 => router4(10.0.3.2): orouter3 => router4(10.0.4.2): o
経路が交換できているため、pingが通りました!


もう一台追加してみる

もう一台ルーターが追加されると、どんな変化があるのか試してみたいと思います。
構成はこんな感じにします。

ルータ追加

以下のコマンドで追加 & 接続ができます。router4のNICも1つ増えます。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router5 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/init
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch5
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch5 eth2 router4 --ipaddress=10.0.5.1/24
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch5 eth0 router5 --ipaddress=10.0.5.2/24
コンテナだとすぐ構成が変えられて色々試しやすいですね!

router5
set interfaces loopback lo address 5.5.5.5/32
set protocols ospf area 0 network 10.0.0.0/16
set protocols ospf parameters router-id 5.5.5.5
set protocols ospf default-information originate always
最後に1行だけ他と違う設定を入れてみます。

router1から経路を確認してみると、
vyos@vyos:~$ show ip routeWARNING: terminal is not fully functionalCodes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,       I - ISIS, B - BGP, > - selected route, * - FIB routeO>* 0.0.0.0/0 [110/1] via 10.0.1.2, eth0, 00:01:46  *                   via 10.0.2.2, eth1, 00:01:46C>* 1.1.1.1/32 is directly connected, loO   10.0.1.0/24 [110/10] is directly connected, eth0, 01:07:55C>* 10.0.1.0/24 is directly connected, eth0O   10.0.2.0/24 [110/10] is directly connected, eth1, 01:07:55C>* 10.0.2.0/24 is directly connected, eth1O>* 10.0.3.0/24 [110/20] via 10.0.1.2, eth0, 01:04:25O>* 10.0.4.0/24 [110/20] via 10.0.2.2, eth1, 01:03:35O>* 10.0.5.0/24 [110/30] via 10.0.1.2, eth0, 00:42:41  *                      via 10.0.2.2, eth1, 00:42:41C>* 127.0.0.0/8 is directly connected, lo

10.0.5.0/24への経路が増えましたね!
0.0.0.0/0への経路も増えました。デフォルトルートが広報されたようです。
同じ宛先への経路が2つ並んで表示されているのはrouter1からrouter5へのコストが等しい経路が2つあるからです。

デフォルトルートが広報されているので、ルーティングテーブルにマッチしないパケットはすべてrouter5へ吸い込まれます。
router1からネットワーク内に存在しないIPアドレスに向けてtracerouteすると
vyos@vyos:~$ traceroute 10.0.123.123traceroute to 10.0.123.123 (10.0.123.123), 30 hops max, 60 byte packets 1  10.0.2.2 (10.0.2.2)  0.072 ms  0.025 ms  0.014 ms 2  10.0.4.2 (10.0.4.2)  0.055 ms  0.023 ms  0.023 ms 3  10.0.5.2 (10.0.5.2)  0.047 ms !N  0.033 ms !N *
確かにrouter5へ向かっていますね!

最後に
かなり端折って書いてしまいましたが、Dockerで基礎的なネットワークを構築してみた紹介でした。
本当はBGPというプロトコルの勉強をして記事にしたかったのですが、検証が間に合わず、、、
ここから先は冬休み?の宿題にしたいと思います(´・ω:;.:… 

明日はk_enokiさんです!

OpenStack Magnumを使ってOpenStackでコンテナを動かしてみよう

$
0
0

みなさん こんにちは。アドテク本部所属の長谷川(@makocchi)です。


サイバーエージェントと言えばこの blog や pigg のようにゲームやコミュニティのサービスを思い浮かべる方が多いと思いますが、広告系のアドテクサービスも幅広く展開しています。
アドテクって何?という方はこちらの adtech blog日本一やさしいアドテク教室を見て頂けるとイメージしやすいかと思います。

アドテク本部ではデータセンターにプライベートクラウドを持っていて、たくさんのアドテクのサービスがプライベートクラウドで動いています。
プライベートクラウドについていくつか外部のイベント等でお話をさせて頂いたりしているのでご存知の方もいらっしゃると思いますが、アドテク本部のプライベートクラウドは OpenStack が採用されています。

OpenStack についてはこの場では詳しく説明しませんが、日本仮想化技術株式会社の宮原さんが書かれた Think IT の記事「OpenStack のアーキテクチャを理解しよう」がとてもよくまとまっていますので是非御覧ください。


最近は OpenStack を採用する会社も増えてきているようです。
(サイバーエージェントも実は結構前から OpenStack を使っているんですよ)


OpenStack は開発のスピードが非常に早く、半年に 1 回大規模な version up が行われます。
(最近の動向ですとコンポーネント毎に個別で version up をしていく方向に変わりつつあります)
OpenStack の version はちょっと特徴的でアルファベット順に OpenStack Summit が開催される国の地名が付きます。
2015年12月現在の最新 version は Liberty ですが、その次は Mitaka と続きます。
M ではついに日本の地名が付くことになりました。


OpenStack Summit と言えば、今年は5月にカナダで開催されましたが10月に日本の東京で開催されました。ご存知の方がいるかもしれませんが、東京の Summit では Keynote に登壇させていただきました!


さて OpenStack のお話はここまでにして本題に入りましょう。

本日は OpenStack のコンポーネントである Magnum というものを動かしてみようと思います。
Magnum ですよ Magnum。なんか名前がかっこいいですよね!

OpenStack Magnum とは

最近はコンテナ技術が盛んになってきていて使えることが当たり前になりつつあります。
その一方で煩雑になりがちなコンテナ達をどうやって管理(オーケストレーション)しようか、という話題も出てきました。

そこでコンテナのオーケストレーションツールとして Kubernetes や docker swarm 等が出てきたのはみなさんご存知の通りです。

OpenStack Magnum はこれらのオーケストレーションツールを OpenStack で管理できるようにするためのコンポーネントになります。
つまり、コンテナのオーケストレーションツールをオーケストレーションするものということになりますね。

OpenStack にはオーケストレーション機能を提供する Heat というコンポーネントがあります。
OpenStack Magnum はこの Heat と連動し、OpenStack 内にオーケストレーションツールをオーケストレーションします。

出展:http://www.openstack.org/assets/pdf-downloads/Containers-and-OpenStack.pdf

この Magnum ですが、まだ正式な OpenStack のコンポーネントには入っていません。Liberty には間に合わないと思いますが、Mitaka もしくはその次あたりで入ってくるかもしれませんので今のうちから慣れておきましょう!

OpenStack Magnum をインストールする・・・前に

OpenStack Magnum は当然ながら OpenStack のコンポーネントですので既に稼働している OpenStack 環境が無いと動きません。

OpenStack を動かすためにはいくつか方法がありますが、比較的簡単に構築できるのは devstackpackstack といったツールになります。

devstack や packstack を使った OpenStack の install の仕方はここでは省略しますが、いろいろ記事が公開されてますのでそれを見ながら構築してください。

OpenStack Magnum をインストールする(devstack)

devstack を使って構築していればこちらの手順書の通り、devstack/local.conf[[local|localrc]] のセクションに下記の設定を入れます。
ここでは最新の stable である kilo の branch を指定しています。

enable_plugin magnum https://github.com/openstack/magnum stable/kilo
その後 stack.sh を実行してコーヒーでも飲んで待っていると magnum が devstack で動きます。成功すれば magnum-api 及び magnum-conductor のプロセスが上がっているはずです。

OpenStack Magnum をインストールする(RDO)

packstack で OpenStack を作成した場合や RDO の repository を使って OpenStackを構築した場合は rpm で OpenStack Magnum を入れることができれば理想的なのですが、RDO には現在のところOpenStack Magnum の rpm は提供されていません。
ですが rpm 自体は実は copr に存在していてこちらにありますので、こちらを入れるのが楽だと思います。

OpenStack Magnum をインストールする(その他)

パッケージやツールを使わないでインストールする場合は git から clone してインストールすれば OK です。
方法は公式の Document の通りにすればいけると思います。

$ git clone https://git.openstack.org/openstack/magnum$ cd magnum$ sudo pip install -e .

インストール以外にも幾つか作業が必要ですのでやっておきましょう。

# create the magnum conf directory$ sudo mkdir -p /etc/magnum# copy sample config and modify it as necessary$ sudo cp etc/magnum/magnum.conf.sample /etc/magnum/magnum.conf# copy policy.json$ sudo cp etc/magnum/policy.json /etc/magnum/policy.json

OpenStack の認証に Magnum を登録する

この作業は devstack を使っていれば devstack がやってくれるので必要ありません。
自前でインストールした場合には既存の OpenStack 環境に Magnum の情報を登録する必要があります。

まず OpenStack の backend の Database に magnum が使用する database を作成します。ここでは magnum という Database と magnum という user を作成しています。

$ mysql -h <your_openstack_db_ip> -u<user> -p<pass> mysql <<EOFCREATE DATABASE IF NOT EXISTS magnum DEFAULT CHARACTER SET utf8;GRANT ALL PRIVILEGES ON magnum.* TO    ‘magnum'@'%' IDENTIFIED BY 'password'EOF

次に OpenStack の backend の rabbitmq に magnum ユーザーを追加します。ここでは vhost を / にしています。環境によって変えて下さい。

$ rabbitmqctl add_user magnum password$ rabbitmqctl set_permissions -p / magnum “.*" ".*" ".*"

そして認証(Keystone) に service を追加して endpoint を作成します。
endpoint の ip アドレスは magnum-api や magnum-conductor が動いているサーバーの ip にしてください。

$ keystone service-create --name=magnum \                         --type=container \                         --description=“OpenStack Container Service"$ keystone endpoint-create --service=magnum \                          --publicurl=http://<api_server_ip>:9511/v1 \                          --internalurl=http://<api_server_ip>:9511/v1 \                          --adminurl=http://<api_server_ip>:9511/v1 \                          --region <your region>

OpenStack Magnum を設定する

設定ファイルは /etc/magnum/magnum.conf になります。いろいろ設定する項目がありますが、最低限これらを設定しておけば動いてくれると思います。rpm_backend には rabbitmq を使用することを前提にしてます。rabbitmq 以外にも ZeroMQ とか使えます。debug や verbose については必要に応じて有効にしてください。database の connection や rabbitmq の接続情報は先ほど作成した user や password を指定してください。

[DEFAULT]debug = trueverbose = truerpc_backend = rabbit[api]host = 0.0.0.0[database]connection = mysql://magnum:password@<user_openstack_db_ip>/magnum[keystone_authtoken]auth_uri = http://<your_keystone_ip>:5000identity_uri = http://<your_keystone_ip>:35357admin_user = magnumadmin_password = passwordadmin_tenant_name = service[oslo_messaging_rabbit]rabbit_hosts = <your_rabbitmq_ip>:5672rabbit_userid = magnumrabbit_password = passwordrabbit_virtual_host = /

conf ファイルを設定する際には直接編集することももちろん可能ですが、OpenStack の conf ファイルは何かと肥大化しており(設定項目がやたら多かったり、ほとんどコメントだったりしますが)
いちいち開いて編集するのもめんどくさくなっています。そこで conf を編集するツール openstack-config が用意されています。
RedHat 系を前提に作られていますが、openstack-config であれば ubuntu 系でも使うことができます。その場合は crudini を別途 install してください。

openstack-config を使用する場合はこんな感じになります。

$ sudo openstack-config --set /etc/magnum/magnum.conf DEFAULT debug true$ sudo openstack-config --set /etc/magnum/magnum.conf DEFAULT verbose true$ sudo openstack-config --set /etc/magnum/magnum.conf DEFAULT rpc_backend rabbit$ sudo openstack-config --set /etc/magnum/magnum.conf api host 0.0.0.0$ sudo openstack-config --set /etc/magnum/magnum.conf database connection mysql://magnum:password@<user_openstack_db_ip>/magnum$ sudo openstack-config --set /etc/magnum/magnum.conf keystone_authtoken auth_uri http://<your_keystone_ip>:5000$ sudo openstack-config --set /etc/magnum/magnum.conf keystone_authtoken identity_uri http://<your_keystone_ip>:35357$ sudo openstack-config --set /etc/magnum/magnum.conf keystone_authtoken admin_user magnum$ sudo openstack-config --set /etc/magnum/magnum.conf keystone_authtoken admin_password password$ sudo openstack-config --set /etc/magnum/magnum.conf keystone_authtoken admin_tenant_name service$ sudo openstack-config --set /etc/magnum/magnum.conf oslo_messaging_rabbit rabbit_hosts <your_rabbitmq_ip>:5672$ sudo openstack-config --set /etc/magnum/magnum.conf oslo_messaging_rabbit rabbit_userid magnum$ sudo openstack-config --set /etc/magnum/magnum.conf oslo_messaging_rabbit rabbit_password password$ sudo openstack-config --set /etc/magnum/magnum.conf oslo_messaging_rabbit rabbit_virtual_host /

OpenStack Magnum API を起動する

一番簡単なのはそのまま叩いてしまうことです。
forground で起動されます。

$ /path/to/magnum-api$ /path/to/magnum-conductor

systemd が配下で動かす場合は下記の service ファイルを使って下さい。
先ほどの rpm を使えばこちらは配置されているはずです。

openstack-magnum-api.service

[Unit]Description=OpenStack Magnum API ServiceAfter=syslog.target network.target[Service]Type=simpleUser=magnumExecStart=/usr/bin/magnum-api[Install]WantedBy=multi-user.target

openstack-magnum-conductor.service

[Unit]Description=Openstack Magnum Conductor ServiceAfter=syslog.target network.target qpidd.service mysqld.service openstack-keystone.service tgtd.service openstack-glance-api.service openstack-glance-registry.service openstack-nova-api.service openstack-nova-objectstore.service openstack-nova.compute.service openstack-nova-network.service openstack-nova-volume.service openstack-nova-scheduler.service openstack-nova-cert.service openstack-cinder-volume.service[Service]Type=simpleUser=magnumExecStart=/usr/bin/magnum-conductor[Install]WantedBy=multi-user.target

python-magnumclient をインストールする

現時点では OpenStack Magnum は OpenStack の管理画面(Horizon) から操作することはできません。
ですが Horizon の pluggin として ui の開発が始まっているようです。
将来的には管理画面からポチポチできるようになると思いますが、現時点ではおとなしく python-magnumclient を使いましょう。
virtualenv で入れておくことをおすすめします。

$ git clone https://git.openstack.org/openstack/python-magnumclientcd python-magnumclientpip install -e .

これで OpenStack Magnum を使う準備が整いました!

baymodel を作成する

まずは baymodel を作成します。baymodel っていうのは次に作る bay の定義と考えて下さい。
baymodel では使用する image や keypair、オーケストレーション(COE)等を定義します。
この際に使用する image や keypair が無いと作ることができませんので、まずは準備をします。

現時点では OpenStack Magnum が support しているのは Fedora AtomicCoreOS だけのようです。(CentOS Atomic も多分動くと思いますが)
ここでは Fedora の Atomic を登録してみます。
まずは https://getfedora.org/ja/cloud/download/atomic.html から qcow2 のイメージを取得します。
記事を書いている時点での最新は Fedora-Cloud-Atomic-22-20150521.x86_64.qcow2 のようです。

$ wget https://download.fedoraproject.org/pub/fedora/linux/releases/22/Cloud/x86_64/Images/Fedora-Cloud-Atomic-22-20150521.x86_64.qcow2

その後 OpenStack の image 管理(Glance) に登録します。

$ glance image-create --file ./Fedora-Cloud-Atomic-22-20150521.x86_64.qcow2  --is-public True --disk-format qcow2 --container-format bare --property os_distro=fedora-atomic --name Fedora-Cloud-Atomic-22-20150521 --progress

注意点としてはイメージの meta 情報の os_distro に fedora-atomic を入れておくことです。
これが無いと bay の作成に失敗します。

続いて keypair を登録します。
keypair の名前はなんでもいいです。ここでは適当に default という名前で登録します。

$ nova keypair-add --pub-key openstack_key.pub default

それから使用する external network の uuid を調べておきます。

$ neutron net-show public --format value --fields id931ef60c-d132-4bfa-9136-182c7b723d79

これで準備が整いました。

さっそく baymodel を作ってみます。
今回は dockerswarm を使う baymodel swarmbaymodel を作ってみます。
(最新の magnum だと network の指定は uuid ではなくて名前でいけるようになったようです)

$ magnum baymodel-create --name swarmbaymodel --image-id Fedora-Cloud-Atomic-22-20150521 --keypair-id default --external-network-id 931ef60c-d132-4bfa-9136-182c7b723d79 --flavor-id m1.small --coe swarm

作成した baymodel は magnum baymodel-list で見ることができます。

$ magnum baymodel-list+--------------------------------------+---------------+| uuid                                 | name          |+--------------------------------------+---------------+| f433f2d9-3592-452f-9642-d7ffadc52b2f | swarmbaymodel |+--------------------------------------+---------------+

また、magnum baymode-show swarmbaymodel とすることで詳細を表示することができます。

bay を作成する

baymodel が作成できたので bay を作成してみましょう。

$ magnum bay-create --name swarm bay --baymodel swarmbaymodel --node-count 1

magnum-bay list を見ると CREATE_IN_PROGRESS になっていると思います

$ magnum bay-list
+--------------------------------------+----------+------------+--------------+--------------------+| uuid | name | node_count | master_count | status |+--------------------------------------+----------+------------+--------------+--------------------+| 0643a67f-fce8-41aa-b8c8-ee2854174b15 | swarmbay | 1 | | CREATE_IN_PROGRESS |+--------------------------------------+----------+------------+--------------+--------------------+

この時内部的には Heat が動いています。

$ heat stack-list+--------------------------------------+-----------------------+--------------------+----------------------+| id                                   | stack_name            | stack_status       | creation_time        |+--------------------------------------+-----------------------+--------------------+----------------------+| 9d850fc8-7940-4523-aa1a-a5aee8931a28 | swarmbay-ur35j3pus33u | CREATE_IN_PROGRESS | 2015-09-11T00:57:35  |+--------------------------------------+-----------------------+--------------------+----------------------+

heat resource-list swarmbay-ur35j3pus33u とするとどんな処理をしているのか確認することができます。
Heat は管理画面(Horizon) から確認することができますので、bay-create をすると管理画面から確認することができます。
しばらくすると CREATE_COMPLETE になると思います。

それではさっそくコンテナを動かしてみます。
docker/whalesay を使って鯨に Magnum と言わせてみましょう。

$ magnum container-create --bay swarmbay --name whale_magnum --image docker/whalesay --command "cowsay magnum”$ magnum container-list+--------------------------------------+--------------+---------+| uuid                                 | name         | status  |+--------------------------------------+--------------+---------+| 481ac897-d922-45ac-a4e6-59198f780f6f | whale_magnum | Stopped |+--------------------------------------+--------------+---------+

コンテナを実行してみます。

$ magnum container-start whale_magnum$ magnum container-logs whale_magnum ________< magnum > --------    \     \      \                    ##        .              ## ## ##       ==           ## ## ## ##      ===       /""""""""""""""""___/ ===  ~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ /  ===- ~~~       \______ o          __/        \    \        __/          \____\______/

無事に動きました!

もちろんコンテナを実行させている swarmbay の中にも login することが可能です。
magnum bay-create した際に Heat によってインスタンスが作られていると思います。
今回は fedora の Atomic で作成してますので fedora@ で login します。
中に入ると docker が動いているのが確認できます。

$ ssh fedora@192.168.0.209[fedora@sw-inltgwe3sxe-0-qgs7s3w5s5cg-swarm-node-raxqpfeo45ud ~]$ sudo docker ps -aCONTAINER ID        IMAGE                       COMMAND                CREATED             STATUS                      PORTS               NAMES00eb818dfe19        docker/whalesay:latest      "cowsay magnum"        5 minutes ago       Exited (0) 4 minutes ago                        whale_magnumbe9d3809265b        swarm:0.2.0                 "/swarm join --addr    2 weeks ago         Up 2 weeks                  2375/tcp            swarm-agent

もっといろいろなコンテナイメージを使って動かしてみようと思ったのですが、ちょっと時間が無いので今日はこれまで!
要望があれば時間作って検証してみたいと思っています。

docker swarm だけじゃない

今回は baymodel に docker swarm を使いましたが、他にも Kubernetes と mesos にも対応しています。
Kubernetes については最近は が GA となり、version も 1.0 がリリースされました。
その際に内部の API が v1beta3 から v1 に変わりましたが、まだ Magnum では v1 には対応してないので Kubernetes の GA 版が動かせないのが残念なところですね。

おわりに

OpenStack Magnum いかがでしたでしょうか。
まだ絶賛開発中のコンポーネントではあるのでサービスで使う場合は十分に注意する必要がありますが、OpenStack が動いている開発環境とかでコンテナを動かしてみたい場合とかには向いてると思います。
現在のところはコマンドラインでしかいろいろ操作できませんが、OpenStack の管理画面 (Horizon) の pluggin も開発が始まっているようです。

Magnum の他にも開発中のコンポーネントはたくさんあり、例えば DNS 管理の Designate、メッセージングサービスの Zaqar、鍵管理の Barbican、ファイル共有の Manila などたくさん進行中です。

OpenStack はすべて OSS で出来ています。
新しいサービスの開発や既存の bugfix 等、誰にでも可能です。
興味がありましたら是非 OpenStack へコントリビュートしてみましょう!
実は自分もちょっとだけ貢献しました。これからもちょこちょこ貢献していきたいと思います!

  

俺の知っているコマンドがIPv6で使えないわけがない

$
0
0

こんにちは。maginemuです。
ここのところはiOS/Android向けにPIGG PARTYというサービスの開発を行っています。


ピグパーティ[ピグパ]


はじめに

iOS9アプリケーションのIPv6への対応期限が刻々と迫ってきました。


今回IPv6への対応に際してトラブルがあり、原因調査をしたのですが、
もともと全然IPv6の知識が無く、ネットワークに関する知識も大して無く、


かろうじて知っているコマンド群もIPv6でうまく動かなかったりしてハマったので、
知ってる人には当たり前だと思いますが、紹介してみることにします。


その前に少しだけ前提を。


iOS9とIPv6対応

AppleではiOS9以降、IPv6でアプリケーションが正しく動作する必要があるとしています。
そしてその対応期限は2016年初頭とされていて、それ以降は対応していないと審査が通らなくなる…!


対応の仕方についてはこちらを参照します。


※実際にアプリケーションをIPv6に対応させることについては、この記事では触れません。


IPv6 DNS64/NAT64環境を用意しよう

早い話が、El Capitanではoptionを押しながらインターネット共有を選択すると、NAT64ネットワークを作成するチェックボックスが出ます。


適当なマシンでこのオプションでインターネット共有を行い、そこにアクセスすればIPv6の環境が試せます。


ひとつ気をつける必要があるのが、インターネットに接続したい場合にはこのマシンがWi-Fi以外でインターネットに接続できる
必要があります(有線LANとか)。
なので最近のMacbook Proなどを使う場合、Ethernetアダプタとかが必要になるかもしれないです。


これで手元ではiMacxxxx...という感じのネットワークが見つかるようになりました。
これに接続して試していきます。


IPアドレスを確認しよう

何はともあれ、諸々確認しましょう。手元の環境は MacBook Pro (Retina, 15-inch, Mid 2014), OS X 10.11.1 です。
ひとまずifconfig


...en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500ether aa:bb:cc:dd:ee:ffinet6 fe80::a8bb:ccff:fedd:eeff%en0 prefixlen 64 scopeid 0x4inet6 2001:xxxx::a8bb:ccff:fedd:eeff prefixlen 64 optimistic autoconfinet6 2001:xxxx::xxxx:xxxx:xxxx:xxxx prefixlen 64 autoconf temporarynd6 options=1<PERFORMNUD>media: autoselectstatus: active...

en0のインタフェースのところだけ抜粋。inet6 となっているところがIPv6アドレスですね。
IPv6では、ホストひとつに対して複数のアドレスを持つことができます。


fe80から始まるアドレスはリンクローカルなアドレスで、ルータを越えない同一ネットワーク内のアドレスです。
下位64ビットはイーサネットアドレス48ビットを24ビットずつに区切り、間にfffeを挟み、
上から7ビット目を反転させたものになっています。


2001から始まるものはグローバルアドレスです。正確には2000::/3からE000::/3がグローバルユニキャストアドレスだそうです。
2001から始まるものが、いまのところIANAによって割り振られているようです。


グローバルアドレスのうち上のほうはステートレス設定というやつで生成されたもののようです。
これはルータから得られたプレフィクスとMACアドレスベースで生成されるものです。


temporaryというのは一時アドレスというやつで、上記ステートレス設定のものだと、
アドレスからマシンが特定できてしまうので、定期的に変わるアドレスも用意されているみたいです。


IPアドレスの体系に関してはとりあえず、3つのタイプがあって、
またそれぞれ到達範囲:スコープでも分類できるという感じです。


IPv6のアドレス(ステートレス)自動設定については下記などに書いてあります(なるべく確実そうなやつ)。


疎通確認(ping)

とりあえず自分にpingしてみようかな!


$ ping 2001:xxxx::a8bb:ccff:fedd:eeffping: cannot resolve 2001:xxxx::a8bb:ccff:fedd:eeff: Unknown host

なん…だと…
IPv6だと何か違うのか…! (ping ipv6とかでググる)


知ってれば何てことないんですが、コマンド違うんですよね。。ping6というのがあります。


$ ping6 2001:xxxx::a8bb:ccff:fedd:eeffPING6(56=40+8+8 bytes) 2001:xxxx::a8bb:ccff:fedd:eeff --> 2001:xxxx::a8bb:ccff:fedd:eeff16 bytes from 2001:xxxx::a8bb:ccff:fedd:eeff, icmp_seq=0 hlim=64 time=0.084 ms16 bytes from 2001:xxxx::a8bb:ccff:fedd:eeff, icmp_seq=1 hlim=64 time=0.210 ms16 bytes from 2001:xxxx::a8bb:ccff:fedd:eeff, icmp_seq=2 hlim=64 time=0.213 ms16 bytes from 2001:xxxx::a8bb:ccff:fedd:eeff, icmp_seq=3 hlim=64 time=0.235 ms^C--- 2001:xxxx::a8bb:ccff:fedd:eeff ping6 statistics ---4 packets transmitted, 4 packets received, 0.0% packet lossround-trip min/avg/max/std-dev = 0.084/0.185/0.235/0.059 ms

よしよし。


サーバのアドレスが知りたい(nslookup)

知ってますよ。nslookupですよね。


$ nslookup google.comServer:  2001:xxxx::1Address:  2001:xxxx::1#53Non-authoritative answer:google.comAddress: 216.58.220.206

あれ…v4のアドレスだけですね。。


あー、さては。


$ man nslookup6No manual entry for nslookup6

違うの。。。


(ググる)


なるほど。-type=AAAAというオプションか。


$ nslookup -type=AAAA google.comServer:  2001:xxxx::1Address:  2001:xxxx::1#53Non-authoritative answer:has AAAA address 64:ff9b::d83a:dcceAuthoritative answers can be found from:google.com

おお。取れた。Wikipediaによると


In the Domain Name System hostnames are mapped to IPv6 addresses by AAAA resource records, so-called quad-A records.

だそうです。


ページ取得(wget)

wgetしてみましょう。


$ wget google.com--2015-12-09 18:46:38--  http://google.com/Resolving google.com... 64:ff9b::d83a:dcce, 216.58.220.206Connecting to google.com|64:ff9b::d83a:dcce|:80... connected.HTTP request sent, awaiting response... 302 FoundLocation: http://www.google.co.jp/?gfe_rd=cr&ei=fvhnVumcLMT98we005DwBg [following]--2015-12-09 18:46:38--  http://www.google.co.jp/?gfe_rd=cr&ei=fvhnVumcLMT98we005DwBgResolving www.google.co.jp... 64:ff9b::adc2:75f7, 64:ff9b::adc2:75f8, 64:ff9b::adc2:75ff, ...Connecting to www.google.co.jp|64:ff9b::adc2:75f7|:80... connected.HTTP request sent, awaiting response... 200 OKLength: unspecified [text/html]Saving to: 'index.html'[ <=>                                                                           ] 19,287      --.-K/s   in 0.009s2015-12-09 18:46:38 (2.10 MB/s) - 'index.html' saved [19287]

おお。普通にいけた。helpを見ると


-6,  --inet6-only              connect only to IPv6 addresses.

というオプションがあるみたいですね。


IPアドレスだと…


$ wget 64:ff9b::d83a:dcce--2015-12-09 18:49:38--  ftp://64/ff9b::d83a:dcce=> 'ff9b::d83a:dcce'Resolving 64... 0.0.0.64Connecting to 64|0.0.0.64|:21... failed: Network is unreachable.

おお、ftpだと思われている。では。


$ wget http://64:ff9b::d83a:dccehttp://64:ff9b::d83a:dcce: Bad port number.

ぐぬぬ。ですよねーーー


IPv6のアドレスを指定するときは、そのままだとポート番号と区別が付きません。
[]で括る必要がありそうです。


$ wget http://\[64:ff9b::d83a:dcce\]--2015-12-09 19:32:48--  http://[64:ff9b::d83a:dcce]/Connecting to [64:ff9b::d83a:dcce]:80... connected.HTTP request sent, awaiting response... 302 FoundLocation: http://www.google.com/ [following]--2015-12-09 19:32:48--  http://www.google.com/Resolving www.google.com... 64:ff9b::adc2:75f3, 64:ff9b::adc2:75f2, 64:ff9b::adc2:75f1, ...Connecting to www.google.com|64:ff9b::adc2:75f3|:80... connected.HTTP request sent, awaiting response... 302 FoundLocation: http://www.google.co.jp/?gfe_rd=cr&ei=UANoVpuWO6Kg8weR_oCoDQ [following]--2015-12-09 19:32:48--  http://www.google.co.jp/?gfe_rd=cr&ei=UANoVpuWO6Kg8weR_oCoDQResolving www.google.co.jp... 64:ff9b::adc2:75f8, 64:ff9b::adc2:75f7, 64:ff9b::adc2:75ef, ...Connecting to www.google.co.jp|64:ff9b::adc2:75f8|:80... connected.HTTP request sent, awaiting response... 200 OKLength: unspecified [text/html]Saving to: 'index.html'[ <=>                                                                                   ] 19,215      --.-K/s   in 0.03s2015-12-09 19:32:49 (553 KB/s) - 'index.html' saved [19215]

無事取れました。


link-localアドレスでの通信

一旦ローカルホストでサーバを立てて、それに接続して検証したかったりしますよね。


上述しましたが、IPv6が有効になっているホストでは
まずリンクローカルアドレスが割り当てられます。


このアドレスはiMacやNAT64の環境を用意しなくても使えそうです。


とりあえず適当なhttpサーバを。。nodeとかnpmとかexpressが入ってる前提で
($ npm install -g express)


$ express app && cd app && npm install && DEBUG=app:* npm startcreate : appcreate : app/package.jsoncreate : app/app.jscreate : app/publiccreate : app/public/javascriptscreate : app/public/imagescreate : app/public/stylesheets...node ./bin/wwwapp:server Listening on port 3000 +0ms

ここで、本質的じゃないのですが、nodeでlistenするときに、IPを指定しないとIPv6でうまくlistenされないようなので
ちょっとソースコードを変更しておきます。


diff --git a/bin/www b/bin/wwwindex a8c2d36..e79c926 100755--- a/bin/www+++ b/bin/www@@ -25,7 +25,7 @@ var server = http.createServer(app);Listen on provided port, on all network interfaces.*/-server.listen(port);+server.listen(port, '::0');server.on('error', onError);server.on('listening', onListening);


$ wget localhost:3000--2015-12-11 15:24:56--  http://localhost:3000/Resolving localhost... ::1, 127.0.0.1, fe80::1Connecting to localhost|::1|:3000... connected.HTTP request sent, awaiting response... 200 OKLength: 170 [text/html]Saving to: 'index.html'2015-12-11 15:24:56 (40.5 MB/s) - 'index.html' saved [170/170]

よしよし。ではIPアドレスで。


$ wget http://\[fe80::a8bb:ccff:fedd:eeff\]--2015-12-11 15:32:03--  http://[fe80::a8bb:ccff:fedd:eeff]:3000/Connecting to [fe80::a8bb:ccff:fedd:eeff]:3000... failed: No route to host.

あれ。。。


$ ping6 fe80::82e6:50ff:fe14:18beping6: UDP connect: No route to host

あれー。。。


調べてみると、どうやら-Iオプションが必要そうです。man ping6を見てみると


-I interfaceSource packets with the given interface address.  This flag applies if the ping destination is a mul-ticast address, or link-local/site-local unicast address.

なるほど。今は送出先がリンクローカルユニキャストアドレスです。
リンクローカルなアドレスを指定するときには、なにかとインタフェース名とか、scope_idといった値を
指定する必要がありそうです。


ifconfigを再度見直してみると


inet6 fe80::a8bb:ccff:fedd:eeff%en0 prefixlen 64 scopeid 0x4

%en0とか、scopeid 0x4とか書いてありますね。


ということで、


$ ping6 -I en0 fe80::a8bb:ccff:fedd:eeffPING6(56=40+8+8 bytes) fe80::a8bb:ccff:fedd:eeff%en0 --> fe80::a8bb:ccff:fedd:eeff16 bytes from fe80::a8bb:ccff:fedd:eeff%en0, icmp_seq=0 hlim=64 time=0.100 ms16 bytes from fe80::a8bb:ccff:fedd:eeff%en0, icmp_seq=1 hlim=64 time=0.104 ms16 bytes from fe80::a8bb:ccff:fedd:eeff%en0, icmp_seq=2 hlim=64 time=0.209 ms16 bytes from fe80::a8bb:ccff:fedd:eeff%en0, icmp_seq=3 hlim=64 time=0.232 ms^C--- fe80::a8bb:ccff:fedd:eeff ping6 statistics ---4 packets transmitted, 4 packets received, 0.0% packet lossround-trip min/avg/max/std-dev = 0.100/0.161/0.232/0.060 ms

うまく通りました。


しかし、wgetは未だにうまくできず。。%en0を付けてみて、


$ wget http://\[fe80::a8bb:ccff:fedd:eeff%en0\]:3000http://[fe80::a8bb:ccff:fedd:eeff%en0]:3000: Invalid IPv6 numeric address.

だめか。。ちなみにcurlだと…?


$ curl http://\[fe80::82e6:50ff:fe14:18be%en0\]:3000                                                                      ⏎<!DOCTYPE html><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><h1>Express</h1><p>Welcome to Express</p></body></html>%

いけたーーーー


scope_idの指定の仕方に関しては、けっこう実装依存のようです。


上記を見てみると、a numeric zone index can be used in the second 16-bit wordとあります。では試しに


$ wget http://\[fe80:4::a8bb:ccff:fedd:eeff\]:3000--2015-12-11 17:36:13--  http://[fe80:4::a8bb:ccff:fedd:eeff]:3000/Connecting to fe80:4::a8bb:ccff:fedd:eeff|fe80::a8bb:ccff:fedd:eeff|:3000... connected.HTTP request sent, awaiting response... 200 OKLength: 170 [text/html]Saving to: 'index.html'100%[======================================================================================>] 170         --.-K/s   in 0s2015-12-11 17:36:13 (20.3 MB/s) - 'index.html' saved [170/170]

おお。いけました。なんだそれ。。。


ちなみに、GoogleChromeのアドレスバーに打ち込んだところ、


http://[fe80:4::a8bb:ccff:fedd:eeff]:3000/

この形式では取得できましたが、


http://[fe80::a8bb:ccff:fedd:eeff%en0]:3000/

の場合検索ワードと見なされてしまいました。


http://[fe80::a8bb:ccff:fedd:eeff%25en]:3000/

とかエンコーディングしてみても変わらずでした。


ローカルホストのIPでアクセスするだけでこれほどハマるとは。。。


まとめ

少しですが、IPv6環境について紹介させて頂きました。


最初はコマンド自体が合ってなかったので、どこに問題があるのかの
切り分け自体できなくてハマりました。。


IPv4からアドレス空間が広くなっただけでなく、
知らない仕様が色々あることを痛感しました。。


調べてみると、200X年とかの記事が結構ヒットしますね。
今後IPv6環境もいよいよ増える流れかと思いますので、
トラブルシューティングのための準備を整えて行きたいところです。


ではでは!


顔認識について書いてみる

$
0
0

ハッピーホリデー!

秋葉原オフィスの @ceeflyer です。


秋葉原(UDX)もすっかり浮かれ模様ですね…
さて、ラボっぽいことを書こうと思い、今チャレンジしている画像処理のことについて書こうと思います。
とはいえ、画像処理(Computer vision)と一口に言っても、目的によって、下のようにいくつかの種類に分けることができるようです。例えば[1]の章立てでいうと、
  • 画像変換(拡大・縮小など)
  • 特徴検出(輪郭など)
  • 画像結合(ストリートビューがいい例)
  • モーション検知
  • 3次元画像復元
  • 画像認識
    • 物体検知
    • 顔認識
    • 物体認識
    • カテゴリ認識
    • コンテキスト(背景)・シーン認識
今回試してみるのが、代表的とも言える顔認識。

顔認識で有名な手法として Viola-Jones法[2]があげられます。
Viola-Jones法についての説明はGoogleにかけてみれば色々と出てくるとは思いますが、ここでは[3]のペーパーに載っていた方法で実装してみました。
ざっくり図に示すと、↓のような流れで特徴量を作って…

判別器を作る。

実装して…

人の顔では月並みなので、の顔を学習させてみましょう。

こちらは顔ではない方のデータ。

実際に動かすと…

お!

お…?

(以上、パシャっとmyペットより)うーむ、単純に適用させるのは難しいようです。だいたい100枚あって数枚が顔に領域がかかるくらい。でもこのエントリはここで終わりです。すみません。まだまだ教えこまないといけないですね。
Viola-Jones法とは直接関連しないのですが、最近ではディープラーニングと呼ばれる、人間の脳神経をモデルにした画像判別法が流行のようです。

(参考: [4] (C) IEEE)


そちらのほうもぼちぼち進めている感じです。
…さて、ここまでのエントリにツッコミを入れたい方、はたまたマルチメディアを扱うR&D業務をしてみたい方、弊社で働いてみませんか?
ぜひお待ちしています。
では、よいお年を!
[参考文献]
[1] Szeliski, Richard. Computer vision: algorithms and applications. Springer Science & Business Media, 2010.
[2] Viola, Paul, and Michael Jones. "Rapid object detection using a boosted cascade of simple features." Computer Vision and Pattern Recognition, 2001. CVPR 2001. Proceedings of the 2001 IEEE Computer Society Conference on. Vol. 1. IEEE, 2001.
[3] Yi-Qing Wang, An Analysis of the Viola-Jones Face Detection Algorithm, Image Processing On Line, 4 (2014), pp. 128–148.
[4] Ciresan, Dan, Ueli Meier, and Jürgen Schmidhuber. "Multi-column deep neural networks for image classification." Computer Vision and Pattern Recognition (CVPR), 2012 IEEE Conference on. IEEE, 2012.

Google Cloud Platform(GCP)の各プロジェクトでコストを追える環境を作る

$
0
0

この記事はCyberAgent エンジニア Advent Calendar 2015 の24日目の記事です。

メリークリスマス!エンジニアブログ運営チームの柿島です。今年は、前半は1月に共著でHBaseの本を出したり、5月にサンフランシスコで行われたHBaseCon 2015で発表したりとHBaseのことばかり考えている日々を過ごしていました。後半は、アメーバでのAmazon Web Services(以下、AWS)やGoogle Cloud Platform(以下、GCP)といったパブリッククラウドの利用が増えてきたため、7月から急遽部署を異動してパブリッククラウドのコスト削減や利用戦略などを考えるチームを作って日々色々な社内プロジェクトと連携をしています。

今回は、その流れでパブリッククラウド、特にGCPのコストについて書きたいと思います。今回の記事で利用する画像はマスクが多く入りますがご了承ください。(イブ公開の記事なのにクリスマスまったく関係ないのもご了承ください)

アメーバでは、AWS,GCPともに支払いアカウント(billing account)は1つでそのアカウントに各プロジェクトのアカウントを紐づける運用をしています。この仕組みはでは支払いアカウントにまとめて請求が来るため、支払い面では便利なのですが、各プロジェクトには請求書が届きません。データセンターに大量のサーバを購入して利用するオンプレミス環境と違って、パブリッククラウドの場合、利用するプロジェクトのエンジニアがコストを意識できる環境を作ることがコスト削減の近道ではないかと考えているのですが、コストがわかりづらいとそもそも意識することが難しいよねというお話になります。

AWSではCost Explorerといった仕組みがあるので、各アカウントでもコストの推移などが調べやすい環境があるのですが、GCPでは各プロジェクトで当月のコストは見えても(Fig.1)、過去の履歴は支払いアカウントでしか見れません(Fig.2)。ただ、この支払いアカウントは支払いに関する情報や他のプロジェクトの情報が見えてしまうといったこともあって最低限のメンバーにしか権限を与えておりません。そのため、各プロジェクトのメンバーから問い合わせがあったときに私からそのプロジェクトのみに絞った過去のデータを渡すという対応をしていました。


Fig.1 各プロジェクトで見れる請求情報は当月のもの

Fig.2 支払いアカウントでは過去のデータも見れるが、権限は最低限のメンバーのみに絞っている

ただ、この問い合わせ対応ベースで過去の履歴を渡すのは、利用プロジェクト側も私たちも面倒なためコストを気軽に確認するという環境ではありませんでした。これを改善したいというのが今回のモチベーションです。

1. Export billing data を有効にする
まずは、支払いアカウントで Export billing dataを有効にします。この機能はdailyのGCPの使用量や料金を指定したGCSのbucketに2日遅れくらいでcsvやjsonで出力してくれる機能です。有効にする方法や出力されたファイルがどんな項目を持つかは https://support.google.com/cloud/answer/6293835?hl=en をみてください。この機能を有効にします(Fig.3)。ここで指定するGCSのbucketを持つプロジェクト、GCSのbucketの権限は支払いアカウントに触れるメンバーに限定してあります。

Fig.3 Export billing dataを有効にする

この例ではcsvのフォーマットでExport billing dataを有効にしています。有効にした日以降のdailyのファイルが2日遅れぐらいで出力されますので、数日後に指定したGCSのbucketを見てみるとこのようにdailyでcsvが出力されていることがわかります(Fig.4)。

Fig.4 指定したGCSのbucketには指定したフォーマットでファイルが出力される

2. Bigqueryにデータを入れる
1.で出力されたファイルはcsvやjsonなので、好きなように使うことができると思います。色々やり方はありますが、GCPにはBigqueryという便利な分析サービスがありますのでアメーバではこれを利用します。アメーバでは、AWSやオンプレで動いているサービスのログ解析として、Bigqueryを利用しているものもあって(社内のログ解析基盤もあります)、エンジニアが慣れているということや、REST API各種言語のクライアントライブラリもあるため、他のものとの連携もしやすいのではというのが理由です。

BigqueryへはプロジェクトごとにDatasetをわける形でロードをします(Fig.5).。なぜ、DatasetごとにわけるかというとこのDatasetの単位でアクセスコントロールが可能なためです。 また、月単位でtableをわける運用にしています。各プロジェクトには共有をしないですが、管理側で使用するために全プロジェクト含んだtableも作成しています。

Fig.5 プロジェクトごとにDatasetsをわける

Bigqueryへのデータのロード方法も、Export billing dataで指定したGCSのbucketのファイルを直接ロードしてからCreate table from queryで作る方法もあありますが、一部前処理をする都合で一度Pandasで処理してからBigqueryにロードしています。当月に関してはcronでdailyの更新をしています。ここらへんのロード方法はまだまだいい方法があると思うので模索中です。

ロードしたtableに対して、実際にクエリを投げてみます。たとえば、先月(2015年11月)のとあるプロジェクトのコストが高かった要素TOP5を見てみます。例えばとあるプロジェクトではBigqueryが高く(Fig.6)、別のプロジェクトはGCEのインスタンスが高い(Fig.7)ということがわかります。

Fig.6 とあるプロジェクトの先月のコストが高かった要素のランキング TOP5(Bigqueryが高い)

Fig.7 別のプロジェクトの先月のコストが高かった要素のランキング TOP5(GCEのインスタンスが高い)

3. Datasetごとに共有設定をする
では、このBigqueryのDatasetに各プロジェクトのメンバーが使えるように共有設定をします。ここではGUIで設定をしてみます。Dataset右側の+ボタンを押すとあらわれるメニューから「Share dataset」をクリックします(Fig.8)。共有する単位はいくつかあります(Fig.9)。また、"Is owner"/"Can edit"/"Can view"の権限レベルも選ぶことができます。今回は、User by e-mailで1人対してDatasetを"Can view"で共有します(Fig.10)。

Fig.8 Share dataset メニューの場所

Fig.9 共有オプションの種類

Fig.10 User by e-mailで1人に共有をしてみます

共有をされたプロジェクトのメンバー側で確認をしてみると、共有されたDatasetだけ見えていることがわかります(Fig.11)。画像はマスクでわかりづらいですが、cost_ではじまるDatasetは1つだけ見えています。

Fig.11 共有したプロジェクトのメンバー側では共有したDatasetsのみ利用可能

4. 利用者に試してもらう(いまここ)

実際にはいまは一部のプロジェクトにだけこの仕組みを提供しています。Bigqueryに入れるのが本当に使いやすいか等、色々意見を聞きながら改善をしてから、全プロジェクトに展開をしようと考えています。

5. Cloud Datalabで可視化をする(おまけ)

データがあると可視化したくなりますよね!Betaサービスとして先日提供されたGoogle CloudDatalabで可視化をしてみます。CloudDatalabではpythonやSQLなどを使って分析が可能です。同じGCPのプロダクトなのでBigqueryへの接続も簡単にできます。例えば、アメーバのとあるプロジェクトの直近3か月のコスト推移を表示してみます(Fig.)。


Fig.12 とあるプロジェクトのここ3か月のコスト推移

表示できましたね!ただ、こちらのCloudDatalabは他の方との共有方法に難ありだったので別の方法(re:dashあたり)を模索中です。

このような感じで、Google Cloud Platform(GCP)で各プロジェクトでコストを追える環境を整えている最中です。利用する各プロジェクトがコストを意識できるような環境を提供することで間接的にアメーバのコストを最適化していけたらと思っています。

明日は CyberAgent エンジニア Advent Calendar 2015の最終日 @kakerukaeru の「今年も1年ありがとうございました from 公式エンジニアブログ」です。

今年も1年ありがとうございました &精神とテクの部屋の紹介 from 公式エンジニアブログ

$
0
0

ハッピーホリデー!!!

全国のサンタの皆さんもそうでない皆さんもこんにちはー!!!

CyberAgent エンジニア Advent Calendar 2015 の25日目の記事です!!
昨日はエンジニアブログ運営チームの柿島さんの「Google Cloud Platform(GCP)の各プロジェクトでコストを追える環境を作る」でしたね!

本日でついに、CyberAgent エンジニア Advent Calendar 2015 & 年内の公式エンジニアブログの更新が最終日となりました!楽しんで頂けたなら幸いですますでございます!  

さて、本日の記事をお届けするのは、  
エンジニアブログ運営チームの @kakerukaeru です!!!


もとい、サンタ(雑コラ)です!


今日はね  
いつもと趣向を変えて、とある場所におじゃましていますヨ?  

精神とテクの部屋です!
エンジニアとデザイナーが集中して作業をするために作られた部屋なんだとか  

そんなお部屋を本日は紹介して、少しでも弊社のイキフンを伝えられたらと思います。  

ちなみに、真面目な方の広報のブログへのリンクも記載しておきます。
技術者向けの集中ルーム「精神とテクの部屋」を大公開!(社内報「CyBAR」より)  

さて、さっそく部屋にはいるところから始めてみましょう。  


ロゴからシッカリしていますね。  
クリエイティブに集中して欲しいというイキフンが伝わってきます。  

部屋を入るとすぐに黒板が。  
弊社のエンジニア、デザイナー達が思うがままに落書きをしていますね。  


おや、この「Mongo参上!」の文字は一体、、、  
コイツ、漢字間違えてますね。  


まずはドリンク。  
飲み物がないと捗るものも捗りませんね。  


無料コーヒーありがたい


それ以外もマダマダありますからね。  
飽きさせませんね。  

さて、  
ドリンクも手に入れたし何処に座ろうかな?  

こっち?


それともこっち?



とか言いつつ、  
この流れで、、、

あえて人を駄目にするソファーに座るけどね!!!はかどるううううううう



ふぅ  
そろそろ、さっきの席に・・・?  


でも、一人用のデスクに座るけどね!!集中できるうううううううう


なんか、昇降デスクもあるらしい


上げ下げたのしいいいスタンディングはかどるうううううう


おや、  
なんだか気分転換のストレッチの柱がアルみたいだゾ?  


あぁあああ、コレ凄い助かる。サンタ的に凄い助かるううう


ふぅ



あまりにも飽きさせない仕組みがありすぎて、ついついテンションが上ってしまいました。  このように(?)様々なアイテムがありいつまでも入り浸れそうな集中できそうな居心地のいい空間でした。

そんな弊社はエンジニアとデザイナーを募集中です!  
ご興味がありましたら是非!!  [採用情報 | 株式会社サイバーエージェント]


そんなこんなで(こんなんでいいのか)

今年も一年ありがとうございました!!
来年もよろしくお願いします!!!

2016年始の挨拶と2015年人気記事の発表!

$
0
0

あけましておめでとうございます!!!
エンジニアブログ運営委員です。

あれ、年が明けたと思ったらもう2週間も経ってるの?
寒中お見舞いのご挨拶のほうがよくない?
年々時間が過ぎるのが早くなっててうっかりしてた?

これはきっと去年の振り返りを怠っているせい。
すっきりと新しい年を始めるためにも、2016年最初の記事は去年のアクセス数ランキングです。
読み逃した記事、気になる記事はお時間のある時に読んでいただけたらと思います。

2015年公開記事アクセス数ランキング!

第10位

Flexible Blue Green Deploymentのススメ
AmebaFRESH!でも使用しているBlueGreenDeploymentの構成について説明しています。

第9位
PiggPARTYでのリアルタイム通信の仕組み
スマホアプリPiggPARTYで使われているリアルタイムコミュニケーションを実現するための仕組みについて説明しています。

第8位
新卒入社2年目エンジニアがGitHubにAndroidのライブラリを公開してみて感じたこと
アドベントカレンダーでの記事です。
エンジニア歴にかかわらず自分が作ったものを公開することでいろいろな気付きが得られますよね。

第7位
ソシャゲからアドテクになって技術的に変わった7つのこと
ユーザアクセスの性質やデータベース設計など、ソシャゲとアドテクの技術的なdiffについてまとめています。

第6位
golangのある生活
弊社内でも徐々にGo言語を導入したサービスが増えています。

第5位
Ameba OwndのSEOを支える技術 for AngularJS
AngularJSを使ったSEO対策の構成や落とし穴を紹介しています。

第4位
自動購読課金について【iOS編】
スマホアプリAWAで実現している自動継続式の月額課金の実装方法を、かなりわかりやすくまとめています。

第3位
最速を究める! 2つのサーバ間で特盛りデータを30倍速で転送する方法

テラバイトクラスのデータ転送の高速化について説明しています。

第2位
ネットワーク初心者の新卒がDockerでネットワークの勉強をしてみた

こちらもアドベントカレンダーの記事です。
入社1年目の新卒がDockerを使った簡単なネットワーク構築方法を紹介しています。

第1位
新米Androiderが開発する上できっと役立つであろう10のサイト

Androidエンジニアがまとめた、これからAndroidエンジニアになりたい方向けの役立ちサイト10選です。


最後に!

本年も技術情報や社内文化について、より多くの皆さまに知っていただけるよう発信していけたらと思います。
サイバーエージェント公式エンジニアブログをよろしくお願いいたします。
Viewing all 161 articles
Browse latest View live