2013年5月28日火曜日

Fluentdってなんじゃ?(設定ファイルをリモートから読み込む)

fluentdのドキュメントに以下のような記載がありました。

Configuration File - (3) Include Directive
# absolute path
include /path/to/config.conf

# if using a relative path, the directive will use 
# the dirname of this config file to expand the path
include extra.conf

# glob match pattern
include config.d/*.conf

# http
include http://example.com/fluent.conf

最後の行、、、HTTPから設定ファイルを取得してインクルードできるみたいです。

ということで試してみました。

common.conf
<source>
  type tail
  format apache
  pos_file /var/log/td-agent/httpd-access.log.pos
  path /var/log/httpd/access_log
  tag apache.access
</source>

<match apache.access>
  type s3

  aws_key_id xxxxxxxxxxxxxxxxxxx 
  aws_sec_key yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
  s3_bucket hoge-bucket
  path logs/
  buffer_path /var/log/fluent/s3
  flush_interval 10s 
</match>

これをS3にアップロードしてWEBホスティングしてみます。


そして、EC2では以下のように設定します。

/etc/td-agent/td-agent.conf
include http://s3-ap-northeast-1.amazonaws.com/hoge-bucket/conf/fluentd/common.conf
# /etc/init.d/td-agent start


httpdのコンテンツにアクセスしてしばらくたつと、、、


無事出力されていました!

これの何がいいかというと、

  • 各サーバーに共通の設定ファイルなどを外部化しておき、一括変更をかけられる (再起動は必要ですが、定期的に再起動をかけるようにしておくという手もあります)
  • いっそ全設定を外出しして完全に外部で管理する

などが可能になります。

以上です。

2013年5月25日土曜日

spiderってなんじゃ?(spider自身の冗長化)

いままではSpiderがひとつに対して、データノードが複数ある構成をとってきましたが、実戦ではSpiderが単一障害点になるため好ましくありません。ここではSpider自身の冗長化を行なってみます。

いままでのSpider x 1 + mroonga x 2 の構成に対してデータを入れ込むためのappノードを用意します。

SpoderのSPOF





mroonga

 CREATE TABLE doc (
  id INT PRIMARY KEY AUTO_INCREMENT,
  created_at datetime,
  content text,
  FULLTEXT INDEX (content)
 ) ENGINE = mroonga; 


spider

 CREATE TABLE doc (
  id BIGINT PRIMARY KEY AUTO_INCREMENT,
  created_at datetime,
  content text,
  FULLTEXT INDEX (content)
 ) ENGINE = spider CHARSET utf8
 CONNECTION ' table "doc", user "memorycraft_user", password "memorycraft_pass" '
 PARTITION BY KEY() (
  PARTITION db1 comment 'host "10.0.1.136", port "3306"',
  PARTITION db2 comment 'host "10.0.1.137", port "3306"'
 ); 

app

# yum install -y php php-mbstring php-pdo php-mysql
$ vim links.php
<?php

//ランダム文字列
function getRandomString($size = 8){
    $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    mt_srand();
    $char = "";
    for($i = 0; $i < $size; $i++) {
        $char .= $chars{mt_rand(0, strlen($chars) - 1)};
    }
    return $char;
}

//XMLテンプレート
$tmpl =<<< END
<?xml version="1.0" encoding="UTF-8" ?>
<data>
  <info>
    <datetime>%s</datetime>
    <address>%s</address>
    <content>%s</content>
  </info>
</data>
END;

//XMLテンプレートに流しこむcontent要素の内容を読み込む
$contents = array();
for($i=0;$i<10;$i++){
  $contents[] = file_get_contents(dirname(__FILE__)."/dummy".$i.".txt");
}

//spiderホストは引数から取得する
$host = $argv[1];
//タイムゾーン
date_default_timezone_set('Asia/Tokyo');

//無限ループ
while(true){
  //XMLテンプレートに各要素を割り当てる
  $xml = sprintf($tmpl, date('Y/m/d H:i:s'), getRandomString(), $contents[rand(0,9)]);
  echo ".";
  //DB接続
  $pdo = new PDO(
    "mysql:dbname=memorycraft;host=$host;",
    "memorycraft_user",
    "memorycraft_pass",
    array(
     PDO::MYSQL_ATTR_INIT_COMMAND => "SET CHARACTER SET `utf8`"
   ));
  $pdo->query("SET NAMES utf8;");
  //投入
  $st = $pdo->prepare("INSERT INTO doc VALUES(NULL,NOW(),?);");
  $rslt = $st->execute(array($xml));
}
?>
実行します
$ php links.php 10.0.1.20
.......................................


Spiderノードで投入されていることを確認します。

mysql> select id, created_at from doc limit 10;
+------+---------------------+
| id   | created_at          |
+------+---------------------+
|    1 | 2013-05-25 11:27:47 | |    2 | 2013-05-25 11:27:47 | |    3 | 2013-05-25 11:27:47 | |    4 | 2013-05-25 11:27:47 | |    5 | 2013-05-25 11:27:47 | |    6 | 2013-05-25 11:27:48 | |    7 | 2013-05-25 11:27:48 | |    8 | 2013-05-25 11:27:48 | |    9 | 2013-05-25 11:27:48 | |   10 | 2013-05-25 11:27:48 | +------+---------------------+ 10 rows in set (0.06 sec)


これで、spider x 1 + mroonga x 2 + app x 1になりました。


Spiderの冗長化


次は、Spider x 2 + mroonga x 2 + internal ELB + app x 4 にしてみます。




Spiderノードをもう1台(spider2)追加します。

テーブルはspider1と同じ内容にします。
/etc/my.cnfでauto_increment_increment = 100でoffsetを1,2でずらします。
これについては、別の記事で触れています。

mysqlってなんじゃ?(マルチマスタでauto_increment)
http://memocra.blogspot.jp/2013/05/mysqlautoincrement.html

また、spiderを複数にした場合、appからの接続は1つにまとめます。
Proxy系のソフトウェアを入れるのも1つの方法ですが、ここでは内部ELBを利用してみます。

ヘルスチェックは3306ではなく別のポート経由でMySQL監視プロセスに接続スべきですが、ここではとりいそぎhttpdを立ちあげ80番に対してヘルスチェックします。


それではappで投入プログラムを実行します。
対象のホストは内部ELBのDNSNameになります。

$ php links.php internal-spider-2040122974.ap-northeast-1.elb.amazonaws.com
........................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................


spider1でデータを見てみます。

mysql> select id, created_at from doc limit 20;
+------+---------------------+
| id   | created_at          |
+------+---------------------+
|    1 | 2013-05-25 11:27:47 |
|  101 | 2013-05-25 11:27:47 |
|  201 | 2013-05-25 11:27:47 |
|  202 | 2013-05-25 11:27:47 |
|  601 | 2013-05-25 11:27:47 |
|  701 | 2013-05-25 11:27:48 |
| 1101 | 2013-05-25 11:27:48 |
| 1201 | 2013-05-25 11:27:48 |
| 1601 | 2013-05-25 11:27:48 |
| 1701 | 2013-05-25 11:27:48 |
| 2101 | 2013-05-25 11:27:49 |
| 2201 | 2013-05-25 11:27:49 |
| 2301 | 2013-05-25 11:27:49 |
| 2601 | 2013-05-25 11:27:49 |
| 2701 | 2013-05-25 11:27:49 |
| 2802 | 2013-05-25 11:27:49 |
| 3101 | 2013-05-25 11:27:49 |
| 3201 | 2013-05-25 11:27:49 |
| 3301 | 2013-05-25 11:27:49 |
| 3601 | 2013-05-25 11:27:50 |
+------+---------------------+

mysql> select count(*) from doc;
+----------+
| count(*) |
+----------+
|   111433 |
+----------+


順調に入っていってるみたいです。
あとはSpiderノードを必要に応じて追加していき、my.cnfでoffsetをずらして起動するだけです。
offsetずらしの処理はcloud-initなどで行うと、AutoScalingすることもできそうです。

今回は以上です。




mysqlってなんじゃ?(マルチマスタでauto_increment)

MySQLでマルチマスタやシャーディングなどを行った場合、auto_incrementを使いたい場合があります。

たとえばspiderだとすると、複数台のSpiderノードを経由してデータが投入されると、データノードでauto_increment値が競合してしまうことがあるため、auto_incrementのオフセットをspiderノードごとにずらします。

spider1
/etc/my.cnf
------
[mysqld]
auto_increment_increment = 100
auto_increment_offset = 1


spider2
/etc/my.cnf
------
[mysqld]
auto_increment_increment = 100
auto_increment_offset = 2


auto_increment_incrementはカウントアップされる単位です。上の例では100ずつ増えていきます。
auto_increment_offsetはauto_incrementのスタート時点の値です。

これによって、各spiderノードのauto_increment値は以下のように増えていきます。

spider1
1
101
201
301
401
.....
123401

spider2
2
102
202
302
402
....
123402

つまり3桁目以上は全体で同じ値をカウントアップしていきますが、下2桁は重複しなくなります。

これを元に投入されたデータはspider上で抽出すると以下のようになります。

1
2
101
102
201
202
301
302
401
402
.....
123401
123402

随分値を飛ばしているように感じますが、ビットずらしのような感覚でとらえれば違和感はなくなると思います。そして、この場合は、Spiderノードを99台まで増やしても値が重複しません。
将来的に何台まで増えるかわからない場合はこのようにするとよさそうです。

以上です。

2013年5月22日水曜日

jqってなんじゃ?(containsで簡単APIテスト)

jqはsedのjson版のようなコマンドラインツールで、jsonデータをフィルタしたり切り取ったり整形したりが簡単にできます。

aws界隈ではaws cliがjsonを返すことで話題になったようで、以下の記事などで紹介されています。
suz-lab : EC2の価格のJSONを"jq"でいじってみた

jqの1.2では、containsという関数が追加されたようで、jsonに特定の要素が含まれているかどうかの真偽値を返すようです。

これをつかって簡単なAPIテストが出来るんじゃないかと思い、試してみました。

こんな感じのJSONがあったとします。
$ curl -s http://aws.amazon.com/jp/ec2/pricing/pricing-on-demand-instances.json | jq '.config.regions[].region'
"us-east"
"us-west-2"
"us-west"
"eu-ireland"
"apac-sin"
"apac-tokyo"
"apac-syd"
"sa-east-1"

containsで指定(config.regions[].region)の要素にap-northeast-1があるかどうかを検査します。
$ curl -s http://aws.amazon.com/jp/ec2/pricing/pricing-on-demand-instances.json | jq 'contains({config: {regions: [{region: "ap-northeast-1"}]}})'

false

無いようです。

ではapac-tokyoがあるかどうかを検査します。
$ curl -s http://aws.amazon.com/jp/ec2/pricing/pricing-on-demand-instances.json | jq 'contains({config: {regions: [{region: "apac-tokyo"}]}})'

true

ありました!


わざわざ導入に手間がかかるツールを使うまでもない簡単な検査であれば、ワンライナーで終わるコマンドラインをシェルにいくつか書いてまとめて実行するというのも手段としてありかもしれません。


以上です。

2013年5月20日月曜日

mroongaってなんじゃ?(Spiderで分散全文検索)

前回の記事でmroongaを使用しましたが、全文検索のデータは大きくなりがちなので、Spiderを利用して書き込み負荷やストレージ容量を分散してみます。



設定


mroongaデータノード

前回と同じようにmroongaテーブルを作りますが、Spiderノードからアクセスするためにユーザー権限を登録します。今回はホストは特に絞りません。
mysql> GRANT ALL PRIVILEGES ON *.* TO 'memorycraft_user'@localhost IDENTIFIED BY 'memorycraft_pass';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'memorycraft_user'@'%' IDENTIFIED BY 'memorycraft_pass';

新しくデータベースをつくり、blogテーブルを作ります。
mysql> CREATE DATABASE memorycraft;
mysql> use memorycraft;
mysql> 
mysql> CREATE TABLE blog (
mysql>  id INT PRIMARY KEY AUTO_INCREMENT,
mysql>  content text,
mysql>  FULLTEXT INDEX (content)
mysql> ) ENGINE = mroonga DEFAULT CHARSET utf8;



Spiderノード

Spiderのインストールは以前の記事のとおりです。
同じように権限を登録し、データベースを作成します。

mysql> GRANT ALL PRIVILEGES ON *.* TO 'memorycraft_user'@localhost IDENTIFIED BY 'memorycraft_pass';
mysql> GRANT ALL PRIVILEGES ON *.* TO 'memorycraft_user'@'%' IDENTIFIED BY 'memorycraft_pass';
mysql> 
mysql> CREATE DATABASE memorycraft;
mysql> use memorycraft;


Spiderテーブルを作成します。
ここでは、2つのノードにKEYパーティションで分散してみます。
mysql> CREATE TABLE blog (
mysql>  id INT PRIMARY KEY AUTO_INCREMENT,
mysql>  content text,
mysql>  FULLTEXT INDEX (content)
mysql> ) ENGINE = Spider DEFAULT CHARSET utf8
mysql> CONNECTION ' table "blog", user "memorycraft_user", password "memorycraft_pass" '
mysql> PARTITION BY KEY() (
mysql>  PARTITION db1 comment 'host "10.0.1.169", port "3306"',
mysql>  PARTITION db2 comment 'host "10.0.1.170", port "3306"'
mysql> );


これで設定は完了です。




確認



次にデータを登録してみます。
登録の仕方は前回と同様です。


Spiderノード


mysql> INSERT INTO blog (content) VALUES ("前回はpsqlでRedshiftを利用してみましたが、通常データウェアハウス(DWH)というのはBI(Buisiness Intelligence)ツールを利用することが多いようです。

エンジニアの観点からすると複雑なSQLを書くだけでいいかもしれませんが、経営者などの立場からするとBIツールなどを使って画面上でポチポチやって分析できることが重要なようです。
今回はそのBIツールの中で、Redshiftにいち早く対応しているJaspersoftという製品を使ってRedshiftに接続してみたいと思います。");

mysql> INSERT INTO blog (content) VALUES ("久しぶりにnagiosの話題です。
アプリログ内容の監視の仕方には様々な要件がありますが、特定の間隔でログを監視し「error」などの文言があったらアラートする。などがよくあるケースで、以前の記事にも書きました。
その逆に、例えば、多量のアクセスがあるにも関わらず頻繁に出力されるはずの重要なキーワードがでていない場合は、不測の事態がおこっているかも知れません。
今回は特定の間隔でログを監視し、その中にキーワードが含まれていなかったらアラートする
というものです。
ではやってみます。");

mysql> INSERT INTO blog (content) VALUES ("S3のwebホスティングで、ログ出力の設定をしていた場合、ログファイルが大量に出力されます。
ログの記録時間は標準時で出力されていてわかりづらいです。
今回はEMRのHiveを利用して、日本時間の0時〜翌日の0時までのログを1ファイルにまとめてみたいと思います。");

mysql > INSERT INTO blog (content) VALUES ("久しぶりのSpiderの話題です。
今回はtpcc-mysqlというベンチマークツールを使ってSpiderのベンチマークをとってみました。
mysqlにかぎらずDBのベンチマークツールの多くは、TPCという団体の定めたベンチマーク仕様に基いて実装されていて、トランザクションやアクセスなどのDB用途によっていくつかのベンチマークタイプに分かれていて、OLTP向けのTPC-Eや意思決定システム向けのTPC-HやTPC-DSなど色々あるようです。");


mysql> select id,MATCH(content) AGAINST("ログ アクセス" IN BOOLEAN MODE) as score from blog WHERE MATCH(content) AGAINST("ログ アクセス" IN BOOLEAN MODE)
    -> ;
+----+-------+
| id | score |
+----+-------+
|  3 |     4 |
|  2 |     4 |
|  4 |     1 |
+----+-------+
3 rows in set (0.01 sec)

mysql> select id, MATCH(content) AGAINST("ログ" IN BOOLEAN MODE) from blog WHERE MATCH(content) AGAINST("ログ" IN BOOLEAN MODE) ORDER BY  MATCH(content) AGAINST("ログ" IN BOOLEAN MODE) DESC;
+----+--------------------------------------------------+
| id | MATCH(content) AGAINST("ログ" IN BOOLEAN MODE)   |
+----+--------------------------------------------------+
|  3 |                                                4 |
|  2 |                                                3 |
+----+--------------------------------------------------+
2 rows in set (0.01 sec)




データノード


mysql> select id from blog;
+----+
| id |
+----+
|  1 |
|  3 |
+----+
2 rows in set (0.00 sec)


mysql> select id from blog;
+----+
| id |
+----+
|  2 |
|  4 |
+----+
2 rows in set (0.00 sec)


うまく分散されているようです。
これで沢山データがあっても分散されます。

以上です。

2013年5月17日金曜日

mroongaってなんじゃ? (mroongaでmysql全文検索)

mysqlで全文検索といえばTritonnが有名でした。現在ではmysqlで全文検索をするときにmroongaというプロダクトが有望なようです。



Tritonnとの違いは以下のサイトが詳しいです。
「全文検索エンジンgroongaを囲む夕べ #1」参加メモ

簡単にいうと、

  • Tritonn:Sennaという全文検索エンジンをMySQL用に組み込んだものです。MyISAMを前提に組み込まれていることもあり、更新が遅く、また更新時の検索が重くなるなど、ベストなパフォーマンスが得られにくかったようです。
  • mroongagroongaという全文検索エンジンをMySQL用にストレージエンジンにしたものです。MyISAMに依存しないため更新時の参照に影響を与えず、更新も速いようです。



では、さっそく導入してみます。
環境はEC2上のCentOS-6.4.1(suz-lab AMI)です。


groongaとmecabのインストール


まずgroongaとmecabをインストールします。
yumリポジトリを登録し、必要なものをインストールします。
# rpm -ivh http://packages.groonga.org/centos/groonga-release-1.1.0-1.noarch.rpm
# yum makecache
# yum install -y mecab
# yum install -y mecab-ipadic
# yum install -y groonga
# yum install -y groonga-tokenizer-mecab
# yum install -y wget


mysqlのインストール


yumを使った場合mroongaはmysql5.1を前提とするようです。ここではmysql5.5を使用したいのでソースからインストールします。
# cd /usr/local/src/
# wget http://dev.mysql.com/get/Downloads/MySQL-5.5/mysql-5.5.31.tar.gz/from/http://cdn.mysql.com/
# tar xzvf mysql-5.5.31.tar.gz
# cd mysql-5.5.31/
# yum install cmake
# yum install -y ncurses
# yum install -y ncurses-devel
# yum install -y gcc-c++
# yum install -y bison
# cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DENABLED_LOCAL_INFILE=true -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_EXTRA_CHARSETS=all -DWITH_READLINE=OFF
# make
# make install


mysql の設定


適当に設定ファイルを用意します。
# cd /usr/local/src/
# mv /etc/my.cnf /etc/my.cnf.org
# cp /usr/local/mysql/support-files/my-large.cnf /etc/my.cnf
# vim /etc/my.cnf
# The following options will be passed to all MySQL clients
[client]
#password = your_password
port  = 3306
socket  = /tmp/mysql.sock
default-character-set = utf8
# Here follows entries for some specific programs

# The MySQL server
[mysqld]
port  = 3306
socket  = /tmp/mysql.sock
skip-external-locking
key_buffer_size = 256M
max_allowed_packet = 1M
table_open_cache = 256
sort_buffer_size = 1M
read_buffer_size = 1M
read_rnd_buffer_size = 4M
myisam_sort_buffer_size = 64M
thread_cache_size = 8
query_cache_size= 16M
# Try number of CPU's*2 for thread_concurrency
thread_concurrency = 8

# Don't listen on a TCP/IP port at all. This can be a security enhancement,
# if all processes that need to connect to mysqld run on the same host.
# All interaction with mysqld must be made via Unix sockets or named pipes.
# Note that using this option without enabling named pipes on Windows
# (via the "enable-named-pipe" option) will render mysqld useless!
#
#skip-networking

# Replication Master Server (default)
# binary logging is required for replication
log-bin=mysql-bin

# binary logging format - mixed recommended
binlog_format=mixed


# required unique id between 1 and 2^32 - 1
# defaults to 1 if master-host is not set
# but will not function as a master if omitted
server-id = 1

# Uncomment the following if you are using InnoDB tables
innodb_data_home_dir = /usr/local/mysql/data
innodb_data_file_path = ibdata1:10M:autoextend
innodb_log_group_home_dir = /usr/local/mysql/data
# You can set .._buffer_pool_size up to 50 - 80 %
# of RAM but beware of setting memory usage too high
innodb_buffer_pool_size = 256M
innodb_additional_mem_pool_size = 20M
# Set .._log_file_size to 25 % of buffer pool size
innodb_log_file_size = 64M
innodb_log_buffer_size = 8M
innodb_flush_log_at_trx_commit = 1
innodb_lock_wait_timeout = 50

innodb_file_per_table
innodb_fast_shutdown = 0

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash
# Remove the next comment character if you are not familiar with SQL
#safe-updates

[myisamchk]
key_buffer_size = 128M
sort_buffer_size = 128M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
interactive-timeout



mysqlの起動


mysqlユーザーの作成と、起動スクリプトのコピー、DBの初期化を行い、mysqlにパスを通して起動します。
# groupadd mysql
# useradd mysql -g mysql -s /sbin/nologin
# cd /usr/local/mysql/
# /usr/local/mysql/scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data
# vim /root/.bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
 . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin:/usr/local/mysql/bin

export PATH
# source ~/.bash_profile
# cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql
# /etc/init.d/mysql start



mroongaのインストール


ここでmroongaをソースからビルドします。
configureオプションで、mysqlのソースを指定します。
# yum install -y automake
# cd /usr/local/src
# curl -OL http://packages.groonga.org/source/mroonga/mroonga-3.03.tar.gz
# tar xzvf mroonga-3.03.tar.gz
# cd mroonga-3.03/
# yum install groonga-devel
# ./configure --with-mysql-source=/usr/local/src/mysql-5.5.31 --with-mysql-config=/usr/local/mysql/bin/mysql_config
# make
# make install



mysqlへのmroongaエンジンのインストール


プラグインのインストールを行い、いくつかの関数を登録します。
mysql -u root
mysql> INSTALL PLUGIN mroonga SONAME 'ha_mroonga.so';
mysql> show engines;
+--------------------+---------+------------------------------------------------------------+--------------+------+------------+
| Engine             | Support | Comment                                                    | Transactions | XA   | Savepoints |
+--------------------+---------+------------------------------------------------------------+--------------+------+------------+
| MyISAM             | YES     | MyISAM storage engine                                      | NO           | NO   | NO         |
| PERFORMANCE_SCHEMA | YES     | Performance Schema                                         | NO           | NO   | NO         |
| CSV                | YES     | CSV storage engine                                         | NO           | NO   | NO         |
| InnoDB             | DEFAULT | Supports transactions, row-level locking, and foreign keys | YES          | YES  | YES        |
| MRG_MYISAM         | YES     | Collection of identical MyISAM tables                      | NO           | NO   | NO         |
| MEMORY             | YES     | Hash based, stored in memory, useful for temporary tables  | NO           | NO   | NO         |
| mroonga            | YES     | CJK-ready fulltext search, column store                    | NO           | NO   | NO         |
+--------------------+---------+------------------------------------------------------------+--------------+------+------------+
7 rows in set (0.00 sec)

mysql> CREATE FUNCTION last_insert_grn_id RETURNS INTEGER SONAME 'ha_mroonga.so';
mysql> CREATE FUNCTION mroonga_snippet RETURNS STRING SONAME 'ha_mroonga.so';
mysql> CREATE FUNCTION mroonga_command RETURNS STRING SONAME 'ha_mroonga.so';


これでひと通りのインストールが完了しました。
show enginesにmroongaが含まれていれば成功です。



確認


それでは簡単に触ってみます。
testデータベースにblogテーブルをつくってみます。
ここでは自分のグログ記事の抜粋をtextカラムにいれておきます。

mysql> use test;
mysql> CREATE TABLE blog (
mysql>   id INT PRIMARY KEY AUTO_INCREMENT,
mysql>   content text,
mysql>   FULLTEXT INDEX (content)
mysql> ) ENGINE = mroonga DEFAULT CHARSET utf8;

mysql> INSERT INTO blog (content) VALUES ("前回はpsqlでRedshiftを利用してみましたが、通常データウェアハウス(DWH)というのはBI(Buisiness Intelligence)ツールを利用することが多いようです。
エンジニアの観点からすると複雑なSQLを書くだけでいいかもしれませんが、経営者などの立場からするとBIツールなどを使って画面上でポチポチやって分析できることが重要なようです。
今回はそのBIツールの中で、Redshiftにいち早く対応しているJaspersoftという製品を使ってRedshiftに接続してみたいと思います。");

mysql> INSERT INTO blog (content) VALUES ("久しぶりにnagiosの話題です。
アプリログ内容の監視の仕方には様々な要件がありますが、特定の間隔でログを監視し「error」などの文言があったらアラートする。などがよくあるケースで、以前の記事にも書きました。
その逆に、例えば、多量のアクセスがあるにも関わらず頻繁に出力されるはずの重要なキーワードがでていない場合は、不測の事態がおこっているかも知れません。
今回は特定の間隔でログを監視し、その中にキーワードが含まれていなかったらアラートする
というものです。
ではやってみます。");

mysql> INSERT INTO blog (content) VALUES ("S3のwebホスティングで、ログ出力の設定をしていた場合、ログファイルが大量に出力されます。
ログの記録時間は標準時で出力されていてわかりづらいです。
今回はEMRのHiveを利用して、日本時間の0時〜翌日の0時までのログを1ファイルにまとめてみたいと思います。");

mysql > INSERT INTO blog (content) VALUES ("久しぶりのSpiderの話題です。
今回はtpcc-mysqlというベンチマークツールを使ってSpiderのベンチマークをとってみました。
mysqlにかぎらずDBのベンチマークツールの多くは、TPCという団体の定めたベンチマーク仕様に基いて実装されていて、トランザクションやアクセスなどのDB用途によっていくつかのベンチマークタイプに分かれていて、OLTP向けのTPC-Eや意思決定システム向けのTPC-HやTPC-DSなど色々あるようです。");



そして、「ログ」を含むレコードを探してみます。
mysql> SELECT * FROM blog WHERE MATCH(content) AGAINST("ログ");
mysql> SELECT * FROM blog WHERE MATCH(content) AGAINST("ログ") \G;
*************************** 1. row ***************************
     id: 2
content: 久しぶりにnagiosの話題です。アプリログ内容の監視の仕方には様々な要件がありますが、特定の間隔でログを監視し「error」などの文言があったらアラートする。などがよくあるケースで、以前の記事にも書きました。その逆に、例えば、多量のアクセスがあるにも関わらず頻繁に出力されるはずの重要なキーワードがでていない場合は、不測の事態がおこっているかも知れません。今回は特定の間隔でログを監視し、その中にキーワードが含まれていなかったらアラートする
というものです。

ではやってみます。
*************************** 2. row ***************************
     id: 3
content: S3のwebホスティングで、ログ出力の設定をしていた場合、ログファイルが大量に出力されます。

ログの記録時間は標準時で出力されていてわかりづらいです。

今回はEMRのHiveを利用して、日本時間の0時〜翌日の0時までのログを1ファイルにまとめてみたいと思います。
2 rows in set (0.00 sec)

ERROR:
No query specified

mysql>


検索が成功したようです。
次に検索スコアを出してみます。デフォルトでは自然言語検索によるスコアのようです。

mysql> select id,MATCH(content) AGAINST("ログ") as score from blog;
+----+---------+
| id | score   |
+----+---------+
|  1 |       0 |
|  2 |  786435 |
|  3 | 1048580 |
|  4 |       0 |
+----+---------+
4 rows in set (0.00 sec)



また、「ログ」と「アクセス」が含まれるレコードの検索をしてみます。

両方含まれるもの
mysql> select id,MATCH(content) AGAINST("+ログ +アクセス" IN BOOLEAN MODE) as score from blog WHERE MATCH(content) AGAINST("+ログ +アクセス" IN BOOLEAN MODE);
+----+-------+
| id | score |
+----+-------+
|  2 |     4 |
+----+-------+
1 row in set (0.00 sec)

どちらかが含まれるもの
mysql> select id,MATCH(content) AGAINST("ログ アクセス" IN BOOLEAN MODE) as score from blog WHERE MATCH(content) AGAINST("ログ アクセス" IN BOOLEAN MODE)
+----+-------+
| id | score |
+----+-------+
|  2 |     4 |
|  3 |     4 |
|  4 |     1 |
+----+-------+
3 rows in set (0.00 sec)



マッチ度がスコアで取得されるので、ソートをすることもできます。
mysql> select id, MATCH(content) AGAINST("ログ" IN BOOLEAN MODE) from blog WHERE MATCH(content) AGAINST("ログ" IN BOOLEAN MODE) ORDER BY  MATCH(content) AGAINST("ログ" IN BOOLEAN MODE) DESC;
+----+--------------------------------------------------+
| id | MATCH(content) AGAINST("ログ" IN BOOLEAN MODE)   |
+----+--------------------------------------------------+
|  3 |                                                4 |
|  2 |                                                3 |
+----+--------------------------------------------------+
2 rows in set (0.00 sec)



ざっとさわりでしたが、mroongaを試してみました。
パフォーマンスやクエリの用法などはまたの機会に調べてみます。

またMySQLでは5.6からInnoDB FTSというInnoDBでの全文検索が可能なようですが、こちらは参照は速いものの更新はmroongaの方が速いという結果も出ているようなので、こちらも機会があれば調べてみたいと思います。
http://www.slideshare.net/y-ken/my-sql-56innodb-fts

以上です。


2013年5月15日水曜日

logrotateってなんじゃ?(pigzで高速ローテート)

大量アクセスがあってログファイルが巨大であったりすると、日々のlogrotateが重くなります。

対象ディレクトリ以下に大量のファイルがある場合も時間がかかることがありますが、その場合はローテションの世代数を減らしたり、対象ディレクトリから定期的に退避すれば済むため、ネックになるのは主に圧縮によるものだと思います。

デフォルトではgzipが利用されますが、別の圧縮プログラムを利用することもできます。
圧縮プログラムの選定ですが、基本的に圧縮率の高いプログラムは時間がかかりますし、高速なものは圧縮率が低いものが一般的ですが、例外があります。

gzipなどはシングルコアしか使用しませんが、マルチコアで分散処理する圧縮プログラムだとおなじ圧縮フォーマットでも格段に速くなります。

今回は、その例としてpigzを利用してみます。
pigzは、gzipフォーマットの圧縮をマルチコアで行う高速gzipとして動作します。
pigzで圧縮したファイルはgunzipで解凍できるので、pigzの無い環境にもファイルを持っていくことができます。

それでは早速触ってみます。


複数のCPUがあるマシンでないと意味が無いので、コア数を確認します。
# cat /proc/cpuinfo | grep processor
processor : 0
processor : 1
processor : 2
processor : 3
processor : 4
processor : 5
processor : 6
processor : 7

今回はc1.xlargeですので、8コアです。


pigzをダウンロードして、ビルドします。
cd /usr/local/src/
curl -OL http://www.zlib.net/pigz/pigz-2.3.tar.gz
tar xzvf pigz-2.3.tar.gz
cd pigz-2.3/
make

cc -o pigz pigz.o yarn.o zopfli/deflate.o zopfli/blocksplitter.o zopfli/tree.o zopfli/lz77.o zopfli/cache.o zopfli/hash.o zopfli/util.o zopfli/squeeze.o zopfli/katajainen.o -lpthread -lz
zopfli/tree.o: In function `CalculateEntropy':
tree.c:(.text+0x75): undefined reference to `log'
tree.c:(.text+0x11a): undefined reference to `log'
tree.c:(.text+0x16b): undefined reference to `log'
collect2: ld はステータス 1 で終了しました
make: *** [pigz] エラー 1


なんかエラーが出ました。リンクが張られていないようなので、Makefileで-lmオプションをつけます。
6c6
<  $(CC) -o pigz $^ -lpthread -lz
---
>  $(CC) -o pigz $^ -lpthread -lz -lm




もう一度ビルドします。
# make
cc -o pigz pigz.o yarn.o zopfli/deflate.o zopfli/blocksplitter.o zopfli/tree.o zopfli/lz77.o zopfli/cache.o zopfli/hash.o zopfli/util.o zopfli/squeeze.o zopfli/katajainen.o -lpthread -lz -lm
ln -f pigz unpigz

# ls -l
合計 584
-rw-r--r-- 1  501 games   2630  5月 16 03:46 2013 Makefile
-rw-r--r-- 1 root root    2626  5月 16 03:46 2013 Makefile.org
-rw-r--r-- 1  501 games   2188  7月 29 05:37 2012 README
-rwxr-xr-x 2 root root  128382  5月 16 03:46 2013 pigz
-rw-r--r-- 1  501 games   4836  3月  4 15:24 2013 pigz.1
-rw-r--r-- 1  501 games 140762  3月  4 16:42 2013 pigz.c
-rw-r--r-- 1 root root  115496  5月 15 04:17 2013 pigz.o
-rw-r--r-- 1  501 games   8758  3月  4 15:24 2013 pigz.pdf
-rw-r--r-- 1  501 games    947  7月 29 05:37 2012 pigz.spec
-rwxr-xr-x 2 root root  128382  5月 16 03:46 2013 unpigz
-rw-r--r-- 1  501 games  11079  1月 14 07:56 2012 yarn.c
-rw-r--r-- 1  501 games   6358  1月 14 07:56 2012 yarn.h
-rw-r--r-- 1 root root   11624  5月 15 04:17 2013 yarn.o
drwxr-xr-x 2  501 games   4096  5月 15 04:17 2013 zopfli



pigzとunpigzが出力されていたら成功です。
この2つのプログラムをパスの通っているところに置きます。
cp pigz /usr/local/bin/
cp unpigz /usr/local/bin/



それでは実際に、動かしてみます。
まず1GBのファイルを作ります。
dd if=/dev/zero of=test.log bs=1024 count=1024000

# ls -lh
合計 1001M
-rw-r--r-- 1 root root 1000M  5月 15 05:02 2013 test.log




そして、gzipでの圧縮/非圧縮と、pigzでの圧縮/非圧縮で時間とCPU使用率を見てみます。
# time gzip test.log

real 0m11.084s
user 0m10.407s
sys 0m0.673s

# top
Cpu0  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu1  : 97.3%us,  2.7%sy,  0.0%ni,  0.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu4  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu5  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu6  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu7  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

------------------------------------------------------------------------------------------
# time gunzip test.log.gz

real 0m23.668s
user 0m7.032s
sys 0m1.174s

# top
Cpu0  : 83.6%us, 15.8%sy,  0.0%ni,  0.0%id,  0.3%wa,  0.0%hi,  0.0%si,  0.3%st
Cpu1  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu4  :  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu5  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu6  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu7  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

------------------------------------------------------------------------------------------
# time pigz test.log

real 0m3.025s
user 0m18.781s
sys 0m1.082s

# top
Cpu0  : 51.0%us,  0.7%sy,  0.0%ni, 45.7%id,  0.0%wa,  0.0%hi,  0.0%si,  2.6%st
Cpu1  : 47.8%us,  4.0%sy,  0.0%ni, 48.2%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu2  : 48.2%us, 11.0%sy,  0.0%ni, 40.5%id,  0.0%wa,  0.0%hi,  0.0%si,  0.3%st
Cpu3  : 50.8%us,  0.3%sy,  0.0%ni, 47.8%id,  0.0%wa,  0.0%hi,  0.0%si,  1.0%st
Cpu4  : 49.0%us,  3.3%sy,  0.0%ni, 47.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.7%st
Cpu5  : 50.0%us,  2.0%sy,  0.0%ni, 45.7%id,  0.0%wa,  0.0%hi,  0.0%si,  2.3%st
Cpu6  : 50.3%us,  0.7%sy,  0.0%ni, 48.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.3%st
Cpu7  : 48.3%us,  3.3%sy,  0.0%ni, 48.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.3%st

------------------------------------------------------------------------------------------
# time unpigz test.log.gz

real 0m5.298s
user 0m6.808s
sys 0m1.128s

# top
Cpu0  : 73.8%us,  3.6%sy,  0.0%ni, 21.5%id,  0.0%wa,  0.0%hi,  0.0%si,  1.1%st
Cpu1  : 48.0%us, 18.5%sy,  0.0%ni, 18.9%id, 13.0%wa,  0.0%hi,  0.0%si,  1.6%st
Cpu2  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu3  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu4  :  0.0%us,  0.3%sy,  0.0%ni, 99.7%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu5  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu6  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st
Cpu7  :  0.0%us,  0.0%sy,  0.0%ni,100.0%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st


おお、だいぶ速くなったようです。複数のCPUが使われていることも分かります。

次はこれをlogrotateで利用してみます。
コメント付きの部分が圧縮プログラムの設定になります。
全体的に適用したい場合は、/etc/logrotate.confに記述します。
# cat /etc/logrotate.d/httpd
/var/log/httpd/*log {
    daily
    missingok
    ifempty
    compresscmd /usr/local/bin/pigz               # 圧縮プログラムを指定
    uncompresscmd /usr/local/bin/unpigz       # 解凍プログラムを指定
    compressext .gz                                           # 圧縮ファイル拡張子を指定
    sharedscripts
    postrotate
        /sbin/service httpd reload > /dev/null 2>/dev/null || true
    endscript
}


httpdのログファイルを作って、時刻をローテーションの時間に合わせます。
dd if=/dev/zero of=/var/log/httpd/access_log bs=1024 count=1024000
date -s "2013/05/14 03:00:00"


しばらくすると、きちんとローテーションされていることがわかります。
# ls -l /var/log/httpd/
合計 1160
-rw-r--r-- 1 root root       0  5月 16 03:11 2013 access_log
-rw-r--r-- 1 root root 1176015  5月 16 03:11 2013 access_log-20130516.gz
-rw-r--r-- 1 root root     245  5月 16 03:11 2013 error_log
-rw-r--r-- 1 root root     294  5月 16 03:11 2013 error_log-20130516.gz


マルチコア環境に限りますが、これでローテーションが軽くなります。
以上です。


2013年5月10日金曜日

nagiosってなんじゃ?(nrpe + check_log3 + negateでログに特定のキーワードが含まれていなかったらアラート)

久しぶりにnagiosの話題です。

アプリログ内容の監視の仕方には様々な要件がありますが、特定の間隔でログを監視し「error」などの文言があったらアラートする。などがよくあるケースで、以前の記事にも書きました。

その逆に、例えば、多量のアクセスがあるにも関わらず頻繁に出力されるはずの重要なキーワードがでていない場合は、不測の事態がおこっているかも知れません。

今回は特定の間隔でログを監視し、その中にキーワードが含まれていなかったらアラートする
というものです。

ではやってみます。


nrpe check_log3の利用


まずは普通にcheck_log3の設定をします。

Nagiosサーバー側に、以下の設定をします。
3分間隔でチェックし、キーワード「hoge」が一つでも含まれていたらCRITICALを出します。
今回はWARNINGは出さないので、WARNINGの閾値をとても大きな数値にしておきます。

commands.cfg
define command{
    command_name    check_nrpe
    command_line    $USER1$/check_nrpe -H $HOSTADDRESS$ -c $ARG1$ -a $ARG2$
}


client.cfg
define host{
        use                    linux-server
        host_name        client_a
        alias                   client_a
        address             ec2-54-250-36-70.ap-northeast-1.compute.amazonaws.com
 }

define service {
        use                                  generic-service
        host_name                      client_a
        service_description         CHECKLOG3
        normal_check_interval   3
        check_command           check_nrpe!check_log3!/var/log/httpd/access_log /etc/nagios/seeks/check_log3.httpd.seek hoge 99999999999999 1

}


すると、キーワードが含まれている場合は、


キーワードが含まれていない場合は、


のようになります。



nrpe check_log3 + negateの利用


次に、これの逆をやってみます。
nagiosにはnegateというプラグインがあり、CRITICALとOKの評価を反転します。
このプラグインを使用して、評価反転用のcheck_nrpeコマンドを定義します。


commands.cfg
define command{
    command_name    check_nrpe
    command_line    $USER1$/check_nrpe -H $HOSTADDRESS$ -c $ARG1$ -a $ARG2$
}

define command{
    command_name    check_nrpe_negate
    command_line    $USER1$/negate $USER1$/check_nrpe -H '$HOSTADDRESS$' -c $ARG1$ -a $ARG2$
}


client.cfg
define host{
        use                    linux-server
        host_name        client_a
        alias                   client_a
        address             ec2-54-250-36-70.ap-northeast-1.compute.amazonaws.com
 }

#define service {
#        use                     generic-service
#        host_name               client_a
#        service_description     CHECKLOG3
#        normal_check_interval   3
#        check_command           check_nrpe!check_log3!/var/log/httpd/access_log /etc/nagios/seeks/check_log3.httpd.seek hoge 99999999999999 1
#}

define service {
       use                     generic-service
       host_name               client_a
       service_description     NEGATE_CHECKLOG3
       normal_check_interval   3
       check_command           check_nrpe_negate!check_log3!/var/log/httpd/access_log /etc/nagios/seeks/check_log3.httpd.seek hoge 99999999999999 1

}


すると、キーワードが含まれている場合は、


キーワードが含まれていない場合は、



のようになり、結果が反転します。
nrpeでなくても、どのプラグインでもnegateと組み合わせることができるので、ちょっとした工夫が必要なときにはとても便利です。

以上です。


2013年5月7日火曜日

Redshiftってなんじゃ?(BI編:JaspersoftでRedshift)

前回はpsqlでRedshiftを利用してみましたが、通常データウェアハウス(DWH)というのはBI(Buisiness Intelligence)ツールを利用することが多いようです。

エンジニアの観点からすると複雑なSQLを書くだけでいいかもしれませんが、経営者などの立場からするとBIツールなどを使って画面上でポチポチやって分析できることが重要なようです。

今回はそのBIツールの中で、Redshiftにいち早く対応しているJaspersoftという製品を使ってRedshiftに接続してみたいと思います。




起動とログイン



RedshiftとRDSに対応してあるバージョンのJaspersoftのAMIがマーケットプレイスにあるので、それを購入します。

Jaspersoft Reporting and Analytics for AWS
https://aws.amazon.com/marketplace/pp/B00B527JQ0





このAMIはインスタンスのランニングコスト以外にもソフトウェアの使用料金が時間単位で掛かります。
ここでは、RedshiftのあるUSのリージョンで起動します。




AWSコンソールのページが開き、インスタンス起動のウィザードが実行されます。




Redshiftと同じゾーンを選択します。
今回はm1.mediumのサイズで立ちあげます。




ここではルートボリュームを100GBにします。



また、セキュリティグループではSSHとHTTPをあけておきます。




起動させたあと、このインスタンスのPublicDNSまたはEIPに対してローカルのブラウザからアクセスしてみます。
すると、jasperサーバーの初期画面が表示されるので、「Login」をクリックします。



すると、ログイン画面が表示されます。



「ログインのお手伝いが必要ですか」というリンクをクリックすると、下図のように初期のID、パスワードが表示されます。ここではsuperuserでログインしてみます。



すると、新しいパスワードを要求されるので、好きなパスワードを設定して改めてログインします。



これでログインすることが出来ました。
これがJasperサーバーのホーム画面のようです。





データソースの登録



次に、データソースを作成します。
ここでいうデータソースとは、データがある場所をしめします。
データベースの場合やファイルの場合などがあり、ここではRedshiftをデータソースとして登録します。
グローバルヘッダの「作成」から「Data Source」を選択します。


 データソース作成画面では、タイプ欄からいくつかのデータソースタイプが選択でき、今回は「JDBC Data Source」を選択します。




ちなみに「AWS Data Source」でRedshiftを選択しても接続できます。






ドメインの作成



次にドメインを作成します。ドメインとはビューに渡すデータセットに当たります。
データソースからデータを選別してビューに渡すために整理した状態にします。

グローバルヘッダから「作成 > ドメイン」を選択します。

 ドメイン作成画面では、ドメイン名と作成したドメインの保存場所を適当に入力します。
また、データソースには先ほど作成したRedshiftのデータソースを選択します。
そして、ドメインデザイナのリンクをクリックします。


すると、ドメインデザイナが開き、データソースの「テーブル」タブが表示されます。
ここで、「>」ボタンなどで使用するテーブルを右側の枠に持っていきます。


次の「派生テーブル」タブで選択されたテーブルを対象に直接クエリ(SubQuery)などをかけられたり、



複数のテーブルを結合(Join)できたり、



フィルタ(Where)をかけられたり


などといったことができます。
つまりドメインというのはGUIでつくるSQL、つまりクエリビルダのようなものです。

最後の「表示」タブでは、このようにして作ったデータセットに対して、レポート表示時のラベルをつけれたりできます。




 そして「OK」を押すと、ドメインにこの設定が保存されます。
 ドメイン作成画面に戻り、「送信」を押すとこのドメインが作成されます。





アドホックビューの作成



次にアドホックビューを作成します。
アドホックビューは、レポート用の様々なタイプのビューで、グラフなどを作成できます。




アドホックビューでは最初に、入力ソースを選択します。
ここでは、さきほど作成したドメインを選択します。





 次に、ドメインに含まれるフィールドを選定します。
使用するフィールドを右側に移動し、下部のボタンから、テーブルやグラフなど表示タイプのボタンを押します。 今回は「グラフ」のボタンを押します。





すると、UIデザインの画面が開きます。
 ここで、左側の「フィールド」と「メジャー」から中央上部の「列」や「行」に適用する項目をドラッグします。この部分はGoogle Analyticsでカスタムレポートに指標やディメンションを追加するのに似ています。




 ここでは、列にprefecture_name, 行にcntをセットして、右側のデータラベルを右側にスライドします。
すると以下のようにグラフが自動で作成されます。
グラフのタイプを変更するには、グラフ左上の歯車アイコンをクリックして、変更します。





保存する場合は、中央ツールバーのディスクアイコンで保存します。








レポートの作成



 次に、レポートを作成します。
レポートは基本的に、アドホックビューを選択するだけです。





レポート作成画面でもグラフのタイプを変更することができます。



 ツールバーのディスクアイコンでレポートを保存します。






ダッシュボードの作成



最後はダッシュボードです。



ダッシュボードの作成画面では、複数のレポートを貼り付けたり、コントロールを貼り付けたりして帳票としての全体的な画面をつくります。




作成されたダッシュボードは以下のようになります。
このように、DBの知識がほとんどなくてもいろいろなデータの見た目をプリセットで整えて、手軽に更新、確認できるのがBIツールの役目のようです。





まとめ



Jaspersoftを使ってみた感覚としては、独特のコンポーネントにつけられた用語や意味を把握するのに少し戸惑いますが、慣れてしまうとそれなりに直感的に操作ができます。

ただ、異なるデータソースのデータ同士をJoinできるかと思ったのですが、やりかたがわかりませんでした。
その場合は、RedshiftにインポートしてRedshiftデータソースとして、ドメイン内でJoinしてしまえばよいかなと思います。


以上です。






2013年5月1日水曜日

Redshiftってなんじゃ?

遅ればせながらAWSのRedshiftというサービスの話題です。
Redshiftはデータウェアハウス(DWH)をサービスにしたものです。
DWHというのは平たく言うと、専用ツールなどを使って様々な角度で分析するためのあらゆるデータの集まりです。

各所に分散している様々なデータを統合して関連付け、見えない傾向や状況などを知ることでビジネスの意思決定(ビジネスインテリジェンス:BIというそうです。)をしやすくするために用いられるようです。

DWHでは直接関わりあいのない業務同士のデータも関連付けに利用されたり、過去との比較も重要な分析になるため、通常のデータベースよりも巨大になります。

従来のDWHでは、専用のハードウェアとソフトウェアを利用するため高価でしたが、Redshiftが出たことによりはるかに安価で気軽に利用することが出来るようになりました。


。。。これだとふわふわしすぎていてよくわからないので、ちょっとずつ触ってみて勉強していきたいと思います。

Redshiftは、いってみればAWSが提供している巨大なPostgreSQLベースのクラスタです。
なので、たくさんのデータを集計しやすいDBだと思ってまずは触ってみます。


AWSコンソールでRedshiftの画面を開いてみます。



「Launch Cluster」をクリックします。
Cluster名やデータベース名などを適当に入力します。



ノードの設定です。
クラスタの各ノードのインスタンスタイプとノード数を設定します。最低2ノードからになります。
今回は2ノードにします。



追加設定です。
パラメータグループやセキュリティグループ、VPCに入れるかなどを設定します。
今回は全部デフォルトで済まします。



設定内容を確認して、「Launch Cluster」をクリックします。



クラスタ一覧にいま作成したクラスタが表示されました。
ステータスをみるとcreatingとなっているので、準備中なのでしょう。



しばらくすると、availableに変わりました。これで使えるようです。
クラスタ名のリンクをクリックしてみます。



すると詳細情報が開きます。接続エンドポイントやJDBC,ODBCの接続子などが表示されています。



また、Security Groupsで、defaultグループにアクセス可能なIPを設定しておきます。




今回は、専用ツールなどは利用せず、psqlでこのエンドポイントに直接接続してみます。
$ psql -h myfirstdwh.cr0bw6iq1m5m.us-east-1.redshift.amazonaws.com -p 5439 -U memorycraft -W myfirstdwh
Password for user memorycraft: XXXXXXXXXX

psql (9.1.5, server 8.0.2)
WARNING: psql version 9.1, server version 8.0.
         Some psql features might not work.
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.

myfirstdwh=#


接続できました。
通常のpostgreSQLとRedshiftのpostgreSQLインターフェースの違いは以下のようになっているそうです。


CREATE TABLE
Amazon Redshiftはテーブルスペース,パーティショニング,継承,制約をサポートしません. Redshift では並列処理を最適化するために、CREATE TABLEにおいてsortとdistributionアルゴリズムを定義することができます。

ALTER TABLE
ALTER COLUMNはサポートされmせん
ADD COLUMNは1つのALTER TABLEステートメントにつき1カラムだけ指定できます.

COPY
RedshiftではS3バケットとDynamoDBから自動圧縮してデータをロードするために特別にカスタマイズされています。

SELECT
ORDER BY ... NULLS FIRST/LAST は未サポートです

INSERT, UPDATE, and DELETE 
 WITHは未サポートです

VACUUM
VACUUMのパラメータはpostgreSQLとRedshiftではまったく異なります。



今回は試しに、日本の郵便番号データを投入してみます。
以下のサイトからダウンロードした全国一括の郵便番号CSVファイルをS3にアップします。
現段階で、Redshiftは同一リージョンのS3でないとロードできないため、USリージョンのバケットに配置します。

次に、このCSVのフォーマットに合わせてテーブルを作成します。
create table zipcode(
  official_area_code integer,
  old_zipcode varchar(10),
  zipcode varchar(10) distkey sortkey,
  prefecture_name_kana varchar(500),
  city_name_kana varchar(500),
  town_name_kana varchar(500),
  prefecture_name varchar(500),
  city_name varchar(500),
  town_name varchar(500),
  flag_a smallint,
  flag_b smallint,
  flag_c smallint,
  flag_d smallint,
  flag_e smallint,
  flag_f smallint
);


そしてデータをロードします。ロードにはCOPYコマンドを利用します。
CSVはカンマ区切りなので、DELIMITER句で ","を指定します。また、文字列はダブルクォーテーションで囲われているので、REMOVEQUOTES句を利用します。
また、S3バケットへのアクセスにはCREDENTIALS句を利用して、AWSアクセスキーとシークレットキーを指定します。
COPY zipcode FROM 's3://redshift-us-region/KEN_ALL.CSV' CREDENTIALS 'aws_access_key_id=<my aws access key>;aws_secret_access_key=<my aws secret access key>' DELIMITER ',' REMOVEQUOTES;

COPY



ロードに成功した場合はCOPYと表示されます。ロードに失敗した場合は詳細ログがstl_load_errorsテーブルに出力されるので、SELECTなどして確認します。
select * from stl_load_errors where filename = 'KEN_ALL.CSV';


データの投入が終わったので、集計などしてみます。
select count(distinct zipcode) from zipcode where prefecture_name = '北海道';
 count
-------
  8006
(1 row)

このように集計できました。


今回は手元のマシンからのアクセスで、データ数も少ないため、パフォーマンス面での性能はまだわかりませんが、psqlで接続できるのはとても手軽です。
今後もいろいろ触って試してみたくなりました。

以上です。