AWSのAutoScalingを利用して、td-agentクラスタを準備する


##検証を思いついた経緯

* appサーバ側のforward設定で複数の`<server>`タグを管理したくない
* td-agentのconfigに影響されず、AWSメンテナンスやインスタンス障害の対応を行いたい
* アプリケーションが乗るappサーバと違い、td-agentクラスタは純粋に負荷を見極めやすいため、AutoScalingに適している
* fluentdのコミュニティで「TCPロードバランシングはユーザ側で試して欲しい」という状況で更新が止まっていた
  https://groups.google.com/forum/#!topic/fluentd/3ZuG_1dPovE


##td-agentクラスタ環境準備

###1.環境構成

今回、VPC,SecutityGroup,AMIの作成方法は割愛。
以下の環境を準備する。

![Untitled.png](https://qiita-image-store.s3.amazonaws.com/0/14190/1043cc39-f889-f790-da15-e34cadcce0c4.png "Untitled.png")

###2.appインスタンスのtd-agent設定

```bash
<source>
  type forward
</source>

<match *.**>
  type copy
  <store>
    type forward
    heartbeat_type tcp
    <server>
      host td-agent-elb-internal-1234567890.ap-northeast-1.elb.amazonaws.com
      port 24224
    </server>
  </store>
</match>
```

`heartbeat_type tcp` ここが今回の一番の肝。
fluentdのハートビートはデフォルトでUDPだが、ELBのListers設定はTCPで行う必要があるため、fluentdのハートビートをTCPで行う。

###3.内部ELB
```bash
aws elb create-load-balancer \
	--load-balancer-name td-agent-elb-internal \
	--listeners Protocol=TCP,LoadBalancerPort=24224,InstanceProtocol=TCP,InstancePort=24224 \
	--subnets subnet-aaaaaaaa \
	--security-groups sg-bbbbbbbb \
	--scheme internal
```
ELBのLisners設定できるのは、TCP,HTTP,HTTPS,SSLのみ。
Lisners側でtd-agentインスタンスの24224ポートへの連携を設定する。

###4.td-agentインスタンスのtd-agent設定
```bash
<source>
  type forward
</source>

#下記は環境によって変更する。
<match *.**>
  type stdout
</match>
```

今回の`<match *.**>`配下はテスト用。
実運用上はここに各種設定を記載する。


###5.AutoScaling
####Launch Configuration
```bash
aws autoscaling create-launch-configuration \
	--launch-configuration-name fluent-as-configuration \
	--image-id ami-cccccccc \
	--key-name xxxx \
	--security-groups sg-bbbbbbbb \
	--instance-type t2.micro \
	--associate-public-ip-address
```
`--image-id ami-cccccccc`は、td-agentインスタンスのAMIを指定する。
`chkconfig --list`などでtd-agentが自動起動することをお忘れなく。

####Auto Scaling Group
```bash
aws autoscaling create-auto-scaling-group \
	--auto-scaling-group-name fluent-as-group \
	--launch-configuration-name fluent-as-configuration \
	--min-size 1 \
	--max-size 2 \
	--desired-capacity 1 \
	--availability-zones ap-northeast-1b \
	--load-balancer-names td-agent-elb-internal \
	--health-check-type EC2 \
	--vpc-zone-identifier subnet-aaaaaaaa \
	--tags Key=Name,Value=fluent-as
```
####Scaling Policies
```bash
aws autoscaling put-scaling-policy \
	--auto-scaling-group-name fluent-as-group \
	--policy-name ScaleOut \
	--scaling-adjustment 1 \
	--adjustment-type ChangeInCapacity
```

##td-agentクラスタ検証
###1.td-agentクラスタのスケールアウト
テスト用に以下のようにCPU使用率を0%以上になったら、スケールアウトするように設定する
![Scalingポリシー設定.png](https://qiita-image-store.s3.amazonaws.com/0/14190/02d23ab5-c3f3-9207-06f9-8c96c2ba666e.png "Scalingポリシー設定.png")

こんな感じで、ELB配下に追加のtd-agentインスタンスが準備される
![EC2追加.png](https://qiita-image-store.s3.amazonaws.com/0/14190/04c19665-b170-965c-af56-e05fef27b0e1.png "EC2追加.png")


###2.appインスタンスから、ログを送信
appサーバからfluent-catを使って、td-agentクラスタに1万件のログ送信を試してみた結果は以下の通り

|検証内容|結果|備考|
|:--|:--|:--||
|2台のtd-agentインスタンスをぶら下げる|td-agent1:5,012件<br>td-agent2:4,988件|
|1台のtd-agentを落として、復帰させる|td-agent1:8,200件<br>td-agent2:1,800件|障害などでELBのヘルスチェックにひっかかったケース|
|ログ送信中にDesiredCapacityを増やす|td-agent1:326件<br>td-agent2:351件<br>td-agent3:9,323件|AutoScalingでインスタンスが増えたケース|


##まとめ
td-agent(fluentd)は、tcpでもロードバランシングしてくれることが確認できた。
今回の検証ではAutoScalingで追加したインスタンスにログ送信が偏ってしまったが、これはELBの振り分けルールによるものと考えられる（新規追加されたインスタンスは、負荷が少ないと認識される？）
ログの欠損もない模様なので、ひとまず実運用に耐えられそうかなと。