EatSmartシステム部ブログ

ウェブサイトの開発や運営に関する情報です。

クスパ決済サービス開始しました

以前、クスパ決済の導入に向けた記事を紹介しましたが、2020年1月7日に無事サービス開始しました。 当初、2019年12月にサービス開始する予定でしたが、ある要因で2020年1月7日サービス開始となりました。 まずは、リリース延期となった経緯を紹介します。

eatsmart.hatenablog.com

リリース延期になった経緯

決済代行経由でクレジット会社の利用審査をお願いしておりましたが、当初予定していたよりも審査が長引いたことが原因でした。
決済代行会社のお話によると、BtoC系サービスの場合、ECでのクレジットカード利用は割と審査が通りやすいらしいのですが、クスパ決済(レッスン予約時のクレジットカード利用)は、役務提供サービスに該当する為、予定していたよりも各クレジット会社の審査に時間が掛かったとのお話でした。
最終的には、VISA/Master/JCB/Diners Club/American Express 5社全て審査が通り、無事サービス開始することが出来ました。
決済代行会社にもよるかと思いますが、今後、役務提供のオンライン決済を導入される方は、余裕をもって準備されることをオススメします。


次に、今回クスパ決済のサービス開始するに辺り、リリースタイミングを調整して利用促進を図った点を紹介します。

利用促進を図った点

そもそも、クスパ決済はレッスン予約を行う際にクスパ経由でオンライン決済してもらうサービスになりますが、クスパ決済で支払いして頂く為には下記3つの条件が必要となります。

  1. 料理教室の先生に、クスパ決済の利用申請をしてもらう必要がある

  2. 利用申請して頂いた料理教室の先生が、レッスン登録する際にクスパ決済の支払い方法選択してもらう必要がある

  3. ユーザーがレッスン予約する際に、支払い方法でクスパ決済を選択してもらう必要がある

上記条件で(1)(2)の数が増えないと、最終的にユーザーがクスパ決済での予約が行えません。
そこで(1)→(2)→(3)の順で、段階的にリリースする事にしました。

リリースタイミングを分ける事で、開発プロジェクトのバージョン管理や、リリース毎に必要なDDL/DMLの整理等が大変でしたが、結果、1月7日のユーザー向けサービス開始のタイミングで、ある程度クスパ決済での支払いが行えるレッスン数を揃える事ができました。

サービス設計される際に、リリースタイミング等は見落としがちなので参考にしてみて下さい。

サービス開始後のユーザーの反応について

1月7日サービス開始してからのユーザーの反応ですが、徐々にクスパ決済の利用者が増えつつある傾向ですが、事前アンケート等で想定していたより利用頻度が少ない状況です。
現時点での要因ですが、

  • 全体のレッスン数に対して、クスパ決済での支払いが行えるレッスン数少ない

  • ユーザーにクスパ決済のアピールが行えていない

等があります。上記に対して、プロモーションやサイト改善等を行っていく予定です。 今後、料理教室の予約をされる方がいらっしゃる様でしたら、クスパ決済を是非活用してみて下さい。

cookingschool.jp

2019年を振り返って

もうすぐ2019年も終わりになりますが、システム部の2019年を振り返ってみたいと思います。

サービス面での振り返り

弊社のサービス的には、時系列で振り返ると

  • 1月〜3月 クスパ 先生向け有料サービスの改善
  • 4月〜7月 もぐナビスマフォ版UI改修
  • 8月    クスパ 稼働サーバー移設
  • 9月〜12月 クスパ レッスン決済サービス開発(年明けリリース!)

のようなことを実施してきました。

ブログ記事を振り返ってみても、ところどころ、これらに絡んだ記事が投稿されていたなあと思いました。

内容的な振り返り

投稿を振り返って印象的だったものを挙げます。

React

もぐナビのUI改修でReactを使用したのですが、随所で新しいものを使うのは各自の判断でちょこちょことあったのですが、まとまった形での実装技術の採用は久しぶりだったと思います。

今までのなんとなくウォッチはしていたのですが、Redux含め内容や構造をきちんと理解して使えるようになるまでは、少し慣れが必要でした。ただ、慣れてくると、確かにちょっと凝ったUIの実装が簡単にできて、便利でした。まあ、イベントドリブンで裏にロジックを書くところが、昔々やったVisualBasicを思い出す感じでしたけど!

インフラ周り

今年もサーバーの移設やら再構成やらで、dockerコンテナ関連のインフラを色々と扱いました。

オーバーレイネットワーク

弊社のサービスでは、ひとつのdocker基盤の中に複数のサービスを動作させているのですが、環境を分離するために、サービスごとにオーバーレイネットワークを作成してネットワークを仮想的に切り離しています。

もともと基盤を構築する時に、コンテナのオーケストレーションツールとしてswarmを使う計画で、オーバーレイネットワークもswarmで構築しました。ただ、デプロイ時のローリングアップデートでの諸問題やswarm自体の安定性に不安があったため、オーバーレイネットワークの基盤としてのみswarmを使っていました。

今年、クスパ 稼働サーバー移設でインフラの見直しをした際に、オーバーレイネットワークもswarmではなくKVSを使ったものに置き換えようと検討して、etcdを使ったオーバーレイネットワークをテストしました。ただ、残念ながらetcdでのオーバーレイネットワークも安定性に不安がある結果となったため、現在もswarmでのオーバーレイネットワークを使用しています。

コンテナ技術について

弊社のサービスは、基本的にJavaを使っています。インフラをdockerに移行した時に、tomcatベースのコンテナやspring-bootを使ってwebサービスを作っていました。その後にJavaを稼働させるコンテナで新しい種類のものが出てきたので、micronautやJibなどを色々と使ってみました。

サーバー移設

ここ最近は、年に1回くらいiDCをまたいでのサーバー移設の作業を行なっているので、サービスは違えど手順はだいぶ確立されてきました。今年はクスパ のサービスを手慣れた手順で移設しました。

Google CoreUpdate

毎年、年に数回はGoogleの変動は発生してきたのですが、昨年までは明らかに悪いSEOをしているコンテンツが落とされている印象でした。今年はGoogle自身がCoreUpdateと銘打って数回の変動を実施しましたが、良い影響も悪い影響もありました。

Googleとしては、ただキーワードの結果を表示するのではなく、ユーザーの検索意図に踏み込んで結果を表示するとのことで、その結果としてうちのサイトが合っていたり合っていなかったりしているんだろうなとは思いますが、以前内容が薄くて落とされた(と思われる)サイトがうちのサイトより上に表示されるようになっていると、少し複雑な気持ちにはなります。(けしてGoogle様に逆らう意図ではありません)

その他

ブログの継続

週1で記事を投稿しようと決めて運用していて、たまに投稿できない週もありましたが、概ね毎週続けられたことがとても嬉しかったです。

ひとりの努力の結果ではないので、個人的な達成感という訳では無いですが、決めたことを続けていって積み重ねるのはチームでも個人でも意識の賜物だと思います。今後は、より情報の質も意識して配信していきたいです。

新人の成長

で、ブログを振り返ってみた時に、新人が書いていた記事が、初めの頃はJavaSQLの基礎中の基礎的な内容だったのが、色々と業務をこなせる所まで少しづつですが成長していることを感じました。とは言え、エンジニアとしてはまだまだ知らないといけないことだらけなんですが、こうやって振り返って歩みが見えるのも良いことだと思いました。

以上、まとまりのない投稿となりますが、これを今年のまとめとしたいと思います。

ZabbixからSSL証明書の有効期限を監視する

先日、一部のサービスで利用しているSSL証明書の有効期限が切れる障害を起こしてしまいました。 SSL証明書にはLet’s Encrypを利用しており、事前に通知が来ていたにも関わらず、更新を忘れてしまっていました。 これをふまえて、業務フローを見直すとともに、SSL証明書の有効期限をZabbixで監視することにしました。

Zabbixから監視するには、以下の記事を参考にしました。

ZabbixでSSL証明書有効期限を監視する - Qiita

違いとしては、スクリプトをZabbixサーバに配置せず、監視対象のWebサーバのメトリクスとして残り日数を取得するようにしました。

SSL証明書の残り日数は、以下のスクリプトで取得します。 引数でホスト名を指定出来るようにしてあります。

date +"%s" --date="`openssl s_client -connect $1:443 -servername $1 </dev/null 2>/dev/null | openssl x509 -enddate -noout | cut -d'=' -f2`" | awk '{printf("%d\n",($0-systime())/86400-1/86400+1)}'

監視対象の zabbix_agentd.conf へ、以下を追加します。 Zabbixで指定したホスト名を、上記スクリプトへ渡すようにしています。

UserParameter=ssl_cert_days.[*], /var/git/infra/bin/ssl_cert_days.sh $1

続いてアイテムを作成します。 Typeでホスト名を指定しています。

項目
Name ssl_cert_days.example.com
Type Zabbix agent
Key ssl_cert_days.[example.com]
Update interval 1d

アイテムの次はトリガを作成します。 余裕を持って14日前に通知が来るようにして、SSL証明書を更新するようにします。

項目
Name ssl certificate of example.com has expired
Severity Warning
Expression {zabbix-server:ssl_cert_days.[example.com].last()}<14

以上で、ZabbixからSSL証明書の有効期限を監視する仕組みをつくることが出来ました。

Talend API Testerを使ってみる

今回は、API開発やテストなどに使える便利なツールTalend API Testerをご紹介します。
※最近、プロダクト名の変更があったようなので調べる際には、Talend API Testerに変えて Restlet Clientでも情報が多くヒットします。

Talend API Testerについて

詳細については、以下に譲りますがブラウザベースで、APIの結果を確認できるChrome拡張機能です。 基本的には、リクエストしたURLに対するAPIの返却結果の確認や渡すパラメーターの正当性を確認する テストなどに使えるかと思います。 Talend API Tester概要

ツールの導入に関して

https://chrome.google.com/webstore/detail/talend-api-tester-free-ed/aejoelaoggembcahagimdiliamlcdmfm/reviews?hl=ja&utm_source
上記サイトから、Googleアカウントにログイン状態で「Chromeに追加」を選択し、「拡張機能を追加」で TalendAPI Tester(無償版)が利用できるようになります。 f:id:eatsmart:20191206150214p:plain
Chromeのメニューバーからアプリの利用ができます。

POSTメソッドを試す

弊社で提供しているサービスカロリーチェックAPIを用いて、 まずはPOSTでのリクエストで、食品に関するカロリーデータを取得してみます。 APIの仕様上、まずは認証キーを取得する必要があるため、POSTメソッドで認証キーを取りに行きます。 画面に「METHOD」と書かれたタブをPOSTにし、URL入力覧にリクエストするためのURLを入れます。 パラメーターとして、siteId(コンテンツ利用に必要なID)とpasswordが必要になるため、「QUERY PARAMETERS」の欄で 参考画像のようにパラメータをセットします。 f:id:eatsmart:20191206150908p:plain

セット完了後、「send」を押すとレスポンスが確認ができます。 f:id:eatsmart:20191206151044p:plain

authkeyが取得できているのが確認できます。 また、ステータス0は「正常」を指すので正しくリクエストしていることになります。

GETメソッドを試す

前項で得られたauthKeyを利用し、六花亭のマルセイバターサンドの食品データを取得していきます。 次は、GETメソッドでリクエストするので、「METHOD」をGETにします。例にならって、「QUERY PARAMETERS」でパラメーターをセットします。authKeyに加えて、今度は食品に割り当てられたfoodCodeも追加し、リクエストを送信します。
f:id:eatsmart:20191206151322p:plain

200OKとともに、食品名、カテゴリー名、店舗名などが返却されているのが確認できます。
f:id:eatsmart:20191206153834p:plain

また、フリーワードでAPIに対してリクエストした場合、freeword(ピスタチオで検索)に加えて、offset,limitをパラメーターで 渡すことで以下のような結果が確認できます。 f:id:eatsmart:20191206155935p:plain

 その他便利な機能

よく使うリクエストを保存して、次回使う際に呼び出すことができるSave機能があります。 右上の「Save as」を選択し、プロジェクト(例:カロリーチェック)を作成し、そのプロジェクト内に 使用したリクエストを保存しておくだけです。左のメニューにプロジェクト及びリクエスト名が確認 できるので、そちらからデフォルトでURL、パラメーターが予め設定されたものが利用できるようになります。 f:id:eatsmart:20191206152006p:plain 返却結果をCSVファイルとしてエクスポートすることもできます。

まとめ

以上となりますが、ブラウザからAPIをたたき、テスト結果を簡単に確認できるので、IDEなどを立ち上げる必要がない分、 便利に感じると思います。特定の開発環境を構築する必要もないので、例えばAPIの返却結果を他人と共有して見たいなど 開発に限定しないシーンでも広く使えるのではないでしょうか。

SMTPサーバーの逆引きエラーについて

今回は弊社で運用しているSMTPサーバー(postfix)で発生したメール送信時の逆引きエラーの調査及び対処方法についてを記事にしてみました。

正引き/逆引きとは

ドメイン名に対応するIPアドレスを問い合わせることを「正引き」と言います。正引きは、主にWEBページの閲覧時URLを指定して参照する際に利用されます。
上記に対して、IPアドレスに対応するドメイン名を問い合わせることを「逆引き」と言います。逆引きは、主にサーバ側においてアクセス元を判別したい時に用いられます。

SMTPサーバーのエラーログについて

逆引きエラーが発生した際のSMTPサーバーのログには下記の様なエラーが出力されます

Client host rejected: cannot find your reverse hostname, [100.100.10.10]

実際のログ
2019-10-1T12:52:15.642892+09:00 xxxxxxxxxx postfix/smtp[xxxx]: xxxxxxxxxx: to=<aaa@test.com>, relay=xxx.xxxx.jp[xxx.xxx.xxx.xxx]:25, delay=xxxxx, delays=xxxxxxxxxx, dsn =4.7.1, status=deferred (host xxx.xxxx.jp[xxx.xxx.xxx.xxx] refused to talk to me: 450 4.7.1 Client host rejected: cannot find your reverse hostname, [100.100.10.10])

なぜ逆引きチェックを行うのか?

インターネット上ではスパムメールが頻繁に送信されており、スパムメールを送信する業者は身元を隠すために、わざと「ドメイン」と「グローバル IP」を一致させないように設定しています。
スパムメール送信業者からすると、グローバルIPアドレスを特定されるとISPも特定され、アカウントを削除されたりブロックされてしまうことを防ぐために隠す必要があります。
上記理由から、各メールサーバーはドメイン名とグローバルIPの正引き←→逆引きの結果が一致するかを検証し、一致する場合のみメール送信を許可しています。
※逆引きチェックは全てのメールサーバーが取り入れている訳では無いので、逆引き設定を行っていなくても送信できる場合もありますが、送信不達を防ぐ為にも設定する事をオススメします。

正引き←→逆引きでチェックOKのケース
メールサーバーのドメイン名:test.com
メールサーバーの IP アドレス:100.100.10.10
100.100.10.10 の逆引き結果:test.com
正引き←→逆引きでチェックNGのケース
メールサーバーのドメイン名:test.com
メールサーバーの IP アドレス:100.100.10.10
100.100.10.10 の逆引き結果:aaaa.com

※逆引きチェックで一致しない場合及び逆引きの結果が返却されない場合何れもエラーとなります

逆引設定を行う

弊社はインフラサービスにさくらインターネットを利用しておりますが、逆引き設定は各ベンダーによって異なりますので参考まで。

さくらのクラウド > ルータ+スイッチIPアドレスの逆引き設定

manual.sakura.ad.jp

▼さくらのVPS > DNS逆引きレコードを変更する

help.sakura.ad.jp

さくらのクラウド > DNS逆引きレコードの設定

manual.sakura.ad.jp

▼【さくらの専用サーバ】DNS逆引きレコード設定・変更

help.sakura.ad.jp

正引き/逆引きが正しく設定されているかを確認するには

Windowsで正引き/逆引きが正しく設定されていることを確認する場合は、nslookupコマンドを利用します。

正引きの確認結果
C:\Users\test>nslookup test.com
サーバー:  aaaa.test.local:DNSサーバー
Address:  192.168.10.10

名前:    test.com
Address:  100.100.10.10
逆引きの確認結果
C:\Users\test>nslookup 100.100.10.10
サーバー:  aaaa.test.local:DNSサーバー
Address:  192.168.10.10

権限のない回答:
名前:    test.com
Address:  100.100.10.10
※「権限のない回答とは」DNSキャッシュを使って回答している事を示している

逆引き設定後のSMTPログ確認

逆引き設定後、SMTPサーバーのログにて正常に送信(status=sent)出来ている事を確認します。

実際のログ
2019-10-1T13:22:15.801774+09:00 xxxxxxxxxx postfix/smtp[xxxx]: xxxxxxxxxx: to=<aaa@test.com>, relay=xxx.xxxx.jp[xxx.xxx.xxx.xxx]:25, delay=xxxxx, delays=xxxxxxxxxx, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as xxxxxxxxxx)

まとめ

メール送信時に不達となる原因は色々考えられますが、今回は逆引きエラーを記事にしてみました。
インフラ担当でないとメールサーバーに触れる機会が少ないとは思いますが、トラブルシューティングの参考になりれければ幸いです。

さくらウェブアクセラレータで使うドメインのSSL証明書更新

弊社ではサイトのCDNとして「さくらウェブアクセラレータ」を利用していて、そのドメインの証明書はLet's Encryptで発行しています。 Let's Encryptの証明書は有効期限が90日なので、3ヶ月に一度くらい証明書の入れ替えが必要です。

運用を始めた頃は、実体のサーバーがCDNの背後にあるので、証明書発行を毎回DNS認証で行なっていたのですが、良く考えたらACMEでも認証tokenは毎回発行されるので、オリジンサーバー上でcertbotを実行することで発行することができるなあと思いました。

ネットで色々と調べて、結果、証明書の入れ替えまでを自動化できたので、その方法を記事にしたいと思います。

Let's Encryptの証明書発行

ACMEのためのwebサーバー設定

弊社のサイトのフロントエンドはnginxを使用しているのですが、ACMEのために.well-knownフォルダにアクセスできるようにオリジンサーバーのnginxのconfに以下の設定を追加します。

location /.well-known {
  root /var/www/nginx/certbot;
}

証明書発行

オリジンサーバー上で、以下のコマンドを実行します。

certbot-auto certonly --webroot -w /var/www/nginx/certbot -d ドメイン名 -m root@eatsmart.co.jp --agree-tos -n

これで、オリジンサーバーの/etc/letsencrypt/live/ドメイン名配下に証明書と鍵が生成されます。

証明書更新

さくらウェブアクセラレータのAPIを使用することで、証明書の更新を自動化することができます。

参考)
公開API | さくらのクラウド ドキュメント

まずは、以下のURLからAPIキー(アクセストークン、トークンシークレット)を発行する必要があります。

SAKURA internet Cloud - Home

サイトID取得

初回は、まず操作対象のサイトIDを取得する必要があります。 サイトIDは、以下のコマンドで確認できます。

$ curl -X GET --user "アクセストークン":"トークンシークレット" \
https://secure.sakura.ad.jp/cloud/zone/is1a/api/webaccel/1.0/site
{
    "Total": 3,
    "From": 0,
    "Count": 3,
    "Sites": [
        {
            "Index": 0,
            "ID": "XXXXXXXXXXXXXX",
            "Name": "cdn1.esimg.jp",
            "Domain": "cdn1.esimg.jp",
            "DomainType": "own_domain",
・・・
    ],
    "is_ok": true
}
(JSONを整形しています)

このIDの値を使用します。

証明書更新

更新は以下のコマンドでできます。

curl -X PUT --user  "アクセストークン":"トークンシークレット" \
https://secure.sakura.ad.jp/cloud/zone/is1a/api/webaccel/1.0/site/113000168864/certificate \
-d "{\"Certificate\": { \"CertificateChain\": \"$(perl -pe 's/\n/\\n/' /etc/letsencrypt/live/ドメイン名/fullchain.pem | perl -pe 's/\\n$//')\", \"Key\": \"$(perl -pe 's/\n/\\n/' /etc/letsencrypt/live/ドメイン名/privkey.pem | perl -pe 's/\\n$//')\" }}"

まとめ

上のふたつをまとめ、以下のようなシェルを作って更新するようにしました。

$ cat replace_cdn_cert.sh
#!/bin/sh

TARGET=$1
SITE_ID=$2
echo 'target:'$TARGET
echo 'siteId:'$SITE_ID

certbot-auto certonly --webroot -w /var/www/nginx/certbot -d $TARGET -m root@eatsmart.co.jp --agree-tos -n

curl -X PUT --user "アクセストークン":"トークンシークレット" \
https://secure.sakura.ad.jp/cloud/zone/is1a/api/webaccel/1.0/site/$SITE_ID/certificate \
-d "{\"Certificate\": { \"CertificateChain\": \"$(perl -pe 's/\n/\\n/' /etc/letsencrypt/live/$TARGET/fullchain.pem | perl -pe 's/\\n$//')\", \"Key\": \"$(perl -pe 's/\n/\\n/' /etc/letsencrypt/live/$TARGET/privkey.pem | perl -pe 's/\\n$//')\" }}"

$ ./replace_cdn_cert.sh cdn1.esimg.jp XXXXXXXXXXXXXX

これで、証明書更新の通知が憂鬱ではなくなりました!

Zabbix から Spring Boot アプリケーションのデータベース接続状況を取得する

イートスマートでは、Zabbixで各サーバやコンテナのリソースを管理し、必要に応じてアラートを飛ばしています。 先日、データベースの接続数が増えてきたのでコンテナごとに接続数を把握しようと思い、Zabbixのテンプレートを使い以下の2つの項目を監視するようにしました。

jmx["Catalina:class=javax.sql.DataSource,context=/,host=localhost,name=\"database\",type=DataSource",numActive]
jmx["Catalina:class=javax.sql.DataSource,context=/,host=localhost,name=\"database\",type=DataSource",numIdle]

それぞれ接続数とアイドル数です。 Tomcatを利用するアプリケーションは問題なく取得出来ましたが、Spring Bootを利用するアプリケーション(以降Spring Bootアプリ)で取得出来ませんでした。 Spring Bootアプリに必要となった設定をまとめます。Spring Bootのバージョンは少し古く1.5.2となります。

データベス接続情報

spring:
  profiles: stg
  datasource:
    driverClassName: org.postgresql.Driver
    url: jdbc:postgresql://xxxx.xxxx.xxxx:5432/xxxx
    username: xxxx
    password: xxxx
    jmx-enabled: true

新たに spring.datasource.jmx-enabled: true という設定が必要になりました。 application.ymlへは、以下のように追加しました。

起動オプション

java -Dcom.sun.management.jmxremote \
  -Dcom.sun.management.jmxremote.port=[JMXポート番号] \
  -Dcom.sun.management.jmxremote.authenticate=false \
  -Dcom.sun.management.jmxremote.ssl=false \
  -Dcom.sun.management.jmxremote.rmi.port=[JMXポート番号] \
  -Djava.rmi.server.hostname=[ホストIPアドレス] \
  ....

アプリケーション起動時に、JMXで利用するポート番号等の設定を追加しました。 ホストのIPアドレスを指定しているのは、Dockerコンテナで起動する場合にポートフォワードでは動かないためです。 そのたりは以下に書いています。

eatsmart.hatenablog.com

動作確認

上記の設定を行い起動すると、ログに以下のようにMBeanの登録情報が出力されます。

2019-11-19 16:22:31.077  INFO 15636 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2019-11-19 16:22:31.079  INFO 15636 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Bean with name 'dataSourceMBean' has been autodetected for JMX exposure
2019-11-19 16:22:31.084  INFO 15636 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Located MBean 'dataSourceMBean': registering with JMX server as MBean [org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool]

この情報をもとに接続します。接続には、javaから手軽に利用できる jmxterm を利用します。

docs.cyclopsgroup.org

java -jar jmxterm-1.0.0-uber.jar
$>open xxx.xxx.xxx.xxx:12345
#Connection to xxx.xxx.xxx.xxx:12345 is opened
$>info -b org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool
#mbean = org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool
#class name = org.apache.tomcat.jdbc.pool.jmx.ConnectionPool
# attributes
  %0   - AbandonWhenPercentageFull (int, rw)
  %1   - AccessToUnderlyingConnectionAllowed (boolean, rw)
  %2   - Active (int, r)
  %3   - AlternateUsernameAllowed (boolean, rw)
  %4   - BorrowedCount (long, r)
  %5   - CommitOnReturn (boolean, rw)
  %6   - ConnectionProperties (java.lang.String, rw)
  %7   - CreatedCount (long, r)
  %8   - DataSource (java.lang.Object, rw)
  %9   - DataSourceJNDI (java.lang.String, rw)
  %10  - DbProperties (java.util.Properties, rw)
  %11  - DefaultAutoCommit (java.lang.Boolean, rw)
  %12  - DefaultCatalog (java.lang.String, rw)
  %13  - DefaultReadOnly (java.lang.Boolean, rw)
  %14  - DefaultTransactionIsolation (int, rw)
  %15  - DriverClassName (java.lang.String, rw)
  %16  - FairQueue (boolean, rw)
  %17  - Idle (int, r)
  %18  - IgnoreExceptionOnPreLoad (boolean, rw)
  %19  - InitSQL (java.lang.String, rw)
  %20  - InitialSize (int, rw)
  %21  - JdbcInterceptors (java.lang.String, rw)
  %22  - JdbcInterceptorsAsArray ([Lorg.apache.tomcat.jdbc.pool.PoolProperties$InterceptorDefinition;, r)
  %23  - JmxEnabled (boolean, rw)
  %24  - LogAbandoned (boolean, rw)
  %25  - LogValidationErrors (boolean, rw)
  %26  - MaxActive (int, rw)
  %27  - MaxAge (long, rw)
  %28  - MaxIdle (int, rw)
  %29  - MaxWait (int, rw)
  %30  - MinEvictableIdleTimeMillis (int, rw)
  %31  - MinIdle (int, rw)
  %32  - Name (java.lang.String, rw)
  %33  - NumActive (int, r)
  %34  - NumIdle (int, r)
  %35  - NumTestsPerEvictionRun (int, rw)
  %36  - Password (java.lang.String, rw)
  %37  - PoolName (java.lang.String, r)
  %38  - PoolSweeperEnabled (boolean, r)
  %39  - PropagateInterruptState (boolean, rw)
  %40  - ReconnectedCount (long, r)
  %41  - ReleasedCount (long, r)
  %42  - ReleasedIdleCount (long, r)
  %43  - RemoveAbandoned (boolean, rw)
  %44  - RemoveAbandonedCount (long, r)
  %45  - RemoveAbandonedTimeout (int, rw)
  %46  - ReturnedCount (long, r)
  %47  - RollbackOnReturn (boolean, rw)
  %48  - Size (int, r)
  %49  - SuspectTimeout (int, rw)
  %50  - TestOnBorrow (boolean, rw)
  %51  - TestOnConnect (boolean, rw)
  %52  - TestOnReturn (boolean, rw)
  %53  - TestWhileIdle (boolean, rw)
  %54  - TimeBetweenEvictionRunsMillis (int, rw)
  %55  - Url (java.lang.String, rw)
  %56  - UseDisposableConnectionFacade (boolean, rw)
  %57  - UseEquals (boolean, rw)
  %58  - UseLock (boolean, rw)
  %59  - Username (java.lang.String, rw)
  %60  - ValidationInterval (long, rw)
  %61  - ValidationQuery (java.lang.String, rw)
  %62  - ValidationQueryTimeout (int, rw)
  %63  - Validator (org.apache.tomcat.jdbc.pool.Validator, rw)
  %64  - ValidatorClassName (java.lang.String, rw)
  %65  - WaitCount (int, r)
# operations
  %0   - void checkAbandoned()
  %1   - void checkIdle()
  %2   - java.lang.Boolean isDefaultAutoCommit()
  %3   - java.lang.Boolean isDefaultReadOnly()
  %4   - void purge()
  %5   - void purgeOnReturn()
  %6   - void resetStats()
  %7   - void testIdle()
# notifications
  %0   - javax.management.Notification(INIT FAILED,CONNECTION FAILED,CONNECTION ABANDONED,SLOW QUERY,FAILED QUERY,SUSPECT CONNECTION ABANDONED,POOL EMPTY,SUSPECT CONNECTION RETURNED)

この出力内容から、今回必要なものが NumActive と NumIdle ということがわかったので、Spring Bootアプリ用のテンプレートを作成し、以下の2つの項目を監視するようにしました。

jmx["org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool",NumActive]
jmx["org.apache.tomcat.jdbc.pool.jmx:name=dataSourceMBean,type=ConnectionPool",NumActive]

まとめ

以上の作業で、イートスマートで利用しているコンテナのデータベース接続数を把握することが出来るようになりました。 実際の利用状況と照らし合わせ、コンテナの最小アイドル数が多かったので、減らすことで問題への対処を行うことが出来ました。