kasei_sanのブログ

かせいさんのIT系のおぼえがきです。胡乱の方はnoteとtwitterへ

nginx+pumaでRailsで動かす場合コネクションプールの数を増やさないと `ConnectionTimeoutError` が発生するよ

先に結論

pumaは worker * スレッド の数だけコネクションを使う

しかし、ActiveRecordのコネクションプールの数はデフォルトで 5

なので大抵不足する

コネクションが不足すると、DBへの接続リクエストは待ち状態に

待ち状態のまま一定時間が経過すると、ActiveRecord::ConnectionTimeoutError が発生

なので、ActiveRecordのコネクションプールを増やす必要がある

コネクションプールとは?

予め(今回の場合は)DBに接続しておいて、必要に応じてその接続を貸し与える仕組み

ActiveRecordのコネクションプールを増やす方法

config/database.ymlconnection_pool で設定

production:
  <<: *default
  database: <%= ENV['DB_NAME'] %>
  username: <%= ENV['USERNAME'] %>
  password: <%= ENV['PASSWORD'] %>
  host: <%= ENV['HOSTNAME'] %>
  port: <%= ENV['PORT'] %>%
  connection_pool: <%= ENV['MAX_CONNECTION_POOL'] || 5 %>

コネクションプールの数は、いくつが良いの?

puma の thread 数と同数とする。 database.yml に設定された pool の数はプロセスごとに確保される値なので、thread数を設定すれば十分。

ただし、 同時接続数が、DBの最大コネクション数を超えないこと

ElasticBeanstalkの場合

pumaのスレッド数は32

posgreSQLの最大コネクション数っていくつ?

RDSの(posgreSQL)の場合

DBInstanceClassMemory / 12582880 らしい

  • m1.smallで145とか
  • ElasticBeanstalkの場合、
    • pumaのworker数はコア数と同一なので、よっぽどアプリサーバとDBサーバの性能に差をつけなければ心配はなさそう

参考

「カンバン:ソフトウェア開発の変革」の読書メモ

カンバン: ソフトウェア開発の変革

カンバン: ソフトウェア開発の変革

カンバン手法の目的って何?

  • ワークフローの見える化による段階的なカイゼン
  • 仕掛り(WIP)制限による労働&成果物の質の向上

アジャイル開発手法のような定義されたフレームワークではなく、チーム毎の状況に応じてプロセスを進化させていく

チーム毎の状況に応じてプロセスを進化させていくことのメリット

  • 「できること」から始められるので、導入のハードルが低い
  • 最終的に各チーム毎に最適なプロセスになる(現実とフレームワークの乖離による問題が発生しない

アジャイル開発手法のカードウォールとの違い

アジャイル開発でよく「カンバン」と言われているものは、仕掛りの明示的な制限が無く、新しい作業を引き取るルールが無い、ただの「見える化」である

仕掛り(WIP)制限のメリット

  • ライフワークバランス向上
  • 品質とパフォーマンスコストの向上
  • ゆとりを作ることのメリット
    • 自主的なカイゼンが進む
    • 突発的な事象に対応可能になる
    • 問題解決に「群がる」ことが可能になる

最初は仕掛り制限を緩めに設定することで、チームの導入の反発を防ぐことができる

  • ただし、仕掛り制限を無しにすると、カイゼンのスピードは大きく落ちると作者は言っている
  • 仕掛り制限があることにより、発生する緊張や議論がカイゼンを促進するという持論らしい
    • 実感が無いのでよくわからん…

タスクボードを作る前にやること

  • バリューストリーム(開発組織が実行する作業の流れ)を明確にする
  • バリューストリームの入力と出力を定義する
  • バリューストリームの作業項目を分析する
    • 作業項目の需要に合わせて、作業容量を割り当てる

タスクボードを作ったあとにやること

  • タスクボードの前でのデイリースタンドアップMTG
  • プロセスの振り返り/分析するための定期的なMTG
    • 上流/下流のチームのメトリクスを報告
  • タスクボードのメトリクスを取る
    • メトリクスの目標となる値を決める

メトリクスについて

メトリクスの目的

  • 作業量の予測が可能になっているか?
  • 組織がビジネス面で機敏に動けているか?
  • 常にカイゼンが明確にあらわれているか?

結局カイゼンしたかどうかは数値にしないとわからないわけで、メトリクス超大事

メトリクスの方法いろいろ

累積フロー図

  • 未処理項目/仕掛り/リリース済の累積数をグラフにする
  • 「仕掛り」の部分の面積が一定であるならば順調
    • 自分達のチームの場合「待ち」の数も必要か

リードタイム

  • そのタスクが完了するまでに掛かった日数
  • 目標を立てて、それから乖離したものを後で確認すると良い

納期パフォーマンス

  • 納期がある作業をどれだけ納期までに完了できたか?

スループット

  • 特定の期間にデプロイされた項目数
  • アジャイルのベロシティに近い

初期品質

  • 見落とした欠陥の数

失敗による負荷

  • 過去のデリバリー品質の低さが招いた作業項目の数

Amazon Lambda おぼえがき

いろいろ忘れるのでメモ

環境変数を使いたい

コードタブの下の方に入力するカラムがある

環境変数を暗号化したい

KMSを使って暗号化する方法がある

このとき、ロールにKMSへのアクセス許可を設定する必要があるので注意

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "********",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "arn:aws:kms:eu-central-1:********:key/********"
            ]
        }
    ]
}

callbackの内容がCloudWatchログに出力されない

ロールに権限が無いのが原因。CloudWatchLogsFullAccess でも渡しておくこと

ElasticBeanstalkでメモリ使用率が一定値を超えたらslackでアラートを出したい

ElasticBeanstalkでメモリ使用率やHDD残量をモニタリングする方法の続き

ざっくり解説

  • ElasticBeanstalkの「アラーム」では、CloudWatchでメトリクスしている項目が設定した閾値を超えた時、AmazonSNSのSNSトピックに通知を渡すことができる
  • AmazonSNSとは、何かをトリガーにしてどこかに情報をpushするサービス
    • 送信先は、Emailとか、特定のURLを叩くとか、Lambdaとかいろいろ
  • SNSトピック : トリガーと送信先(Subscriptions:複数可)のセット

方法

例として、メモリ使用率が98%を超えたら通知する場合

まず、ElasticBeanstalkでメモリ使用率やHDD残量をモニタリングする方法で追加したカスタムメトリクスMaxMemoryUtilizationを「モニタリング」に追加する

f:id:kasei_san:20170505175154p:plain

モニタリングに追加されたら、グラフの右上のベルのマークを押す

f:id:kasei_san:20170505175040p:plain

アラームの追加に遷移するので

  • しきい値」を設定する
  • 「次の時間経過後に状態を変更」を設定する
    • 1分なら、1分後にしきい値以下になったらOKになる
  • Slackの有料アカウントを使っているならば、Eメールアドレスにslack通知用のアドレスを設定すれば良い

f:id:kasei_san:20170505175609p:plain

Slackの有料アカウントを持っていない場合

こちらでAWS LambdaでSlackを叩く方法が解説されている

CloudWatchのAlertをAWS Lambda経由でSlackに飛ばす - Qiita

  • AWS Lambda上で、Slack の WebHooksを叩くLambda functionを作成する
  • 上記で作成されたSNSトピックに、このLambda functionを叩くSubscriptionを追加する

参考

ElasticBeanstalkでメモリ使用率やHDD残量をモニタリングする方法

最初に

ここに書いてある

ざっくり解説

  • ElasticBeanstalkでは、CloudWatchを使って各項目のモニタリングが可能
  • CloudWatchがEC2でモニタリングしている項目に、メモリ使用量やHDD残量はない
  • そのため、CloudWatchに独自のデータを送信する カスタムメトリクス という手段を使う

「例: カスタム Amazon CloudWatch メトリクスの使用」でやっていることの解説

例: カスタム Amazon CloudWatch メトリクスの使用 - AWS Elastic Beanstalk

. ebextensions を使ってEC2構築時に以下のことをやっている

  • CloudWatchにデータ送信するためのツール(perlスクリプト)をインストール
  • 上記を動作させる為に必要なyumライブラリもインストール
  • crontabに5分に1回データを送信する処理を追記
    • /etc/cron.d/cwpump にもデータを格納
    • 動作確認用。動作確認が済んだら標準出力先を /dev/null にするように書かれている

またIAMにて、ElasticBeanstalkで生成されたEC2用のロールaws-elasticbeanstalk-ec2-roleに、CloudWatchにデータを送信する許可を追加している

ここまでやるとこんな風に、ElasticBeanstalkの「モニタリング」で、メモリの使用率やHDDの残量をメトリクスできるようになる

f:id:kasei_san:20170505164319p:plain

ちなみに統計は最大を使用すること。平均だと、一台だけ異常値になった時に気づけないので

ElasticBeanstalkで独立したRDSに接続する手順(Railsの場合)

解説

ElasticBeanstalkでは、環境にRDSインスタンスを作成することができる

しかし、環境内にRDSインスタンスを作成した場合、環境を終了させると、RDSインスタンスも終了してしまう

そのため、本番環境ではRDSインスタンスを環境外に作成して、環境に接続して運用することが推奨されている

環境の一部であるデータベースインスタンスは、環境のライフサイクルに固定されており、追加されると環境から削除することはできません。環境を終了すると、データベースインスタンスも終了します。 環境に DB インスタンスの追加時、環境を終了しスナップショットからデータベースを復元するとき、Elastic Beanstalk を設定して、データベースのスナップショットを保存することができます。データベースのスナップショットを保存するときに料金が発生する場合があります。詳細については、Amazon RDS 料金表の「バックアップストレージ」セクションを参照してください。 本稼働環境では、環境外にデータベースインスタンスを起動する、および Elastic Beanstalk. によって提供される機能の外部に接続するようアプリケーションを設定することもできます。 環境の外部にデータベースインスタンスを使用する場合、追加のセキュリティグループと接続文字列設定が必要ですが、複数の環境からデータベースに接続でき、統合されたデータベースでサポートされていないデータベースタイプを使用し、青/緑のデプロイを実行して、データベースインスタンスに影響を与えずに環境を解放することもできます。

Elastic Beanstalk でデータベースを設定する - AWS Elastic Beanstalk

方法

  1. ElasticBeanstalk環境を作成する
  2. RDS接続用セキュリティグループを作成する
  3. RDS環境を作成する
  4. ElasticBeanstalkの環境変数に、RDS接続用の値を設定する

config/database.yml の設定例

production:
  <<: *default
  database: <%= ENV['DB_NAME'] %>
  username: <%= ENV['USERNAME'] %>
  password: <%= ENV['PASSWORD'] %>
  host: <%= ENV['HOSTNAME'] %>
  port: <%= ENV['PORT'] %>%

それぞれの詳細については、後日追記

クイズで学ぶ初心者がハマりがちなRubyの代入いろいろ

クイズ1

以下のコードを実行した場合、変数 a の値はどうなるでしょう?

a=100
b=a
b=200

答え

100

解説

  • a=100では、変数aに数値オブジェクト100を参照させている
  • b=aでは、変数bに変数aと同じオブジェクトを参照させている
  • そして、b=200では、変数bに数値オブジェクト200を参照させている
  • この時点で、変数abが参照するオブジェクトは異なるものとなる
  • そして、変数bが参照するオブジェクトが変わっても、変数aが参照するオブジェクトは変わらない

クイズ2

以下のコードを実行した場合、変数 a の値はどうなるでしょう?

a="aaa"
b=a
b.gsub!(/a/, "b")

答え

"bbb"

解説

  • gsub!はレシーバーの内容を直接書き換えるメソッド(破壊的メソッド)
  • gsub!は、文字列オブジェクト"aaa"に対して破壊的に実行される
  • b=aでは、変数bに変数aと同じ文字列オブジェクト"aaa"を参照させている
  • そのため、変数aからも、変数bからも書き換えられた文字列"bbb"を見ることができる

クイズ3

以下のコードを実行した場合、変数 a の値はどうなるでしょう?

a= ["aaa",100]
b=a[1]
b= 200

答え

["aaa", 100]

解説

  • クイズ1の応用問題
  • a[1]は配列の1個目要素を取り出すメソッド
  • b=a[1]では、変数ba[1]で取り出した、数値オブジェクト100を参照させている
  • そして、b=200では、変数bに数値オブジェクト200を参照させている
  • この時点で、a[1]と変数bが参照するオブジェクトは異なるものとなる
  • そして、変数bが参照するオブジェクトが変わっても、a[1]から取得できるオブジェクトは変わらない

クイズ4

以下のコードを実行した場合、変数 a の値はどうなるでしょう?

a= [ ["aaa","bbb"], 100]
b=a[0]
b[1] = "ccc"

答え

[["aaa", "ccc"], 100]

解説

  • こんどは、a[0]bは、配列オブジェクト ["aaa", "bbb"] を参照している
  • b[1] はメソッド Array#[]= の呼び出し
  • Array#[]=は、指定された配列の要素の中身を置き換えるメソッドのため、b[1] = "ccc" ならば ["aaa", "ccc"] となる