個人利用から大規模開発までConoHaで始めるクラウド開発入門

第4回実際の業務開発におけるConoHaの活用例

ConoHaでお手軽Hadoop&Spark開発

筆者が所属している次世代システム研究室では、Hadoopを活用したビッグデータシステムを開発しています。以前の案件では、弊社のサービスであるGMOアプリクラウドを使用していましたが、新規案件では新しくなったConoHaを使用し、Hadoopクラスタの構築と周辺のアプリケーション開発を行いました。以下、その設計と料金の具体的な事例を紹介したいと思います。

ConoHaで構築するHadoopクラスタのインスタンス構成と料金

試験などのための開発環境として、図1に示す構成を設計しました。Hadoopディストリビューションは、Hortonworks社のHortonworks Data Platform(HDP)2.3を使用しています。HDPにあらかじめ用意されているAmbari、YARN、HBase、Hive、SparkなどのHadoopエコシステムをフル活用しています表1⁠。

図1 インスタンスの図
図1 インスタンスの図
表1 HDPに用意されているHadoopエコシステム
AmbariHDPのHadoop管理システム
YARNHadoopクラスタ上で動作するソフトウェアのスケジュール管理、リソース管理を行う
HBaseGoogleのBigTableをモデルとした列指向の分散データベース
HiveHadoopの上に構築されたデータベース。HiveQLというSQLに似たクエリを使用できる
Sparkインメモリで分散処理をするソフトウェア。リアルタイムストリーミング処理が行えるSparkStreaming、SQLが実行できるSpark SQLがある

リージョンは「日本⁠⁠、OSはゲートウェイがCentOS 7.1、それ以外はCentOS 6.6を使用します。Hadoopのノード系インスタンスにはメモリ8GBは必要です。インスタンス14台、ロードバランサ1台で、合計67,640円でHadoopクラスタを使用したシステムがConoHaで構築できます表2⁠。Hadoopクラスタを使ったサービスを月額7万以下で作れるのは割安だと思います。ConoHaは転送料金など使用量に関する追加料金は発生しないので、この値段が固定の月額料金となります。

表2 Hadoopクラスタを使用したシステムの見積り料金
マシン名役割CPUメモリSSD月額料金
gatewayインターネットから接続できるSSHサーバ2コア1GB50GB900円
ci_ambariHDPのHadoop管理システムAmbariとデプロイサーバ4コア4GB50GB3,420円
master_node1~3Hadoopのマスタノード6コア8GB50GB6,670円×3
slave_node1~3Hadoopのスレーブノード6コア8GB550GB11,170円×3
dev-web1、2Nginxサーバ2コア1GB50GB900円×2
dev-ap1、2HTTPアプリケーションサーバ3コア2GB50GB1,750円×2
dev-batch1、2集計バッチサーバ(spark-submit)3コア2GB50GB1,750円×2
ロードバランサ1台Webサーバで使用1,000円
合計67,640円

システム構築作業の際にインスタンスを作って壊すことも何度かはあるため、プラス数千円が予算を通す際の値段になるでしょう。請求は1時間単位で、明細書に詳細に記載されます。

HadoopクラスタでのSparkの活用

構築したクラスタで、spark-shellのYARNクライアントモードを試してみます(YARNを使ってSparkの処理をクラスタで分散させます⁠⁠。レコメンドの元ネタとなるデータとしてWebページのアクセスログを解析し、⁠ユーザごとの閲覧Webページの一覧」を算出するためSpark SQLを利用します。

1.ダミーデータの作成(1,000万レコード)

データベーステーブルの元となるアクセスログのダミーデータ(TSV)をPerlで作成しますリスト1⁠。

リスト1 ダミーデータを作成するPerlスクリプト
#!/usr/bin/perl
for ($i=0; $i < $ARGV[0]; $i++) {
 $user_id = "uid_".int(rand ($ARGV[1]));
 $page_url = "http://maru/page/".int(rand $ARGV[2]);
 print $user_id."\t".$page_url."\n";
}

あるサイトに1万ページのURLがあり、そのサイトにアクセスした100万人のユーザが合計1,000万アクセスしたと仮定し、ログ(TSV)を生成します。

[hive@slave_node1]$./dummy.pl 10000000 1000000 10000 > dummy10m.tsv

生成したログデータは次のようなものです。

uid_1    http://maru/page/1
uid_1    http://maru/page/2
uid_2    http://maru/page/3
uid_3    http://maru/page/4
uid_3    http://maru/page/5

このデータをリスト2のようなデータ形式にSpark SQLで変換してみます。

リスト2 Spark SQLで変換したデータ
uid_1    http://maru/page/1    http://maru/page/2
uid_2    http://maru/page/3
uid_3    http://maru/page/4    http://maru/page/5

2.テーブルにデータ(TSV)を登録

spark-sqlを起動し、データベースとテーブルを作成します。

spark-sql>
create database noda_conoha_sd4;
use noda_conoha_sd4;

CREATE TABLE raw_log_data (
  uid STRING,
  url STRING
)
ROW FORMAT DELIMITED
  FIELDS TERMINATED BY '\t'
  LINES TERMINATED BY '\n'
STORED AS TEXTFILE;

CREATE TABLE log_data (
  uid STRING,
  url STRING
)
STORED AS ORC tblproperties ("orc.compress"="SNAPPY");

TSVファイルをTEXTFILEフォーマットテーブルにロードしたあと、処理が最適化されたORCフォーマットテーブルに変換します。

spark-sql>
LOAD DATA LOCAL INPATH "./dummy10m.tsv" into table raw_log_data;
INSERT OVERWRITE TABLE log_data select uid, url from raw_log_data;

select * from log_data limit 10;
uid_387616	http://maru/page/2197
uid_734748	http://maru/page/6714
uid_982660	http://maru/page/6854

3.spark-shellのYARNクライアントモード

spark-shellをYARNクライアントモードで起動し、シェルで実行するSparkの処理をHadoopクラスタで分散させます。

[hive@slave_node1]$ spark-shell --master yarn-client
scala>

 Hiveテーブルを扱うため、Hiveのパッケージをインポート
import org.apache.spark.sql.hive.HiveContext

SparkContextでspark-shellを起動すると、scは自動的に作られる
val hiveCtx = new HiveContext(sc)

HiveQLでSQLを実行
val rows = hiveCtx.sql("select uid, url from noda_conoha_sd4.log_data")

重複行を削除
val rdd = rows.distinct.rdd

map形式に変換 (ユーザID => ページURL)
val pairs = rdd.map( u => (u{0}.asInstanceOf[String], u{1}.asInstanceOf[String]))

ユーザIDをキーにデータを集約する (ユーザID => ページ  URL1, ページURL2)
val group = pairs.groupByKey()

データを10個取り出す
group.take(10)

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

Array[(String, Iterable[String])] =
Array((uid_203708,CompactBuffer(http://maru/page/1909,
http://maru/page/4316),(uid_66952,CompactBuffer(http://maru/page/3593,http://maru/page/3497),
 ……略……

イメージ保存機能を利用したサーバのチューニング

今回は、ConoHaが持つイメージ保存機能の活用方法も紹介しておきます。ここで取り上げるのは、Webサーバのチューニングの事例です。

Nginxの設定(nginx.conf)を変更してチューニングをしたかったのですが、あいにくほかのメンバーが試験で使用中のため、気軽にWebサーバの設定を変更できない状況でした(設定の変更によってNginxの動作に不具合が生じ、バックエンドの処理で試験データが破損するのを避けたかったからです⁠⁠。そこで、ConoHaのイメージ保存機能を使ってWebサーバのインスタンスをコピーし、新たに検証用のWebサーバを構築してチューニングをしました。

図2は、そのチューニングの手順の全体像を示したものです。以下、順を追って説明します。

図2 チューニング全体のイメージ図
図2 チューニング全体のイメージ図
1.イメージを保存する

ConoHaのインスタンスは、起動中はイメージを保存できないため、いったんWEB1を停止してからイメージを保存します。イメージのネームタグは「WEB1_COPY」とします図3⁠。

図3 インスタンスのイメージの作成
図3 インスタンスのイメージの作成
2.イメージから新規インスタンスを構築する

WEB1を再起動し、試験で使用可能な状態に戻します。次に、メニューの「サーバー追加」からイメージタイプ「保存イメージ」を選択し、ネームタグから「WEB1_COPY」を選択して、新規インスタンスをWEB3として1台構築します図4⁠。

図4 イメージを元にインスタンスを構築
図4 イメージを元にインスタンスを構築
3.Nginxをチューニングする

WEB3単体でNginxをチューニングします。httperfなどでHTTPのパフォーマンスを見ながら、nginx.confの最適値を算出します。

[noda@gateway]# httperf --server=WEB3のIP --port=80 --uri=/index.html --rate 5000 --num-conn 250000 --num-call 5 --timeout 5
4.チューニングしたインスタンスをコピーする

WEB3のチューニングが終わったらWEB3を停止します。WEB3の保存イメージを作成し、そのイメージを使用してさらにインスタンスWEB4を1台構築します。ロードバランサ経由でのHTTPアクセスの動作を確認するため、ロードバランサ2を追加します。

ロードバランサ2をWEB3とWEB4に接続し、ロードバランサ経由でのチューニングと動作確認を行います。結果に問題がなければ、夜間などWebインスタンスが使用されていないときに、ロードバランサ1に紐付けているWEB1とWEB2を、それぞれWEB3とWEB4に変更します。インスタンスを残しておくと料金が発生するため、WEB1、WEB2、ロードバランサ2は削除します[1]⁠。

まとめ

今回は、実際の業務でConoHaを使った事例を紹介しました。月額7万円以下でSparkも使えるHadoopクラスタが構築できるのは魅力です。また、イメージ保存機能を利用したサーバのチューニングについてイメージをつかんでいただけたら幸いです。皆さんもぜひ、業務での開発にConoHaを活かしてください。

おすすめ記事

記事・ニュース一覧