Firebase RealtimeDatabaseに大量データ投入　-　その4　-

GYAOのtsです。

#経緯
[前回の投稿](https://qiita.com/tstakano-yj/items/121abb3a21da7c961ae7)で一通り機能は揃ったので、テストや監視を設定してみる。

今回はかなり奮闘した。負荷テストの500万件登録は何度やったことやら。クラウドの使用料金がどこまで行くか心配。。。

#監視
functionsのログはすべてCloudLoggingに集約されるので、指標を作成し、それに引っかかったら通知を出す設定を行う。
通知先はSlack。

* stackdriver Loggingで下記のフィルタを設定

```:フィルタ設定
resource.type="cloud_function" OR resource.type="gcs_bucket"
severity>=WARNING
```

* 指標を作成する
<img width="1244" alt="スクリーンショット 2018-07-12 14.07.12.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/955ea3e2-a0cf-a9ae-1679-1d1496b1aa36.png">

* 指標から通知を作成する
<img width="1238" alt="スクリーンショット 2018-07-12 14.10.25.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/c74bc0cb-0271-9f1f-bb5a-d17b43dd567b.png">

<img width="871" alt="スクリーンショット 2018-07-12 14.18.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/fb599bef-b9f9-c7c6-98c2-1943ada7455c.png">

* 通知先をSlackに
<img width="676" alt="スクリーンショット 2018-07-12 14.19.55.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/cadb15d3-c585-6929-8244-3f943166bcb3.png">

完了。

#Unit test
* ディレクトリ構成
<img width="270" alt="スクリーンショット 2018-07-11 15.58.32.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/e471594b-380c-dada-2993-9c8555364bfe.png">

* テストコードと起動
 
```js:unit.box.aggregator.test.js
const test = require('ava');
const sinon = require('sinon');

const authenticate = require('../index').authenticate;
const StateContext = require('../state-context');
const userState = require('../user-state');
const messageState = require('../message-state');

test.cb('StateContext.getState: should get the correct state messages.', t => {
    t.plan(1);
    const stateContext = new StateContext('messages/test.json');
    t.is(typeof stateContext.getState(), typeof messageState);
    t.end();
});

test.cb('StateContext.getState: should get the correct state users.', t => {
    t.plan(1);
    const stateContext = new StateContext('users/test.json');
    t.is(typeof stateContext.getState(), typeof userState);
    t.end();
});

test.cb('StateContext.getState: should throw the exception because of invalid directory.', t => {
    t.plan(1);
    try {
        new StateContext('hoge/test.json');
    }
    catch (e) {
        t.pass();
        t.end();
        return;
    }
    t.fail();
    t.end();
});


and so on...
```

* 結果

```bash
$ npm t

> functions@ test /Users/tstakano/IdeaProjects/BoxAggregatorFunctions/functions
> ava



  10 tests passed

```
sinonを使ってオブジェクトのモックを使用したテスト（オブジェクトの振る舞い偽装してのテスト）を行おうと思ったが、大したことはやっていないのと、それをやると偽装だらけになってあまり旨味がなさそうだったので（特にDB周り）、下記の方針で進めた。

* ロジックを書く場合は極力関数として出せるものはexportsし、test対象。
* ロジックのあまり入っていないevent triggerの部分やDBに近い部分は無理やりunitテストしない。

なので、cron起動の認証周りと上記のstateパターンもどきのオブジェクト切り替えロジックをテスト対象とした。

#Stress Test
高負荷時の挙動を見るためにストレステストを行う。
シナリオは10000行の[json lines](http://jsonlines.org/)が1ファイル記述されていて、それが連続で500ファイルcloud storageにアプロードされる。
結果500functions起動されて、firebaseに対してそれぞれのfunctionが10000件のupdateを試みることになる。

* ファイル作成

[dummy-json](https://github.com/webroo/dummy-json)を使用して500万行の[json lines](http://jsonlines.org/)作成する。

```bash
$ npm install -g dummy-json
$ vim user.hbs
```
```json:user.hbs
{{#repeat 5000000 comma=false}}
{"userId" : "user-{{@index}}", "messageId": "941"}
{{/repeat}}
```
```bash
$ dummyjson user.hbs > user.csv
```

* ファイル分割

```bash
$ split -l 10000 user.csv test_
for f in test_??;do mv $f $f.csv;done
```

* upload

まとめて一気にupload。
<img width="423" alt="スクリーンショット 2018-07-12 12.52.09.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/1aa722f4-e726-d3e6-a1d9-ff6fdc577e17.png">

* 実行結果

各Functionが10000件ずつさばく。終わるまで20分位。
CloudLogging
<img width="660" alt="スクリーンショット 2018-07-12 12.54.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/fc0bcfa5-1f06-4370-023f-8b0dee74f274.png">

Firebaseからjsonをexportする。247MBある。。。
<img width="786" alt="スクリーンショット 2018-07-12 12.57.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/22ab1397-b13f-1b18-1def-6d713721e857.png">


```bash
$ grep -c 'user-' export.json 
5000000
```
500万件登録済みが確認できた。

#その他

## Storageバケットライフサイクル
このままだとStorageにファイルが無限に溜まっていくので、ライフサイクルを設定する。

* CloudStorageの対象バケットのライフサイクルをクリック

<img width="146" alt="スクリーンショット 2018-07-12 14.23.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/eb90ce2a-e605-7af2-78ee-a7b75720f23d.png">

* ルールを追加して完了
<img width="662" alt="スクリーンショット 2018-07-12 14.25.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/114329/fbcbb5ca-09b1-5952-223f-a5eaea2f5323.png">