• Home
  • コーポレートブログ Geniee’s BLOG
コーポレートブログ

Geniee’s BLOG

ジーニーは最先端の広告テクノロジーで
顧客の収益を最大化します。

こんにちは、人事担当の見並です。

ジーニーでは、ビジネスサイド・エンジニアサイド問わず、社内の勉強会開催が増えてきています。今回はその中で、R&D本部 マーケティングオートメーション開発部の勉強会へ潜入をしてきました。

ライトニングトークではなくロングトークなLT

マーケティングオートメーション開発部は、ジーニーが2016年7月に立ち上げたMAJINのプロダクト開発を担う部門です。
MAJINはPC向けのサービスだけではなく、スマートフォンアプリへプッシュ通知機能などを組み込むことができる、SDK(Software Development Kit)も提供しています。

今回の勉強会テーマは、そのSDK開発におけるこれまでの様々な知見や気付きを共有するものでした。

勉強会は毎週持ち回りで発表者が変わるのですが、今回の発表者はMAJINのSDK開発を担当する大内(中央の女性)というエンジニアです。
現在は弊社内でもGenieeSSPのSDK開発を担当するエンジニアが複数名体制になるなど、アプリ開発に携わるエンジニアが増えましたが、大内の入社した頃はまだ人数が少なく、その頃に抱えていた悩みや、時系列で変わっていったことなどを詳しく話してくれました。

技術的なトピックスとしては、通常のWEB開発と異なり多種多様なデバイスやバージョンに対応するための仕組みや、開発時の注意点、アプリディベロッパーのエンジニアに組み込んでもらうツールだからこその難しさなどを赤裸々に語る発表となりました。

また、技術面以外にも、マネージャーへの要望や御礼、自戒を込めた頑張る宣言なども盛り込まれ、大いに盛り上がりました。

形式としてもインタラクティブな対話の多い勉強会となり、仲間たちからも大いに質問や容赦ないツッコミも沢山ありましたが、その結果、他部門から参加していたGenieeSSPのエンジニアから新しいMTGのお誘いが生まれるなど、社内の新たな連携も誕生する結果となりました。

技術はもちろん、お互いのことをもっと知れる場を作りたかった

マーケティングオートメーション開発部が行っている勉強会は、エンジニアの張が発起人としてスタートしました。

彼は日本の大学院を卒業後、スマートフォンアプリのゲーム開発会社を経て2016年4月にジーニーへジョインしました。

チームでの機能開発を牽引したり、新しい技術に取り組むスピードの速さが周囲のメンバーから評価され、2016年度のGeniee Value体現者へ贈られる、「BEST GENIEEIST」のSpeedとTeamworkの代表に選出されています。

勉強会を終えた後、開催の背景など少しインタビューをさせてもらいました。

– この勉強会をスタートするきっかけなどはあったのでしょうか?

MAJINの開発は非常に短期間で、かつジーニーでの社歴が長い方から入社したばかりの方まで、様々なエンジニアが集まってプロジェクトがスタートしました。

そのため、チームメンバーがそれぞれがどの分野に詳しいのか、興味関心が高いのかなどが分からないという状態があり、最初はそのスキルやナレッジを共有し、理解し合うことを目的に勉強会を開始しました。

– もうすぐ半年近くになると思うのですが、開始してみていかがでしたか?

MAJINの開発はジーニーの中でも新規プロダクトということもあり、比較的新しい技術を柔軟に取り入れています。勉強会では、新しい技術に関するトピック等をお互いに持ち寄ってディスカッションしたり、理解を深めていくことができて良かったと思います。

また、技術面以外にも、今回のSDK開発を担当していた大内のように、外からは見えづらい、携わる分野独自の悩みをお互いに共有することによって、プロジェクトやチーム等の枠組みを越えて手を取り合うキッカケが生まれているのも嬉しいですね。

– 今後も勉強会は継続していく予定ですか?

もうすぐ僕の総括パートの順番が回ってくるので、そこで振り返りを行って、参加してくれたみんなからもフィードバックをもらう予定です。
それを受けて、勉強会をより良く、もっと広げていけたらと思っています。

– 楽しみですね、ぜひまたお邪魔させてください!本日はありがとうございました!

こんな環境で一緒に学び合い、新しいことにどんどん取り組んでいただけるエンジニアの方を、キャリア採用・新卒採用どちらも広く募集しています。
ぜひ気軽な気持ちでオフィスへ遊びにいらしてください!

【 採用サイトはコチラ 】

【 Wantedlyページはこちら 】

Date
Author
社風やジーニーでの働き方などをご紹介していきます。 ジーニー人事チーム

こんにちは、元・システムエンジニア、現・人事の見並です。
最近は「昔はコードを書いていました」というのも憚られるくらいコーディングの感覚が薄れているので久しぶりにQiitaへ投稿してみました。

さて、本題に入りまして、今回はジーニーが早稲田大学と取り組んでいる産学連携に関して、対象研究室の学生から成果発表がありました。
元・システムエンジニアという名の下お邪魔してきましたので、頑張ってレポートをいたします。

冒頭の挨拶は、新卒入社1年目のエンジニア・堀田さん。ジーニー側のプロジェクト窓口として牽引し、今回の社内発表会も彼が企画をしてくれました。

CTR向上を目的としたオンライン広告のWEBページにおける配置位置の推定

本日の発表は2つ。まずはジーニーの広告配信をしたログを材料に研究をしていただいたテーマからです。

こちらはジーニーが広告配信をした際に取得しているログデータを分析してもらうというもの。
数週間分の一部を切り出したデータ量ですが、15億回以上の広告配信をした記録や200万回以上のクリックがされた記録などがインプットデータとして用いられています。

これらを広告サイズや表示する位置、広告の種類カテゴリなど複数の観点から分析を行います。
Gradient Boosting Decision Tree(GBDT)やEMアルゴリズムなどを用いた手法が先行研究としてあり、その上で新たな手法を用いた推定方法を提案していただきました。

社内のエンジニアも普段自分たちが作っているプロダクトに直結する話なので真剣です。
途中何度も「どのように定義した数値?」「前提条件を発表のように設定した背景は?」など活発に質問が上がりました。

これまでジーニーで用いていなかったモデルを使う示唆もあり、「このやり方は面白い」「このやり方でやるなら、分析するデータにこんな要素も付加して結果を見てみたい」など、次に繋がるディスカッションが生まれました。

単語判定用辞書の自動拡張

続いて、こちらはジーニーが提供している独自技術「GAURL」への活用を目論む研究です。

「GAURL」とは、サイトコンテンツ上のキーワードをURL単位で自動解析し、配信する広告を出し分ける仕組みです。
サイトコンテンツを判別するためには、基準として突き合わせる膨大な「単語辞書」が必要であり、この作成や拡張を人手で運用し続けるのは大変。そこで、この辞書拡張の大部分をテクノロジーによって自動化してしまおうというのが本研究のテーマです。

アプローチとしてはジーニーが既に保持している単語辞書が一定規模あるため、カテゴライズを精査してWord2Vecなどの手法を用い、単語ベクトル学習させたり、交差検証でその妥当性を図った結果を発表いただきました。

まだ全ての単語カテゴリに適用できるわけではありませんが、実施したカテゴリでは新たに拡張するための単語を拾い上げることに成功しました。一方で、発表内容からヒントを受けて、精度をより上げる手法の提案が社内のエンジニアから上がり、まだまだ発展させられるテーマであることが分かりました。

今後はジーニーで持っているナレッジをより密に共有しながら、実用化へと近付けていく次のステップへ進んでいきます。

研究開発と自社プロダクト

ベンチャー企業が研究開発へ取り組むメリットは、実用化へのスピード感であったり、新鮮な実データを用いてリアルなビジネス環境でPDCAを回せることにあります。

ジーニーではキャリア採用・新卒採用ともにテクノロジーで企業競争力を高めていただけるエンジニアを募集しています。ぜひ気軽な気持ちでオフィスへ遊びにいらしてください!

【採用サイト】
【Wantedly】

Date
Author
社風やジーニーでの働き方などをご紹介していきます。 ジーニー人事チーム

 

こんにちは、人事の藤本です。
今回は、先日のバレンタインデーに開催した、ジーニーのエンジニア向け勉強会についてご紹介します

ジーニーは、プロダクトを自社開発していることもあり、従業員数の約4割がエンジニアです。最先端のアドテクノロジーを活用していくには、エンジニアのスキルアップ・キャリアアップは欠かせません。ジーニーでは、定期的にエンジニア向けの勉強会を行うなど、様々な取り組みを行っています。
今回の勉強会では、Google Mapの日本版立ち上げやTwitterでのプロダクト開発に携わってこられた上田 学氏をお招きし、エンジニアのキャリアについて語っていただきました。

 

ラウンジには、米国IT業界で活躍する上田さんのお話が直接聞けるとあって、エンジニアが大集合。上田さんが、キャリアについて熱く語り始めました。
上田さんによると、エンジニアのキャリアには大きくは2つの軸があるとのこと。

上田さん:
1. 複雑度を上げていく
複雑度が上がるというのは、大きく3段階あると思っています。
最初は、小さなバク修正や、依頼された機能を作るといった、定義されている問題を解決していくこと。次は、現実のスペックに当てはまらない問題を解いていくということ。そして最後は、問題の定義が曖昧で、自分で問題を定義して解決していくということ。これを少しずつ上げていくのは1つの軸だと思います。

2.影響範囲を広げていく
次に、エンジニアとしてキャリアを伸ばしていく上で「影響範囲を広げる」という軸があると思います。まずは、開発者が自分一人で言われたものを作れるというのが第一段階。次に、他の人が読みやすいコードを書くことや、自分のチームの人が使うフレームワークを作ってそれで作業効率を上げるというのが次の段階。例えば、通信ライブラリやWEBのフレームワークというような、自分のチームの人達だけでなく、会社全体の人が使うようなコードや、他チームのプロダクトでも使われるようなものを作ると、さらにエンジニアとしての価値が上がると思います。そして最後は、世界中で使われるオープンソース等、他の会社のエンジニアがそれを使うことで、より高いレベルの仕事ができたり、無駄を省いたりできるものを作ること。会社の範囲を飛び出すことが、エンジニアとしてできる一番大きな仕事だと思います。

 

ジーニーのエンジニアから出される質問にも、1つひとつ丁寧に答えて頂きました。

質問:
実力が高い人達と一緒に仕事をしたと思うのですが、何を盗みましたか?

上田さん:
自分よりできる人はいっぱいいると思っています。ただ「これを盗んだ!」とすぐに思いつくのはあまりなくて、自分の価値を発揮できる所を見つけ出して、そこをずっと伸ばしてきました。例えば、私はメールのシステム開発の専門家としてずっとやっていて、当時、MIMEパーサーを書ける人は私しかいなくて、誰にもない知識を持っていました。自分なりのカラーを見つけて他の人にはできない事を作っていっていました。

質問:
大変だったり、不安だったり、辛い時はどのように乗り越えていましたか?

上田さん:
これは他の人に教えて貰った事ですが、何か不安に感じている時は、何が不安なのかを書き出します。そうすると、意外と問題になっているのは10個くらいと多くはないんです。そして、まず今やらなければならないこと、明日以降でもできることに分けて、今やらなければならないことからやっていきます。そうすると自然と3個~5個くらいまで減るので、落ち着いて処理することができます。

 

講演の後は、懇親会。ビール片手に、最後までコアな話をして頂きました!

ジーニーでは、今後もエンジニアのスキル・キャリアアップに繋がる取り組みを積極的に行っていきます。

上田学さん、今回は本当にありがとうございました!

 

こんな人達と一緒に働いてみたい!という方は是非コチラからエントリーをお待ちしています!

Date
Author
社風やジーニーでの働き方などをご紹介していきます。 ジーニー人事チーム

今回も唐突ではございますが、Phillips Hueを使用して、Sensuからのアラートをランプで視覚化してみましたのでそれについて簡単にご紹介させていただきます。

準備

とりあえずアラートを表現したい種類分購入しました。 今回は

・SSP
・DSP
・DMP
・その他

の4種類としました。 開封の儀を執り行った後は、初期設定を行います。 パッケージの説明にもありますが、ランプの追加などもほぼ全てアプリからできるようです。

HueのAPIを叩いてみる

HueはRESTful APIで手軽に操作できます。 詳しくは日本語の情報もありますし、以下をご覧いただければとおもいますが、

色々遊べるハイテク照明 「Philips hue」のAPIを叩いてみた。 | u1’s tech blog
今回はsensuの状態をランプの色で可視化したいので、とりあえず手順通りにsensuユーザーを作成して試してみます。 http://…/api/sensu/lights を試しにブラウザで叩くと、

{“1”:{“state”: {“on”:true,”bri”:1,”hue”:47000,”sat”:254,”effect”:”none”,”xy”:[0.1682,0.0423],”ct”:500,”alert”:”none”,”colormode”:”hs”,”reachable”:true}, “type”: “Extended color light”, “name”: “Hue Lamp 1”, “modelid”: “LCT001″,”uniqueid”:”********”, “swversion”: “66013452”, “pointsymbol”: { “1”:”none”, “2”:”none”, “3”:”none”, “4”:”none”, “5”:”none”, “6”:”none”, “7”:”none”, “8”:”none” }},”2″:{“state”: {“on”:true,”bri”:1,”hue”:47000,”sat”:254,”effect”:”none”,”xy”:[0.1682,0.0423],”ct”:500,”alert”:”none”,”colormode”:”hs”,”reachable”:true}, “type”: “Extended color light”, “name”: “Hue Lamp 2”, “modelid”: “LCT001″,”uniqueid”:”00:17:88:01:00:f2:2f:68-0b”, “swversion”: “66013452”, “pointsymbol”: { “1”:”none”, “2”:”none”, “3”:”none”, “4”:”none”, “5”:”none”, “6”:”none”, “7”:”none”, “8”:”none” }},”3″:{“state”: {“on”:true,”bri”:1,”hue”:47000,”sat”:254,”effect”:”none”,”xy”:[0.1682,0.0423],”ct”:500,”alert”:”none”,”colormode”:”hs”,”reachable”:true}, “type”: “Extended color light”, “name”: “Hue Lamp 3”, “modelid”: “LCT001″,”uniqueid”:”********”, “swversion”: “66013452”, “pointsymbol”: { “1”:”none”, “2”:”none”, “3”:”none”, “4”:”none”, “5”:”none”, “6”:”none”, “7”:”none”, “8”:”none” }},”4″:{“state”: {“on”:true,”bri”:1,”hue”:47000,”sat”:254,”effect”:”none”,”xy”:[0.1682,0.0423],”ct”:500,”alert”:”none”,”colormode”:”hs”,”reachable”:true}, “type”: “Extended color light”, “name”: “Hue Lamp 4”, “modelid”: “LCT001″,”uniqueid”:”********”, “swversion”: “66013452”, “pointsymbol”: { “1”:”none”, “2”:”none”, “3”:”none”, “4”:”none”, “5”:”none”, “6”:”none”, “7”:”none”, “8”:”none” }}}

が返ってきます。これがランプ一覧と現在の状態のようです。

SensuのAPIを叩いてみる
次に、sensuで発生しているイベントを取得するために、 http://your sense server:port/events を叩きます。すると

[]

が返ってきました。そこまで頻繁にアラートがされるようなシステムではないため、上の例では何もない状態ですが、どんなものが返ってくるかなど詳しい内容は Sensu | Events をご覧ください。

Parsingなどは省略させていただきますが、 今回は弊社のプロダクトごとにsensuでカテゴリ分けしてあるので、 eventのcategoryとそのstatus(CRITICALかWARNNIGか)を集計すればうまくいきそうです。

実際に動かしてみる。

とりあえず版はcrontabに登録して1分ごとに回してみます。 イベントの数に応じて、そのプロダクトの稼働状態を表現したいので、 色相(hue)をイベントの種類に応じて

my $HUE_NORMAL = 47000; #blue?
my $HUE_WARN = 19384; #yellow
my $HUE_CRIT = 0; #red

として、イベントの数を明るさ(bri)と対応させ、 明るさで表現できない数のイベント発生も考慮して点滅(alert)も設定する感じにしました。 上を踏まえて

my $json = encode_json {“hue”=>$h, “sat”=>255, “bri”=>$b, “on”=>”true”, “alert”=>$a};

でエンコードされるようなjsonをHTTPでPUTします。

実際の動作風景は以下の様な感じです。

今後の課題

今回はcronで適当にapiを叩くというようなスクリプトなので、状態管理などの高等なことがあまりできていません。 今後やる暇があったら、新規イベントがあったら一回点滅するなどしていければと思っています。

Date
Author
エンジニア

明けましておめでとうございます。

2015年の第一弾はデータの分析に関する内容を紹介させていただきます。

今回紹介するのはオープンソースのBIツールPentahoを使ったデータ分析についてです。

Pentahoとは

PentahoとはオープンソースのBIツールです。

PentahoはBIスイートですので、レポーティング、アナリティクス、ダッシュボード、データ統合など様々な機能が用意されていて、これらの機能の中から必要な機能に限定して利用することもできます。

導入の背景

弊社では広告配信に関連するデータを集計して日々モニタリングしています。 データを分析する切り口はユーザによって様々であり、定型的なレポートを各ユーザごとに作成するのが難しい状況でした。 そこで、Pentahoのアナリティクス機能を導入し、ユーザがそれぞれ自分の見たい切り口でデータを分析できる環境を準備することになりました。

環境構築

PentahoとSaiku Analyticsを使ってデータ分析を行います。データを蓄積するDBにはMySQLを利用しています。

biserver-ce 5.2
Saiku Analytics 2.6
MySQL 5.x
MySQLはデータ分析用にレプリケーションされたものを利用します。 アナリティクス環境ではユーザが自由にクエリを発行できるため、広告配信用のDBとは分離して分析専用のDBを用意することにしました。

今回はDBにMySQLを使っているため、Pentahoの設定ファイルでMySQLに接続するための設定を行う必要があります。

スキーマ設定

分析を行う前に、分析対象となるデータのスキーマを設定する必要があります。

キューブ、ディメンジョン、メジャーをそれぞれ設定します。

キューブとは多次元構造を表すもので、1つのデータソースとなります。 キューブに対して、分析を行う集計軸(ディメンジョン)と指標(メジャー)を設定します。

スキーマの設定はSchema Workbenchを使って行いましたが、ここでは詳細な操作方法については割愛させていただきます。

分析例

Saikuの操作は直感的に操作できるインターフェースとなっています。

ここでは、日付(Date)と広告のサイズ(Size)別にインプレッション(Impression)とクリック(Click)を抽出してみます。

まず、左側のMeasuresからImpressionとClickを選択します。 次にDimensionsからSizeを選択してColumnsに、DateのYear/Month/DayをRowsに設定します。 設定後にクエリを実行すると、画面右側のマトリックスが表示されます。 (※結果の数値は適当な値です)

結果のマトリックスをご覧いただければ分かるように、日付、広告サイズ別のインプレッションとクリックが指定した行列形式で表示されます。

今回はシンプルなキューブを作成して分析を行いましたが、実際にはディメンジョン、メジャー共に10種類以上の項目を設定して利用しています。

Pentaho構築前は細かな集計をエンジニアに都度依頼して集計してもらう必要がありましたが、Pentahoの構築によって利用者は項目を自由に選択して分析できるようになりました。

エンジニアに依頼して集計してもらう場合は依頼するハードルやコスト、結果が出るまでに時間がかかる等、いろいろな問題が発生してしまいますが、これらの問題を少し解決できたのではないかと思います。

Date
Author
エンジニア

今回は、前回の記事で少し話題に出したデータベースのInfluxDBと、その可視化フロントエンドのGrafanaについて紹介していきたいと思います。 InfluxDBは、単純に利用するだけならばMySQL等のRDBMSと似た感覚で使用する事ができ、監視系のデータをとりあえず入れておくという用途にはぴったりのデータベースです。 GrafanaはInfluxDBに入れたデータを綺麗なグラフにして表示する事ができ、複数のグラフをまとめたものをダッシュボードとして保存して、いつでもそのグラフセットを簡単に呼び出すなど、機能も豊富な可視化ツールです。

概要

InfluxDBは時系列のデータを取り扱うのに特化したデータベースであり、Go言語で書かれています。 特徴としては、

スキーマレスである
HTTPのRestfulAPIから操作できるので、特別なクライアントが必要ない
検索にはSQLライクなクエリ言語を利用できるため、クライアントサイドで利用するだけなら技術的障壁はかなり低い
時系列での集計関数が豊富
シャーディングおよびレプリケーションによるスケールアウトの効果が大きい
などがあります。 単純にデータを挿入していくだけで自動的に時系列管理ができるため、弊社ではこれを監視システムによって取得したデータの保存先として利用しています。 何か問題が発生した場合は、このデータベースから情報を取得して、いつどのような問題が発生したかの解析の助けとします。

Grafanaは、InfluxDBを含めたいくつかの時系列データベースのための可視化フロントエンドで、Pure HTML5で書かれています。

上記スクリーンショットは弊社で実際に使っている画面(一部修正あり)ですが、ご覧の通りかなりカッコいい見た目で、 無骨な見た目のグラフで作業するよりもモチベーションが上がったという話も聞きます。 表示範囲や項目の表示非表示の切り替え、表示データのフィルタリングなども簡単に行う事ができ、問題が発生した時により調査を行いやすくなっています。

簡単な機能の紹介

InfluxDBの設置とクエリ発行

InfluxDBはdebおよびyumパッケージが用意されているため、InfluxDBを設置するサーバを用意して、サーバ上で以下のコマンドを実行するだけでInfluxDBをインストールする事ができます。

# debの場合
wget http://s3.amazonaws.com/influxdb/influxdb_latest_amd64.deb
sudo dpkg -i influxdb_latest_amd64.deb

# rpmの場合
wget http://s3.amazonaws.com/influxdb/influxdb-latest-1.x86_64.rpm
sudo rpm -ivh influxdb-latest-1.x86_64.rpm

InfluxDBは、データを「データベース」と「シリーズ」という単位で階層化します。 これはちょうどMySQLの「データベース」と「テーブル」に相当し、データベースこそ事前に作る必要はありますが、 シリーズはデータを格納すれば自動作成されます。 curlコマンドを使ってデータベース作成からデータの格納までを行うと次のようになります。

curl -X POST ‘http://domain.of.influxdb.server:8086/db?u=root&p=root’ -d ‘{“name”: “testing”}’
curl -X POST ‘http://domain.of.influxdb.server:8086/db/testing/series?u=root&p=root’ -d ‘[{“name”:”test”,”columns”:[“val”],”points”:[[23]]}]’
curl -X POST ‘http://domain.of.influxdb.server:8086/db/testing/series?u=root&p=root’ -d ‘[{“name”:”test”,”columns”:[“val”],”points”:[[33]]}]’

以上により、testingデータベースを作成し、testシリーズにval=23と、val=33という2つのデータを格納しました。 次にここからデータを検索してみます。

curl -G ‘http://domain.of.influxdb.server:8086/db/testing/series?u=root&p=root’ –data-urlencode “q=select * from test”
[{“name”:”test”,”columns”:[“time”,”sequence_number”,”val”],”points”:[[1418214673850,116725100001,33],[1418214334450,116703830001,23]]}]

本当にcurlだけでデータの格納から取得までができてしまいました。timeとsequence_numberが追加されていますが、格納された時間と、格納されたデータの通し番号が自動的に追加される仕組みです。 q=select * from test の部分に注目してください。SQLと全く同じ構文です。これは素晴らしい。 もちろんwhere句も使う事ができ、例えば select * from test where time > now() – 5m で、最新5分のデータを取得する事ができます。

他にも継続クエリや多数の集計関数(特定の時間間隔での合計、平均、差分、最大最小などなど)など、たくさんの機能がクエリから使用できます。詳しくは本家サイトのドキュメントを御覧ください。

Grafanaでの可視化

GrafanaはPure HTML5で書かれているため、普通のWebサイトの設置と同じ方法で利用する事ができます。 公式サイトからtar.gzファイルを落として来てWebサーバから見える場所に置き、config.jsonを環境に合わせて設定(主にInfluxDBへの接続設定)するだけで使用可能になります。画面の操作も簡単で、グラフの作成時にInfluxDBの強力な集計関数も利用することができます。特に差分値などは重宝しています。

成長するプロダクト達

InfluxDBもGrafanaも成長が著しいプロダクトです。 InfluxDBは、執筆時点(2014年12月現在)のバージョンはv0.8.6です。弊社に導入した時期は夏前頃だったのですが、 その時点では0.7.3でしたので、かなりの機能がこの間に追加されています。 性能が向上したのはもちろん、集計関数が追加されたり、シャーディングおよびレプリケーションの設定が以前より複雑でなくなったり、 正規表現を用いたシリーズのJOINが可能になったりなど、使い勝手がかなり向上しています。

Grafanaについても、以前は描いたグラフの情報を保存して次回接続時にも同じグラフを確認するためにはElasticsearchが必要でしたが、バージョンも上がってInfluxDBのみで設定が完結するようになりました。また、フィルタリング機能が強力になったなど、グラフの機能面でも強化されています。

これらのプロダクトの成長に負けないように、弊社のプロダクトも日進月歩で成長していきたいと思っています。

Date
Author
エンジニア

今回は、弊社のインフラを監視しているシステムについて紹介させていただきます。

広告の配信は24時間365日行われなければならないので、一旦配信サーバが落ちてしまうと大変な損害になります。 弊社の配信サーバに限らず、止まってはいけないサーバに対しては、ほぼリアルタイムでサーバの状態を監視するシステムが動いていると思います。このような監視システムの例として、 CactiZabbixMuninなどが知られています。 これらのシステムは、サーバの状態を監視および記録し、異常を検知した時には、メールなどで通知を行います。

システムを置き換えるに至ったモチベーション

弊社ではこのシステムとしてCactiを使用していましたが、事業が拡大していくにつれて、 監視システムを運用していく面で色々と使いづらくなっていきました。 弊社で運用していたCactiの問題点としては、

監視対象のサーバやグラフを増やす事に対して融通が効かない
監視項目を増やすのが大変
アラートの通知が値の高低でしか行えず、メールでしか通知できない
といったものがあり、特に新しいサービスのためにサーバをどんどん追加・転用するようになって来ると、 監視対象や監視項目の追加の作業の負担がどんどん大きなものになってしまうという懸念がありました。 以上の点から代替のシステムを探して、Sensuという監視システムに行き着きました。 Sensuそのものの説明については他サイトに譲りますが、特に監視項目や監視対象の追加に対してCactiよりも 簡単かつ柔軟な対応が可能であるという点でこちらに移行することになりました。

移行の際の課題

CactiからSensuに移行する際には、

Sensuのクライアントを直接導入できないルータなどに対しても監視を行えるようにする必要がある
Sensuそのものは取得したデータの保存およびグラフ化機能を持たないため、別途用意する必要がある
の2点が課題としてありました。

Sensuは基本的に、監視対象のマシンにクライアントを導入して監視を動かすため、Sensu単体でクライアントを導入できない ルータの監視を行うのは簡単ではありませんでした。 これに関しては、監視をとりまとめるためのサーバ(つまり他に主だったサービスは動いていない)を、 ルータの情報を見に行って監視するためのクライアントとして同時に運用することで解決しました。

2に関しては、既に色々なところで、SensuとGraphiteというメトリクス収集およびグラフ描画システムを連携させる ための情報がありますが、Graphiteの難しいところとしては、導入が複雑で容易ではないという点があります。 弊社でもSensuを新しい監視システムとして使う事を検討した際にGraphiteを導入して試験運用してみたのですが、 Graphiteそのものの導入や設定が難しく、元々動いているCactiから置き換えるコストには見合わないと判断しました。 代わりのメトリクス収集ツールとして、deb/rpmパッケージが用意されており導入が楽なInfluxDBを利用する事にしました。 InfluxDBはNoSQLの一種で、時系列データを扱うことに特化したデータベースです。 Sensuからここに保存したデータをGrafanaという可視化ツールでグラフ化しています。

CactiからSensuに移行して嬉しい事

Cacti上で監視対象を増やす際には、当然ひな形から監視対象の設定を作る事ができますが、このひな形は1つしか選択できなかったので、 例えば「NginxとMySQLが乗ったサーバの監視を作りたい」と思った時に、「Nginxのひな形+MySQLのひな形」という形で 新しい監視対象を作ることができなかったのです。そのため例えばNginxでとりあえず作り、MySQLの分は手で追加するという事が必要でした。

Sensuでは1つのサーバに複数のタグ付け(Sensu上ではroleといいます)が可能なので、このような問題は起こりません。 新しく監視項目が増えた時に、その分だけをあとから追加する事も簡単になりました。

また、Cactiでは実現が難しかった、異常検知時の通知方法を細かく設定することも簡単になりました。 弊社ではSlackというチャットツールを活用していますが、特定の異常検知についてはメールと同時にSlackの特定のチャンネルに流すなど、 Cactiではできなかった複数の方法での通知を設定しています。

今回はほとんどツールの紹介のみの記事になってしまいました……

Date
Author
エンジニア

今回は、暗号の話をしましょう。といっても、難しい数学の話をするわけではありませんよ。ただ、数個のコマンドをたたくだけです。

インターネットという開かれた空間の中であんまり収集されると困る情報をやりとりするのに暗号は重要です。弊社では広告配信のステータスをユーザのブラウザを介して送受信するので、そこで最も暗号化処理が活躍します。

私の勝手なイメージですが、ブロック暗号の中ではBlowfishが処理速度が速いと思っていました。他にも3DESやAESといったよく使われる暗号方式はありますが、それらはBlowfishと比べて暗号強度は強いが処理は遅いものだと思っていました。しかし、世の中にはAES-NIという加速装置があるではありませんか! この加速装置がどのくらいの性能であるのかみてみましょう。

AES-NIは、AES (Advanced Encryption Standard)専用のCPU命令群です。AESのために専用の回路がCPUの中にあるわけです。CPUに足し算やかけ算をさせるのと同じように、AES(の処理の1ステップ)をやれ、と命令できるわけです。さすが暗号標準と言われるだけありますね。すさまじい優遇措置です。

速度比較

opensslコマンドを使ってベンチマークをします。コマンドは次の通り。

openssl speed blowfish camellia-256-cbc des-ede3 aes-256-cbc

これで、Blowfish, Camellia, 3DES, AESのベンチマークができます。使用マシンのCPUは、AMD Opteron(R) 6276 2.3GHz。opensslのバージョンなどは結果を参照ください。

結果は次のようになりました。

OpenSSL 1.0.1i 6 Aug 2014
built on: Mon Aug 11 21:45:22 CEST 2014
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) blowfish(idx)
compiler: gcc -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector –param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-z,relro -Wa,–noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
The ‘numbers’ are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
des ede3 20369.30k 20810.84k 20913.41k 20885.16k 20995.08k
blowfish cbc 74977.91k 81826.65k 85267.20k 86458.48k 86436.52k
aes-256 cbc 55840.73k 58654.36k 59740.07k 141040.98k 142798.34k
camellia-256 cbc 82854.92k 104024.62k 111749.97k 114186.92k 114657.96k
3DESはやっぱり遅いですね。Blowfishの1∕4程度の速度しか出ていません。

そして、AESもBlowfishに比べれば遅……くもないですね。1KBを超えてから突如として性能が良くなっています。実は加速装置はまだ使っていないはずなんですが。AESのブロックサイズは16 Bytesですし、256 Bytesと1KBに隔たりがある理由はなんでしょう? 今後の考察対象になりますね。メモリの速度とかまで関係してくると最早わかりませんが。

また、試しに比較対象にしてみたCamelliaが意外に速かったです。これ、使えるかも。

本番

さて、AES-NIを使うためには次のようなコマンドを使わないとならないようです。

openssl speed -evp aes-256-cbc

ベンチマーク用の暗号化プログラムではなく、通常利用する(openssl enc)ための暗号化プログラムを使うということでしょうか。時間があったらソースコードを見てみたいですね。

-evpをつけた複数のアルゴリズムを同時に速度比較できないようなので、AESだけで実行します。結果は次のようになりました。

OpenSSL 1.0.1i 6 Aug 2014
built on: Mon Aug 11 21:45:22 CEST 2014
options:bn(64,64) rc4(8x,int) des(idx,cisc,16,int) aes(partial) blowfish(idx)
compiler: gcc -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector –param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-z,relro -Wa,–noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
The ‘numbers’ are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
aes-256-cbc 252170.02k 341556.71k 386134.44k 395323.59k 397369.34k

先ほどの結果と並べてみましょう。

des ede3 20369.30k 20810.84k 20913.41k 20885.16k 20995.08k
blowfish cbc 74977.91k 81826.65k 85267.20k 86458.48k 86436.52k
aes-256 cbc 55840.73k 58654.36k 59740.07k 141040.98k 142798.34k
camellia-256 cbc 82854.92k 104024.62k 111749.97k 114186.92k 114657.96k

圧倒的な速さ! Blowfishの3倍〜4.5倍くらいの速度が出ています! もとのAESとの比較では、256Bytesのときに6.4倍にもなっています。さすが、暗号標準は優遇されていますね。

Intelでは?

せっかくなので、IntelのCPUでも比較してみました。Intel(R) Xeon(R) CPU E5-2620 v2 @ 2.10GHzです。1コアあたりの公称周波数は上で使ったAMDのマシンよりちょっと劣りますね。

コマンドと

openssl speed blowfish camellia-256-cbc des-ede3 aes-256-cbc -evp aes-256-cbc

結果。

OpenSSL 1.0.1e 11 Feb 2013
built on: Wed Aug 6 18:48:11 UTC 2014
options:bn(64,64) rc4(16x,int) des(idx,cisc,16,int) aes(partial) blowfish(idx)
compiler: gcc -fPIC -DOPENSSL_PIC -DZLIB -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector –param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-z,relro -Wa,–noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
The ‘numbers’ are in 1000s of bytes per second processed.
type 16 bytes 64 bytes 256 bytes 1024 bytes 8192 bytes
des ede3 20447.94k 20658.20k 20828.21k 20768.77k 20788.57k
blowfish cbc 92491.66k 97588.27k 98745.43k 99492.39k 99396.27k
aes-256 cbc 70233.34k 73782.06k 75054.58k 75234.65k 75423.74k
camellia-256 cbc 63901.00k 87021.12k 95395.67k 98536.54k 99046.74k
aes-256-cbc 345117.58k 360506.67k 364538.03k 366619.06k 365707.26k

AMDと比較して、周波数が低いので全体的に遅くなるかなと思いきや、Blowfishだけなぜか速くなっています。SSEなどベクトル演算関係の命令の速さの違いとか、opensslのバージョンによる実装の違いとか、あるかもしれませんね。

AES-NIを使わない場合(aes-256 cbcのほう)と使った場合(aes-256-cbcのほう)を比較すると、どの平文のサイズでも安定して4.9倍くらいになっています。

まとめ

Blowfishと比べるとその他のアルゴリズムは遅いものと思っていましたが、完全に勝手な思い込みでした。3DESが3回暗号化している分3倍遅いくらいで、AESもチートハードウェアのアシストがなくてもそれなりのスピードでした。そして、今まで使おうとも思ったことがなかったCamelliaが、AMDのCPUではBlowfishを上回るスピードを出してくれたのも収穫でした。

Date
Author
エンジニア

今回は、主にウェブサーバー、具体的にはLinuxのSO_REUSEPORT(プログラミング言語としてはC言語)の話題になります。背景として、弊社では、広告配信がいわゆるネイティブアプリケーションであるため、ウェブサーバーの開発を行っているといったことが挙げられます。そもそも今回の記事を書いたきっかけは、弊社でSO_REUSEPORTを使用し始めており、それについて紹介したいと考えたからです。

特にC10K問題については
TheC10kProblem – 「C10K問題」(クライアント1万台問題)とは、ハードウェアの性能上は問題がなくても、あまりにもクライアントの数が多くなるとサーバがパンクする問題のこと

が詳しいので今回は説明を省略します。 また、Linux(正確にはKernel 3.9以降)におけるSO_REUSEPORTについては、
或るプログラマの一生 » Linux Kernel 3.9 の SO_REUSEPORT
linux – Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ? Do they mean the same across all major operating systems? – Stack Overflow

を一読されると概要はつかめるかと思います。ここでいうSO_REUSEPORTは、特に言及が無い限りLinuxのものをさしておりますので、BSD系におけるそれとは異なりますので予めご了承ください。

ウェブサーバーの作成

自社でHTTPを話すアプリケーションを作成する際に、やはり既存のウェブサーバーを参考にするのは非常に容易に思いつく手段です。 弊社では、nginxをリバースプロキシや簡単なソフトウェアバランサとして使用している実績があり、そのパフォーマンス(特にスケーラビリティ)が非常に良いことは実感しています。また、CPU(コア数)だけ設定すればチューニングは不要というようなプログラムを作りたいという希望もあったので、安直ではありますが、自然にepollを使用したevent-drivenなプログラムを作成していこうという方針になりました。 1プロセスあたり複数のリクエストを同時並行的に処理でき、また、ちょうど世の中には libevent のようなライブラリ(HTTPまで実装されている!)があるのも後押しになりました。

スケーラビリティの確保

C10K問題をクリアするというのはNginxという先駆者を参考にしているので当然の話ですが、一方で負荷分散のデザインがなかなか固まりませんでした。 ユーザーからのリクエストをバランシングする方法は実に様々ですが、スケーラビリティを確保するということを念頭に当初思いついた案は次のような物でした。

案1「とにかくみんなacceptする」

細かい点は置いておいて、まず素朴な案としてはとりあえずスレッド(プロセス)ごとに同じソケットを監視してしまえということが思い浮かびます。ロジックとしては以下のような感じです。

socket() bind() listen()して1つだけソケットを作成
スレッド(またはプロセス)を必要なだけ立ち上げる
各々で同じソケットを監視してリクエストを待つ
リクエストが来たらacceptを試みる

図1. みんなacceptしに行くパターンの動作イメージ

上の通りこの案は、実際の動作は無視できるとはいえエラーがたくさん起きるため、人によっては気持ち悪いと感じるかもしれせん。実際acceptが1リクエストにたいして全スレッド(プロセス)分発生するのでオーバーヘッドもあります。逆に利点としてはロジック自体シンプルですし、実際プログラムもシンプルに書けるということがあります。ただし、シンプルといっても同じソケットである必要があるため、既存のシングルスレッドのプログラムを単純に複数立ち上げるだけではできません。

案2「リクエストをacceptするスレッドが一人」

次に思いつくのは、acceptは排他的なので一人だけでやってほかのワーカー(返事を作る人たち)にソケットを渡すという方式です。実はmemcachedがこれで実装されているみたいなのですが、簡単に図にするとこんな感じです。

socket() bind() listen()して1つだけソケットを作成
スレッド(またはプロセス)を必要なだけ立ち上げる
1スレッドだけ着信を待ち受ける。その他はpipeを待つ。
リクエストが来たらacceptして、ソケットをpipe経由でほかのスレッドへ

図2. memcachedっぽい何か

案1と違って、動作上は非常にすっきりしたように見えます。しかしこの実装だと素朴な疑問として、accept担当のスレッドは暇なのかどうかや、ワーカーはコア数分立ち上げればいいのかacceptするスレッドを引いてコア数-1立ち上げるのかという議論もあり、当初の方針である「CPU(コア数)だけ設定すればチューニングは不要」から逸れてしまいます。

案3「平等 (みんなにacceptする機会を与える)」

案1と案2で作ってみたもののやはりぱっとしないので、nginxの実装を調べてみることにします。 すると以下のようにaccept()を各ワーカー間で持ち回りにしていることが分かります。

図3. ランダムにacceptするlockを一定期間保持する

起動後ワーカーが一斉にmutexを獲得しようとします。一定リクエストを処理したらmutexを解放することで、すべてのワーカーがリクエストを分散して処理できるようにしています。 先ほどの案2と違って、ワーカー数=CPU(コア)数で余計な心配がありません。また、ワークロードが不均一な場合には、重たい処理をしているほどmutexを獲得しにいく頻度が減りますので、結果的にうまいこと負荷分散もできているように見えます。 今まで出てきた案の中で一番良さそうかつ実績のあるこの方式ですが、やはりacceptをしに行くスレッドは瞬間的には一人ですので、性能的には案2と大差ないと考えられます。また、何よりも今まででてきた中で最も実装するものが多くなりそうです。

SO_REUSEPORTの台頭

上述の案をためしてみたのですが、(当たり前ですが)案1の「とにかくみんな取りにいく(acceptしにいく)」が非常に簡単かつ速くコードが書けてしまいます。 そして、3案を試しているうちにSO_REUSEPORTがマージされたLinux Kernel 3.9を知ることになります。

Linuxに追加されたSO_REUSEPORTは具体的に何がうれしいか、当該部分(__inet_lookup_listener内)を抜き出してくると

Before (Kernel 3.2)

sk_nulls_for_each_rcu(sk, node, &ilb->head) {
score = compute_score(sk, net, hnum, daddr, dif);
if (score > hiscore) {
result = sk;
hiscore = score;
}
}

SO_REUSEPORTが追加される前は、接続要求があった時にcompute_scoreで受信アドレスを指定しているか等優先度はあるものの、単純にlistenしているソケットを探しているため、このままでは常に同じソケットが選ばれます。

しかしSO_REUSEPORTが追加された3.9以降では以下のように

After (Kernel 3.16)

sk_nulls_for_each_rcu(sk, node, &ilb->head) {
score = compute_score(sk, net, hnum, daddr, dif);
if (score > hiscore) {
result = sk;
hiscore = score;
reuseport = sk->sk_reuseport;
if (reuseport) {
phash = inet_ehashfn(net, daddr, hnum, saddr, sport);
matches = 1;
}
} else if (score == hiscore && reuseport) {
matches++;
if (((u64)phash * matches) >> 32 == 0)
result = sk;
phash = next_pseudo_random32(phash);
}
}

接続要求があった時にlistenしているソケットをラウンドロビンで選んでいることが分かります。 これを採用すると、はじめの素朴な案1並みにシンプルなプログラムが書けます。

図4. SO_REUSEPORTを利用したときの動作イメージ

また、既存のプログラムを活用するという意味では、SO_REUSEPORTをセットして複数立ち上げるだけで簡単なロードバランシングができてしまいます。

今回の記事は以上になります。 普段の仕事で使っているものの感想も幾分混じっている記事で、イマイチだったかもしれませんが、感想やご指摘いただけますと今後の参考にさせて頂きたいと思います。

それでは、また次回をご期待ください。

Date
Author
エンジニア

Hello, World!

ジーニーでエンジニアをやっているxxjです。 弊社もエンジニアがブログを書くという試みを始めて行きたいと思います。 中身についてはまだ未定な部分も多いのですが、できれば以下の2点を満たすものを毎回執筆担当を変えてやっていきたいと思います。

  • 使っている人は少ないが、重要だと考えられる技術など
  • 日本語の情報が少ないもの
  • 弊社の情報発信という側面もありますが、読んでいる方に少しでも有意義な話題を書いていきたいです。 よろしくお願いします!

    Date
    Author
    エンジニア
    Back to top