フロムスクラッチ開発者ブログ

from scratch Engineers' Blog

Apache ZooKeeperの内部解析してみる vol.1 〜概要とデータノード編〜

こんにちは、fukuです。

フロムスクラッチでは主にアーキテクチャー周りの仕事に従事しています。

今回から数回に分けてApache ZooKeeper(以下ZooKeeper)について記事を書いて行こうと思います。ゆくゆくはソースコードレベルで解説を行なっていけたら良いかなと思っています(不安...)。1回目の今回はZooKeeperの紹介を行なっていきます。

昨今ではApache Hadoopをはじめとし、さまざまな分散処理フレームワークのOSSがありますが、そのいくつかの分散処理のシステム管理はZooKeeperを用いて行われています。

ZooKeeperとは

f:id:fuku_dw:20171227180655p:plain

分散処理のアプリケーションではアプリケーションのロジックだけでなく、分散処理されるアプリケーションプロセス同士を協調させながら処理を行うことが重要になってきます。

ZooKeeperではそのような分散処理における協調動作を行うための分散コーディネーションサービスを提供します。

ZooKeeperはApacheのトッププロジェクトの1つであり、元々はGoogleのChubbyを元にYahooによって開発が行われました。

ZooKeeperではアプリケーションに対してAPIを提供して、APIを通して分散システムにおける構成管理や、リーダー選出、分散ロック、メッセージキューなどの用途に利用されます。

分散システムの制御

ここではZooKeeperを離れて、少し 分散システムの制御について記述します。下記の図のような一般的なHadoopなどのマスタ・ワーカの分散システムにては、以下のような事に関しての問題を考える必要があります。

f:id:fuku_dw:20171227190148p:plain

マスタ障害

マスタに障害がおこると、ワーカ対するタスクの割り当てなどが行えなくなります。マスタに障害が発生した場合には、バックアップのマスタが処理を元のマスタの役割を引き継ぐ必要があります。さらにクラスタ状態の障害前の状態に戻すためには、元のマスタの状態を知る必要があります。当然、障害がおきたマスタ上でデータを管理していると、元のマスタの状態を知ることができなくなってしまいます。

ワーカ障害

ワーカの障害では、そのワーカに割り当てられているタスクに実行が完了しなくなります。そのためマスタはワーカの障害を検知して、障害がおこったワーカに割り当てていたタスクを、別のワーカに再度割り当てる必要があります。

また部分的にタスクが実行されていたりしていると、ワーカの障害がおこった場合に、部分的に実行された内容に関するリカバリなどを考慮する必要がある場合も考えられます。

通信障害

通信障害ではネットワークが分断されてワーカが マスタから切り離されることが考えられます。この場合に問題になるのはロックなどの同期処理への影響を考える必要があることです。分断されたワーカが何かしらの資源に対する排他ロックを行なっていた場合には対象のリソースが永久に解放されなくなってしまうかもしれません。

 これらの分散システムにおける問題を扱うために ZooKeeperではさまざまな機能を提供しています。次はZooKeeperの基本的な機能について見ていきましょう。

ZooKeeperの基本

ZooKeeperではデータツリーと呼ばれるファイルシステムのような階層的なツリー構造を構成しています。ツリー構造の各ノードはznodeと呼ばれ、各znodeノードの名前は、スラッシュ(/)で区切られるパス要素によって識別されます。

以下にデータツリーの例を示します。図からわかるように一般的な木構造のデータ構造をとっており、ルートのznodeは"/app1"と"/app2"の2つの子ノードを持ってることがわかります。

f:id:fuku_dw:20171227165956p:plain

さらに各znodeにはデータを格納することができ、データはバイト配列として格納されます。そのため多くのアプリケーションではProtocol BuffersやMessage Packなどのシリアライズ を行うためのパッケージを利用してデータを格納することが多いです。

znodeのモード

znodeにはモードと呼ばれる、znodeの振る舞いを変える機構があります。代表的なモードとして以下の4つがあります。

  • PERSISTENT
  • EPHEMERAL
  • CONTAINER
  • PERSISTENT_TTL

ここではそれぞれのモードの特徴について見ていきましょう。

PERSISTENT

PERSISTENTモードは永続化されるノードです。PERSISTENTなノードを削除する場合にはノードを削除するAPIを実行して、明示的に削除を行うしかありません。

PERSISTENTなノードはアプリケーションに関わるデータを保持して、ノードを作成したプロセスがクラッシュ・終了した場合でもデータを保持しなければならない場合などに用いられます。

EPHEMERAL

EPHEMERALモードは一時的なノードとして作成されます。ノードを作成したクライアントがクラッシュ(セッションが切れる)した場合や、ZooKeeperへのセッションをクローズしたりした場合に自動的に削除されます。

EPHEMERALなノードはノードを作成したセッションが維持されて間だけ存在するアプリケーション情報データを格納する場合に利用します。具体的にはマスタ・ワーカアーキテクチャ型のシステムにおけるマスタ情報などです。マスタはEPHEMERALなノードを作成しておくことで、マスタの生存を対象のノードが存在するかどうかのチェックを行うことで行うことができます。

CONTAINER

CONTAINERモードはバージョン3.5.1から提供されており、ガベージコレクションの機能をもつノードとなります。具体的にはCONTAINERなノードの子ノードがなくなると、ZooKeeperによって対象ノードは自動的に削除されます。

クラスターに参加するノード情報をCONTAINERなノードの子のEPHEMERAノードとして管理しておき、対象のクタスター全体を終了した場合などに、クラスタ情報全体を削除するといった利用方法が考えられます。

PERSISTENT_TTL

PERSISTENT_TTLモードはバージョン3.5.3から提供されており、期限付きの一時ノードとして作成されます。ノードに設定された期限がきた場合に自動的に削除されます(子ノードがない場合などの制限はあります)。

TTLなノードを利用することによって、タイムアウトをもつセッション情報を管理したりすることができます。

上記のモードを上手に使い分けながら、分散システムの状態を管理するのは、ZooKeeperを利用するアプリケーションの役割となります。

znodeの監視と通知

znodeの存在の有無や、データの変更などデータツリーの状態をチェックするために、毎回クライアントがアクセスを行うことを考えると、ZooKeeperに対して負荷がかかることが考えられます。

そのためZooKeeperではクライアントが状態をポーリングしなくてもよいように、データツリーの変更をクライアントに対して通知する機構があります。クライアントは特定のznodeに対しての変更などを通知してもらうために、監視(Watc

her)の設定を行う必要があります。ここで注意しなければならないのは、設定された監視は1度しか通知が行われないことです。そのため何度も通知を受けたい場合などは、通知を受け取ったのちに新しい監視情報を登録する必要があります。

f:id:fuku_dw:20171227185311p:plain

ここで不安になるのが監視を設定して通知をされて時に、再度監視を設定する間に端子対象のznodeに対して変更などがあった場合です。

f:id:fuku_dw:20171227185314p:plain

監視の設定では、監視を設定した時のznodeの状態も取得できるため、上記のようなパターンでは2度目の監視の設定の時に取得できるznodeの状態を見ることによって、対象のznodeの状態が変更されているかをチェックすることができます。

おわりに

今回はZooKeeperの概要から、データノードに関しての説明を行いました。ZooKeeperではあくまで分散システムの強調動作を実現するための基本機能の実装しか行われていないので、制御のためのロジックを実装するのはアプリケーション側の役割となります。

次回は実際にZooKeeperを動かしながらZooKeeperに対して、できることを紹介していく予定です。

ではでは...

参考文献: ZooKeeperによる分散システム管理(2014/10/8 オライリージャパン)

マイクロサービスアーキテクチャと技術選定

こんにちは。

フロムスクラッチでエンジニアをしている原口と申します。

普段はアーキテクトとしてスクラムチームのサポートを行ったり、それ以外にもAWS EMR周りの管理を担当したりしています。

先日、フロムスクラッチ Advent Calendar 2017 - Qiitaにて、AWS EMRのコストと安定稼働の両立に関する記事を執筆させていただきました。もしよろしければそちらもご覧ください。

【AWS】【EMR】スポットインスタンスでの安定稼働を目指して(1/3):スポットインスタンスとは - Qiita

【AWS】【EMR】スポットインスタンスでの安定稼働を目指して(2/3):インスタンスフリートを考える - Qiita

【AWS】【EMR】スポットインスタンスでの安定稼働を目指して(3/3):処理特性と設定指針 - Qiita

 

さて、はじめてはてなブログで執筆するブログの記事、どうしようかなと思ったのですが、まあ・・・初回は真面目に書きましょうかね?

ということで、今回取り上げるのはマイクロサービスアーキテクチャと技術選定というお題でブログを書こうと思います。

 

マイクロサービスアーキテクチャとは

マイクロサービスアーキテクチャについて、ここで改めて細かく言及するつもりはありません(章末にいくつかのリンクを記載しておきます。)が、

  • アプリケーションのコンポーネントを小さな単位に分割する
  • それぞれのコンポーネントは極力疎結合の状態にし、コンポーネント間のインタラクションはAPIを通じてやりとりすることで実現する

という特徴があります。

f:id:shun-haraguchi:20180103225558p:plain

マイクロサービスアーキテクチャの図例

(出典:Microsoft Azure アーキテクチャスタイル https://docs.microsoft.com/ja-jp/azure/architecture/guide/architecture-styles/microservices

そうすることによって、例えばアプリケーションの改修を行う際にその影響範囲を小さくすることができたり、障害が発生した場合の影響範囲を小さくすることができるというメリットがあります。逆にデメリットとしては、インフラ面が細かい単位で分断されるので、管理が煩雑になることが挙げられるでしょう。

フロムスクラッチのプロダクトであるb→dash 2.0においても、このマイクロサービスアーキテクチャを採用しています。フロムスクラッチでは複数のスクラムチームで、おおよそ2週間スパンでのアジャイル開発を行っているため、マイクロサービスアーキテクチャのメリットが開発の効率化に繋がっています。

マイクロサービスアーキテクチャにおける技術選定

フロムスクラッチの各コンポーネントは、例えば"分析機能"や"レコメンド機能"といった、それ単独でお客様に価値を提供するサービスの単位で分割されています。それぞれのコンポーネント内はそれぞれのサービスごとに設計・開発していますが、プログラミング言語にはWeb系にRails+Vue.js、バッチ系にJavaやScalaなど、おおよそお決まりのパターンがあります。

 

話は少し変わりますが、私は昨年、米IBMが毎年ラスベガスで開催しているイベントInterConnect 2017に参加しました。その中で印象に残ったセッションの1つに、「Java, Node.js and Swift: Which, When, and Why?」にというセッションがありました。

このセッションはマイクロサービスモデルにおいて、どういう時にどの言語(ここではJava, Node, or Swift)を選定するべきかという内容のセッションで、ざっくり内容を述べるならば、

せっかくコンポーネント間が疎結合で、かつAPIでやりとりするのであれば、コンポーネントごとにその特性に合わせた言語選定をすれば良いのではないか。それは例えば、

  • ファイルI/OやDBとのやりとりが中心になるコンポーネント:Java
  • 外部サービスとのやりとりなどでJSONの変換が多く発生するコンポーネント:Node

といったように。(注:セッション内では言語のスペック比較を示して上記の結論を出していましたが、ここではそこまでは紹介しません。)

このセッションではアプリケーションの言語選定のみを考えていましたが、もっと攻めるならば、例えば外部サービス:メール配信サービスをスループット重視なのか価格重視なのかをサービスによって変えてみたり、といったことなど、言語に限らずもっと様々な範囲で活用できる話だと思っています。もっとも、上記のセッションでは技術的な観点だけで考察しており、その他の要素(例えば、組織の柔軟性や、コスト面などの組織やビジネスの観点)は一切考えていないので、現実的にはもっと様々な観点で判断する必要があるでしょうが・・・。

ただ、マイクロサービスアーキテクチャによって、これまでにはできなかった組み合わせや設計も実現できる可能性がある。だから、固定観念にとらわれず、もっと大胆に色んなことを考えることができるのではないかな、と思っています。

 

この章の冒頭でも述べましたが、フロムスクラッチのb→dashではおおよそお決まりのパターンがあります。それにより、必要なスキルセットをコンポーネント間である程度固定することによって、組織の柔軟性を確保している面があります。

そのため、新しい技術要素を取り入れるということは、そういった流動性を一時的に損なってしまったり(その技術要素のスキルを持った人に依存してしまう)、管理が煩雑になってしまうというデメリットもあります。

しかし、私はマイクロサービスアーキテクチャにはまだまだ可能性が眠っていると思っています。なので、アーキテクトとして固定観念にとらわれることなく大胆な発想で様々な選択肢を、しかし冷静に客観的にそれらの選択肢を評価して、その上で良いと思うものはしっかりと取り入れていきたいと思っています。

まだまだb→dashは発展途上。これからも進化していきます。もちろん使っている技術も、私たちエンジニアも。

 

今後のフロムスクラッチに益々ご期待いただければ幸いです! 

それでは、ごきげんよう!

 

参考文献

Techブログ始めます

こんにちは。フロムスクラッチでCTOをしている井戸端といいます。

この度、フロムスクラッチでTechブログを始めることになりました。
フロムスクラッチの持つ技術や開発の様子を紹介していくので、よろしくお願いします。

今日はフロムスクラッチという会社と、その開発組織について簡単に紹介したいと思います。

フロムスクラッチとは

フロムスクラッチは、ビッグデータ×人工知能を主軸に事業を展開するデータテクノロジーカンパニーです。現在は、マーケティングテクノロジー領域におけるソリューションである「b→dash」の開発・提供を中心に事業を展開しています。今後は強みである、データ統合技術、データ高速処理技術、人工知能技術を競争力の源泉とし、様々な産業領域と地域での事業展開を予定しています。 

社名である“フロムスクラッチ”は「常に0から1=新たな価値創造をし続ける」という思いが込められています。ただ単にちょっと便利なモノを作るのではなく、テクノロジーによって世の中のあり方から変革し、価値観そのものを変えるようなサービスを創り出すことを目指しています。

フロムスクラッチの開発組織

フロムスクラッチは東京以外に、福岡、ベトナムに開発の拠点を有しており、エンジニアに加えて、プロダクトマネージャー、UIUXデザイナー、QAなども含めると、60人近い人数が開発に携わっていることになります。2017年よりアジャイル開発の手法の1つであるスクラムをベースとした開発手法を採用しており、約2週間のスプリントを1つの単位として、柔軟に計画を見直しながらスピーディーに開発を進めていくことを意識しています。

エンジニアの種別について

フロムスクラッチでは、フロントエンジニア、サーバーサイドエンジニア...etcのように、エンジニアの種別をはっきりと分けてはいませんが、業務上の役割分担として開発チーム、アーキテクチャチーム、インフラチームの大きく3つに分かれています。

開発チーム
開発チームのエンジニアは実際のプロダクトの開発に専念するエンジニアで、b→dashのアプリケーション毎にチームが分かれています。スプリント毎にプロダクトマネージャーと話し合い、スプリントのゴールを定めて開発を進めていきます。

アーキテクチャチーム
アーキテクチャチームのエンジニアは、新機能のアーキテクチャの設計や、共通機能の実装、ライブラリの開発が主な役割となります。その他、開発チームが実装に悩んだときや、開発チームだけでは解決できない問題が生じた場合に、遊撃的に開発チームに入って問題を突破して開発を進めることも行なっています。

インフラチーム
インフラチームのエンジニアは、サービスのインフラおよび運用監視システムの構築と運用を行います。CIを整備したり、デプロイの仕組みを整えたり、運用や監視の方法を見直したりしながら、如何に効率的に安定したサービスを提供していけるかを追求しています。

フロムスクラッチのエンジニア

フロムスクラッチのエンジニアに求めることは大きく3つあります。

サービスとしての価値を意識すること
フロムスクラッチでは、"ユーザー"と"ビジネス"の観点で自分たちが開発しているサービスの価値を意識するようにしています。いくら技術的に優れていても、利用するユーザーにとって価値あるものでなければ何の意味もありませんし、ビジネス的に優れていなければ世の中に価値を提供し続けていくことができず、世の中に変革をもたらすことができません。"技術"だけでなく、"ユーザー"、"ビジネス"の観点も兼ね備えたエンジニアであることを常に求めています。

フルスタックであること
フロムスクラッチでは前述のとおりエンジニアの技術領域を明確に区別していません。フロントエンドが得意、サーバーサイドが得意など、人によって得意不得意はあれど、基本的に全員何でもやる(できるようになる)ことを前提としています。
b→dashには10近い数のアプリケーションが存在しており、且つ種類としても多様で、アプリケーション毎に採用している技術も異なれば、システムとしての特性も異なるため、求められるものが変わってきます。全員がフルスタックであることで、開発としての効率が良い上、いざとなったらお互いにカバーに入れる為、状況に応じて柔軟な対応を取ることができます。これによって、100人にも満たない人数でこれだけの規模・種類のサービスを素早く開発していくことが可能となっています。
エンジニアにとっては非常に大変ではありますが、"開発すること"ではなく、フロムスクラッチの提唱する、"価値あるものを創り出す"、"世の中に変革をもたらす"というミッションに共感しているメンバーが集まっているため、大変さ以上に「色々なことができて面白い」という思いで日々開発に取組んでいます。

チームで成果が出せること
個人としてハイパフォーマンスを出すこと以上に、チームとして成果が出せることを重視しています。開発はチームスポーツのようなものだと思っており、1人の優れたプレーヤーがいても、プレーヤー同士がうまく連携しなくても勝つことができません。個人として成果を出しつつ、チームでも成果を残せる人間を評価しています。 その為には、"ミッション理解"、"コミュニケーション力"が必須だと考えています。まずはチームのミッションをしっかりと理解し、その為に自分に何ができるのかを考えられること。更にお互いの役割を理解し適切な情報伝達を通して、相互に連携して動けること。これらができて初めてチームとして成果を出すことができると考えています。

最後に

今回は最初ということでフロムスクラッチの組織的な側面を紹介しましたが、今後は技術的な取り組みやデータマーケティングについての知見をこのブログを通して紹介していけたらいいなと思っています。
技術的な面では、Javascript、Ruby、Scala、Java、Go等、フロムスクラッチで採用している言語に関してや、BigData処理の要であるHadoop、Spark、Hive、Presto等といった分散処理技術、その他、ストリーミング技術、人工知能技術についても紹介していく予定です。乞うご期待ください!