AWS X-Ray(プレビュー版)を使ってSolrの検索処理をトレースしてみる。
Solrへリクエストを投げるところからトレースを開始する。
システム構成
サーバ
使用するインスタンスは2台。
Amazon Linuxを使う。
- Webサーバ(express/node.js - t2.micro)
- 検索エンジン(Solr/Jetty - t2.medium)
サービスマップ
こんな感じになる。
localhost
と書いてあるけどSolrへのリクエスト。
サーバの構築
共通
セキュリティグループ
ローカルマシン→Webサーバの80番ポートは開けておく。
Webサーバ→検索エンジンの80番ポートも開けておく。
ローカルマシン→Solrにアクセスするならそちらの8983番ポートも開けておく。
IAMロール/インスタンスプロファイル
後述のX-RayデーモンがAWS X-Rayサービスにデータを送るので書き込み権限を設定してあげる。
インスタンスに関連付けるIAMロールを適当に作り、AWSマネージドポリシーからAWSXrayWriteOnlyAccess
ポリシーをアタッチする。
ポリシーの内容はこんな感じ。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"xray:PutTraceSegments",
"xray:PutTelemetryRecords"
],
"Resource": [
"*"
]
}
]
}
X-Rayデーモン
X-Rayデーモンのインストール。
もう起動してる。気が早い。
$ curl -sL https://s3.amazonaws.com/aws-xray-assets.us-east-1/xray-daemon/aws-xray-daemon-1.x.rpm -o /home/ec2-user/xray.rpm
$ sudo yum install -y xray.rpm
$ sudo initctl status xray
xray start/running, process 2607
インストール内容はこんな感じ。
xrayデーモンはGolang製の模様。
systemdの設定もあるようだがデフォルトだとUpstartで起動している。
$ rpm -ql xray
/etc/amazon/xray/cfg.yaml
/etc/init/xray.conf
/etc/systemd/system/xray.service
/usr/bin/xray
設定はデフォルトのままでいじらず。
Webサーバ
検索エンジンのIPアドレスをxray-solr
としてを/etc/hosts
に登録した。
node.js
epel
からインストールすると0.10系になるので最新版になる方法でインストールする。
レポジトリを登録。
$ curl -sL https://rpm.nodesource.com/setup_7.x | sudo bash -
## Installing the NodeSource Node.js 7.x repo...
## Inspecting system...
+ rpm -q --whatprovides redhat-release || rpm -q --whatprovides centos-release || rpm -q --whatprovides cloudlinux-release || rpm -q --whatprovides sl-release
+ uname -m
## Confirming "el7-x86_64" is supported...
+ curl -sLf -o /dev/null 'https://rpm.nodesource.com/pub_7.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'
## Downloading release setup RPM...
+ mktemp
+ curl -sL -o '/tmp/tmp.OHBteTsWWV' 'https://rpm.nodesource.com/pub_7.x/el/7/x86_64/nodesource-release-el7-1.noarch.rpm'
## Installing release setup RPM...
+ rpm -i --nosignature --force '/tmp/tmp.OHBteTsWWV'
## Cleaning up...
+ rm -f '/tmp/tmp.OHBteTsWWV'
## Checking for existing installations...
+ rpm -qa 'node|npm' | grep -v nodesource
## Run `yum install -y nodejs` (as root) to install Node.js 7.x and npm.
## You may also need development tools to build native addons:
## `yum install -y gcc-c++ make`
v7.6.0をインストール。
$ sudo yum install -y nodejs
$ node -v
v7.6.0
yarn
npm
はpackage.json
を管理する気があるのかないのか分からないのでyarn
をインストールする。
$ sudo curl -sL https://dl.yarnpkg.com/rpm/yarn.repo -o /etc/yum.repos.d/yarn.repo
$ sudo yum install -y yarn
express
/home/ec2-user/web
以下にプロジェクトを作った。
$ yarn init -y
$ yarn add express aws-sdk aws-xray-sdk
ここまででpackage.json
はこんな感じ。
{
"name": "web",
"version": "1.0.0",
"main": "index.js",
"repository": {},
"license": "MIT",
"dependencies": {
"aws-sdk": "^2.12.0",
"aws-xray-sdk": "^1.0.4-beta",
"express": "^4.14.1"
}
}
リクエストが来たら検索エンジンで検索するWebアプリを書く。
const express = require('express');
const app = express();
const AWSXRay = require('aws-xray-sdk');
AWSXRay.config([AWSXRay.plugins.EC2]);
const http = require('http');
AWSXRay.captureHTTPs(http);
app.use(AWSXRay.express.openSegment('xray-web'));
app.get('/', (req, res) => {
const options = {
hostname: 'xray-solr',
port: 8983,
path: '/solr/xray/select?indent=on&q=*:*&wt=json'
};
http.get(options, (response) => {
let data = '';
response.on('data', (chunk) => data += chunk);
response.on('end', () => {
res.send(data);
});
});
});
app.use(AWSXRay.express.closeSegment());
app.listen(80);
EC2プラグインを指定するとAWS X-Rayに渡される情報にインスタンス情報が付加される。
今のところインスタンスIDとAZのみ。
AWSXRay.config([AWSXRay.plugins.EC2]);
サンプリングルールの設定も出来る模様。
AWSXRay.setSamplingRules('sampling-rules.json');
公式ドキュメントに記載されている形式だとエラーで動かないので下記のような形式にすると動いた。
ただDefault
の設定しか反映されないので、どこか間違っていそう。
毎秒fixed_target
数のリクエストをトレース、その後はrate
の割合でトレース。
{
"rules": {
"1": {
"service_name": "*",
"http_method": "*",
"url_path": "*",
"fixed_target": 10,
"rate": 0.1
},
"Default": {
"fixed_target": 10,
"rate": 0.1
}
}
}
express用のミドルウェアが用意されているので使わせて頂く。
これでWebサーバに来たリクエストをトレース出来る。
app.use(AWSXRay.express.openSegment('xray-web'));
:
app.use(AWSXRay.express.closeSegment());
http
やhttps
を使った通信をトレースすることが出来る。
内部的にhttp.request
を置き換えている。
これで検索エンジンとの通信をトレース出来る。
AWSXRay.captureHTTPs(http);
http.get('http://.../')
のようにURLを直接渡すとhttp://localhost/
へのリクエストが無限ループになって死ぬ。
接続先が未知の場合はlocalhostに設定されるのはnode.jsの仕様らしい。誰が喜ぶんだこれ。
今のところoptions
はハッシュで渡されることが期待されている。
const options = {
hostname: 'xray-solr',
port: 8983,
path: '/solr/xray/select?indent=on&q=*:*&wt=json'
};
http.get(options, (response) => {...});
検索エンジン
自分のIPアドレスをxray-solr
としてを/etc/hosts
に登録した。
node.js
SolrへのプロキシとしてWebサーバと同様に node.js + express をインストールした。
コードはWebサーバとほぼ同じだが、検索エンジンのクライアントは色々ある前提でDynamic Naming Modeにしてみた。
defaultName
を与えないとエラーになった。
AWSXRay.middleware.enableDynamicNaming();
app.use(AWSXRay.express.openSegment('defaultName'));
java
1.8以上が必要らしい。
$ sudo yum install java-1.8.0-openjdk
$ sudo alternatives --config java
2 プログラムがあり 'java' を提供します。
選択 コマンド
-----------------------------------------------
*+ 1 /usr/lib/jvm/jre-1.7.0-openjdk.x86_64/bin/java
2 /usr/lib/jvm/jre-1.8.0-openjdk.x86_64/bin/java
Enter を押して現在の選択 [+] を保持するか、選択番号を入力します:2
Solr
/home/ec2-user/solr/
以下にSolrをインストールした。
$ curl -sL 'http://ftp.jaist.ac.jp/pub/apache/lucene/solr/6.4.1/solr-6.4.1.tgz' -o /home/ec2-user/solr.tgz
$ tar zxf solr.tgz
$ mv solr-6.4.1 solr
デフォルトの8983番ポートで起動。
$ cd solr
$ ./bin/solr start
コアを新規作成する。
solrコマンドのヘルプは./bin/solr create_core -help
などと打てば見られる。
$ ./bin/solr create_core -c xray -d sample_techproducts_configs
Servlet Filter
GradleやMavenでのビルド方法がよく分からないので、とりあえず必要そうなJARを持ってきてぶち込んだ。
$ curl -sL 'http://central.maven.org/maven2/com/amazonaws/aws-xray-recorder-sdk-core/1.0.4-beta/aws-xray-recorder-sdk-core-1.0.4-beta.jar' -o aws-xray-recorder-sdk-core-1.0.4-beta.jar
$ curl -sL 'http://central.maven.org/maven2/com/amazonaws/aws-java-sdk-core/1.11.91/aws-java-sdk-core-1.11.91.jar' -o aws-java-sdk-core-1.11.91.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-databind/2.8.6/jackson-databind-2.8.6.jar' -o jackson-databind-2.8.6.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.8.6/jackson-dataformat-cbor-2.8.6.jar' -o jackson-dataformat-cbor-2.8.6.jar
$ curl -sL 'http://central.maven.org/maven2/commons-logging/commons-logging/1.2/commons-logging-1.2.jar' -o commons-logging-1.2.jar
$ curl -sL 'http://central.maven.org/maven2/joda-time/joda-time/2.9.7/joda-time-2.9.7.jar' -o joda-time-2.9.7.jar
$ curl -sL 'http://central.maven.org/maven2/software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2.jar' -o ion-java-1.0.2.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-annotations/2.8.6/jackson-annotations-2.8.6.jar' -o jackson-annotations-2.8.6.jar
$ curl -sL 'http://central.maven.org/maven2/com/fasterxml/jackson/core/jackson-core/2.8.6/jackson-core-2.8.6.jar' -o jackson-core-2.8.6.jar
$ mv *.jar /home/ec2-user/solr/server/solr-webapp/webapp/WEB-INF/lib/
/home/ec2-user/solr/server/solr-webapp/webapp/WEB-INF/web.xml
にAWSXRayServletFilter
の設定を追加。
SolrRequestFilter
の手前に入れた。
<filter>
<filter-name>AWSXRayServletFilter</filter-name>
<filter-class>com.amazonaws.xray.javax.servlet.AWSXRayServletFilter</filter-class>
<init-param>
<param-name>fixedName</param-name>
<param-value>xray-solr</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AWSXRayServletFilter</filter-name>
<url-pattern>/solr/*</url-pattern>
</filter-mapping>
リクエストとトレースの確認
node.jsとSolrを起動してxray-web
にリクエストを投げてみる。
トレース結果は下記のようになった。
時間がずれるとこううまく表示されないのが気持ち悪い。
なにが悪いのか・・・