kasei_sanのブログ

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

AUTOVACUUMが動かない時に調べること

AUTOVACUUMの設定

SELECT name, setting
FROM pg_settings
WHERE name LIKE '%autovacuum%';
  • autovacuumon であること
  • 他の数値も異常な値でないこと(どう考えても実行されない閾値とか)

AUTOVACUUMの最終実行日時

SELECT relname, last_autovacuum,last_autoanalyze FROM pg_stat_user_tables
WHERE 
    last_autovacuum is not NULL OR
    last_autoanalyze is not NULL;

テーブル毎のオプション

SELECT relname, reloptions
FROM pg_class
WHERE array_length(reloptions, 1) IS NOT NULL;
  • {autovacuum_enabled=false} が設定されていると、AUTOVACUUMされない

AUTOVACUUM実行対象のテーブル一覧

WITH vbt AS (SELECT setting AS autovacuum_vacuum_threshold FROM 
pg_settings WHERE name = 'autovacuum_vacuum_threshold'),
vsf AS (SELECT setting AS autovacuum_vacuum_scale_factor FROM 
pg_settings WHERE name = 'autovacuum_vacuum_scale_factor'), 
fma AS (SELECT setting AS autovacuum_freeze_max_age FROM pg_settings WHERE name = 'autovacuum_freeze_max_age'),
sto AS (select opt_oid, split_part(setting, '=', 1) as param,
split_part(setting, '=', 2) as value from (select oid opt_oid, unnest(reloptions) setting from pg_class) opt)
SELECT '"'||ns.nspname||'"."'||c.relname||'"' as relation,
pg_size_pretty(pg_table_size(c.oid)) as table_size,
age(relfrozenxid) as xid_age,
coalesce(cfma.value::float, autovacuum_freeze_max_age::float) autovacuum_freeze_max_age,
(coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) +
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * c.reltuples)
AS autovacuum_vacuum_tuples, n_dead_tup as dead_tuples FROM
pg_class c join pg_namespace ns on ns.oid = c.relnamespace 
join pg_stat_all_tables stat on stat.relid = c.oid join vbt on (1=1) join vsf on (1=1) join fma on (1=1)
left join sto cvbt on cvbt.param = 'autovacuum_vacuum_threshold' and c.oid = cvbt.opt_oid 
left join sto cvsf on cvsf.param = 'autovacuum_vacuum_scale_factor' and c.oid = cvsf.opt_oid
left join sto cfma on cfma.param = 'autovacuum_freeze_max_age' and c.oid = cfma.opt_oid
WHERE c.relkind = 'r' and nspname <> 'pg_catalog'
AND (age(relfrozenxid) >= coalesce(cfma.value::float, autovacuum_freeze_max_age::float)
OR coalesce(cvbt.value::float, autovacuum_vacuum_threshold::float) + 
coalesce(cvsf.value::float,autovacuum_vacuum_scale_factor::float) * 
c.reltuples <= n_dead_tup)
ORDER BY age(relfrozenxid) DESC LIMIT 50;

👇こちらから拝借

docs.aws.amazon.com

参考

qiita.com

Railsのdatabase.ymlのpoolの適正数

先に結論

Railsの中でスレッド処理をしていないのであれば

  • Unicornの場合 1
  • Pumaの場合 スレッドの数

なんで UnicornとPumaで数が違うの?

ざっくりいうと、Unicornはマルチプロセスで、Pumaはマルチスレッドだから (厳密には違うけど)

それで、コネクションプールはRailsのプロセスごとに持ってる

マルチプロセスのUnicornでは、1worker = 1プロセス なので、workerが消費するのは、1つのコネクションだけ。 なので、database.ymlの pool の値は 1 が適正

それに対して、マルチスレッドのPumaでは、1つのプロセスで複数のスレッドが動作する。 そのため、スレッドの数だけコネクションが必要になる

参考

blog.kasei-san.com

AWSコスト最適化ガイドブック 読書メモ

初学者やAWS詳しくない人が、最適な使い方を学ぶのには良い本でした

逆にある程度くわしい人は、知らないところをつまみ食いすればそれで終わる感じでした

ざっくり

  • AWSのコスト最適化についてのアドバイス集
  • それに合わせて、各サービスの最適な使いかたの紹介
  • EC2、RDS、ストレージ系、lambda、ECS、DynamoDBなど

感想

  • AWSの中の人が書いているので信頼度は高いと感じた
  • 基本的なことはしっかり抑えられている
  • その分、自分が知らなかった! というものはほとんど無かった

どんな人が読むべきか?

  • AWS詳しくないけど前任者が居なくなってインフラを任せさられた! って人や初心者が読むべき
  • AWSソリューション認定アーキテクト、アソシエイトを取得した人が、各サービスの実践的な使い方を学ぶのには最適なんじゃないでしょうか
  • 少なくとも、資格取ってこれ読んでくれれば、最低限の戦力になってくれそうな気がする

メール関係の用語おぼえがき

勉強する必要が出たのでおぼえがき

レピュテーション(reputation)

「レピュテーション(reputation)」とは、電子メールの送信元の信頼性や評判を示す指標

  • スパムメールや悪意のあるメールの送信者と、信頼性のあるメール送信者を区別するために使用される
  • レピュテーションが低い内に、大量のメールを送信すると、受信側で受け入れが制限されることがある スロットリング と呼ばれる
  • レピュテーションは、ISPやメールサーバ毎にそれぞれ保有しているため、同じ送信元でもスロットリングされたり、されなかったりする
  • 基本的にはIPアドレス単位で判断される(他の要素も勘案されるらしい)
  • なので、 共有IPのメールサービスを使う場合、他のユーザの行動によって巻き添えを食う場合がある
  • そのため、 商用でメールを送るシステムを作る場合、個別IPにするのが無難
  • ただし、個別IPでメールシステムを立ち上げた場合、以下の IPウォームアップ が必要になる

ブラックリスト

スパムや悪質なメールを送信する、IPアドレスやドメインを共有しているリスト

ここに入ったからといって、ただちにメールが受け入れられなくなる訳では無いが、レピュテーションの評価に強く影響を受ける

この辺が有名らしい

  • Spamhaus
  • SURBL
  • Barracuda Reputation Block List
  • Invalument
  • Spamcop
  • MultiRBL

苦情

メールを受信したユーザが「迷惑メールを報告」などのボタンを押すこと

  • 苦情率が高いと、レピュテーションに大きく影響を受けたり、メールサービスからBANされたりする
  • さらにブラックリストに乗せられることもある

IPウォームアップ

新規にメールサーバを立ち上げた場合、レピュテーションが低い状態でいきなり大量のメールを送信すると、スロットリングされることがある

そのため、少しづつメールを送って、レピュテーションを高めていく作業をIPウォームアップと呼ぶ

sendgrid.kke.co.jp

バウンス

メールが配信できなかった。ということを指す用語

受信側からエラーコードが返ってくる

  • 4xxはソフトバウンス
  • 5xxはハードバウンス

ソフトバウンス

受信側の都合でメールが受信できない

  • メールボックスがビジーである
  • ポリシー上の理由で一時的にブロックされている
  • 処理中のエラー
  • システムストレージが不十分

など

なお、スロットリングはソフトバウンス扱い

ハードバウンス

受信側ではどうにもできない理由でメールが受信できない

  • 構文エラー、パラメータエラー、未実装の命令
  • 存在しない、無効なメールアドレス

など

レピュテーションが低下するため、ハードバウンスは避けなければならない

ハードバウンスを避けるにはどうしたら良いの?

無効なメールアドレスにはメールを送らない

メールシステムを利用しているのであれば、ハードバウンスが帰ってきたメールアドレスは送信リストから削除して、受信側に迷惑をかけないようにする

参考

👇4.2.3 数字順の返信コード に受信側のレスポンスコード一覧がある

tex2e.github.io

sendgrid.kke.co.jp

スロットリング

スロットリングとは、システムの過負荷や特定利用者による資源の独占を回避するため、一定の制限値を超えた場合に意図的に性能を低下させたり、要求を一時的に拒否したりする制御のこと。

e-words.jp

メールシステムにおいては、受信側が大量のメールの受信を制限する機能

  • 一度に大量のメールを送ると発生する
  • システム的には ソフトバウンス 扱い

スロットリングを防ぐにはどうしたら良いの?

  • レピュテーションを高める
    • 最初は、まとめて送信せずに時間を置いて少しづつ送信する
    • ただし、無効なメールアドレスが多く含まれていたりすると、なかなか受け入れてもらえない
  • 複数のIPアドレスで送信する
    • これはこれで、それぞれのレピュテーションがある程度無いと無意味

参考

sendgrid.kke.co.jp sendgrid.kke.co.jp

サプレッションリスト

メールサービスに存在する、ハードバウンスや苦情等を受け取って送信対象外とするメールアドレスの一覧

  • Amazon SESでは、
    • リージョン単位の グローバルサプレッションリスト
    • アカウント単位の アカウントサプレッションリスト
    • さらに、Configuration set-level suppression というのがある
  • SendGridでは、アカウント単位の バウンスリスト がある

それぞれ挙動は微妙に違う

グローバルサプレッションリストについて

キャリアメールだと「特定のドメイン以外受信しない」設定があるため、特定のドメイン外のメールを受けてハードバウンスを食らった場合に、 受信可能なドメインのメールもサプレッションリストのせいで送信できない 、という問題があるらしい

qiita.com

(ハード)バウンスはメールアドレスが存在しないなど、恒久的なエラーの場合に発生するものなので、一度バウンスすると他のユーザからも送信不可能にするSESの仕組みは非常に合理的といえます。ただし、日本で使用する場合に問題になるのが携帯キャリアへ送信する場合です。

例えば、ドメイン指定拒否をしている人に対して、許可されたドメイン以外から送信すると、バウンスが発生します(挙動はキャリアによって異なります)。そうすると当然Suppression Listに掲載されてしまうので、許可されたドメインから送信していた人もSuppression Listに引っかかってしまい、送信ができなくなってしまいます。リストから削除しても、また他のドメインから送信されてしまうと、また巻添いを食らってしまいます。これがSESが携帯キャリアへの配信と相性が悪いと言われる所以だと考えています。

参考

dev.classmethod.jp

sendgrid.kke.co.jp

qiita.com

参考

sendgrid.kke.co.jp

RDS の Aurora の昇格についておぼえがき

RDS Auroraでライターインスタンスが死んだ場合、どういうルールで昇格するんだっけ?

  • ライターインスタンスの内「優先度」が最も低い値のインスタンスから選ばれる(0がデフォルト)
  • 同じ「優先度」の場合、同じサブネット、AZのものが優先される

Terraformでインスタンスの「優先度」を決めるにはどうしたら良いの?

instances の中で promotion_tier を設定すれば良い

  instances = {
    1 = {
      # 未指定だと 0
      instance_class      = "db.r5.2xlarge"
      publicly_accessible = true
    }
    2 = {
      identifier     = "static-member-1"
      instance_class = "db.r5.2xlarge"
      promotion_tier = 10
    }
    3 = {
      identifier     = "excluded-member-1"
      instance_class = "db.r5.large"
      promotion_tier = 15
    }
  }

typeが READER のカスタムエンドポイント内のリーダーインスタンスが昇格するとどうなるの?

  • エンドポイントから外される
  • なので、負荷がギリギリなカスタムエンドポイントだと死ぬ
  • そういうエンドポイントのインスタンスは、優先度の数値を高くして昇格を防ぐ

フェイルオーバーや昇格に伴って DB インスタンスのロールがライターとリーダーの間で変更されると、Aurora は静的リストまたは除外リストで指定された DB インスタンスを変更します。

例えば、タイプ READER のカスタムエンドポイントに Aurora レプリカが含まれ、その後、ライターインスタンスに昇格されたとします。新しいライターインスタンスは、カスタムエンドポイントの一部ではなくなります。

docs.aws.amazon.com

👆ここの「カスタムエンドポイントのメンバーシップルール」より

参考

registry.terraform.io

dev.classmethod.jp

GitHubのRSA SSH ホスト鍵変更に対してクライアント側の修正方法

GitHubのRSA SSH 秘密鍵が漏洩したため、2023/03/24 にGitHubのRSA SSH ホスト鍵が変更されました

github.blog

RSA SSH 秘密鍵って?

  • RSAは暗号化方式
  • RSA SSH 秘密鍵は、RSAでSSHするためにGitHubが持っている秘密鍵
  • 今回これが漏洩した

RSA SSH ホスト鍵って?

  • 秘密鍵と公開鍵のペアのこと
  • クライアント側は、接続するサーバから公開鍵を受け取って known_hosts に格納する
  • known_hosts に鍵が格納されると、次回以降のSSH接続では、known_hosts にある公開鍵と、サーバから受け取る公開鍵に差異が無いことを確認して、サーバが偽物に成り代わっていないかチェックするようになる

ホスト鍵が変わると何が困るの?

ホスト鍵(公開鍵も)が変わり、known_hosts にある GitHub の公開鍵と、GitHub受け取る公開鍵に差異が発生するため、SSH接続が失敗するようになる

具体的にはこんなエラーが出る

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the RSA key sent by the remote host is
d5:2c:63:d9:bc:75:9d:de:b1:4e:36:28:9f:7a:9c:39.
Please contact your system administrator.
Add correct host key in /home/hoge/.ssh/known_hosts to get rid of this message.
Offending RSA key in /home/hoge/.ssh/known_hosts:3
RSA host key for github.com has changed and you have requested strict checking.
Host key verification failed.

👆/home/hoge/.ssh/known_hosts の3行目にある公開鍵と、サーバから受け取った公開鍵が違うよというエラーメッセージ

どうしたら良いの?

公式ドキュメントの手順に従えばOK

known_hosts から古い公開鍵を削除

ssh-keygen -f /home/hoge/.ssh/known_hosts -R github.com

👆github.com に関する known_hosts の情報を削除するよというコマンド

known_hosts に手動で以下の公開鍵を追加

github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk=

実際に GitHub に SSH して動作確認する

$ ssh -T git@github.com

Warning: Permanently added the RSA host key for IP address '20.27.177.113' to the list of known hosts.
Hi hoge! You've successfully authenticated, but GitHub does not provide shell access.

警告が出なければOK

ウチのサーバの場合、さらに以下の警告も出たので同様に公開鍵を削除した

Warning: the ECDSA host key for 'github.com' differs from the key for the IP address '20.27.177.113'
ssh-keygen -R 20.27.177.113

参考

SSH公開鍵については、過去のblog記事で解説してます

kasei-san.hatenadiary.org

AWS コスト削減チェックリスト

前提

  • 金銭的なコスト削減のために、運用コストが上昇したら元も子もないので注意!!!

全体

  • EC2 から、ECS(Fargate)、lambdaへの移行を検討中ならば、Compute Savings Plansを使用する
  • そもそも使っていないインスタンスを停止する

EC2

  • 性能が過剰ならば、より低スペックのインスタンスに変更する
  • インスタンスタイプが古いのであれば、最新にする(最新のほうが安い
  • 可能であれば、CPUを Graviton に変更する
  • 24H稼働が不要であれば、夜間休日は停止する(検証環境や営業時間しか使わないサービスなど)
  • 停止しても問題なければ、スポットインスタンスに変更する
  • 1年以上使用するのであれば、リザーブドインスタンスやSavings Plansを契約する
  • バッチ処理などは、ECS(fargate)やlambdaへの移行を検討する
    • → そもそもEC2は運用コストが高い場合が多い
  • オートスケーリンググループを使って、低負荷時はマシンを停止する

ECS(fargate)

  • 性能が過剰ならば、メモリやCPUを減らす
  • 可能であれば、CPUを Graviton に変更する
  • 24H稼働が不要であれば、夜間休日は停止する(検証環境や営業時間しか使わないサービスなど)
  • 停止しても問題なければ、Fargate Spotに変更する
  • 稼働する量が決まっているならば、Savings Plansを契約する
  • 処理頻度が低いのであれば、lambdaに移行する

RDS(Aurora)

  • 性能が過剰ならば、インスタンスタイプを下げる
  • CPUを Graviton に変更する
  • 低頻度アクセスや社内利用であれば、Aurora Serverlessへ移行する
  • 1年以上使用するのであれば、リザーブドインスタンスやSavings Plansを契約する
  • 不要ならばバックアップ保持期間を短くする
  • IOが多いならば、Aurora I/O 最適化を検討する

lambda

  • メモリ使用量が過剰ならば減らす → Lambda Power Tuning
  • 可能であれば、CPUを Graviton に変更する
  • 実行可否をlambda内で処理しているのならば、イベントフィルタリングを使ってlambdaを実行させないようにする
  • 実行頻度が高いのであれば、ECS(fargate)に移行したほうが安いかも

S3

  • 不要なのに保存しているオブジェクトを廃棄する
    • もしくは、数ヶ月経過後はアーカイブする
  • 消えても大きく問題がないオブジェクトは、シングルAZに変更する
  • アクセス頻度が低いオブジェクトは、低頻度アクセスやアーカイブに変更する
  • S3Intelligent-Tieringを使って自動的にコスト最適化を行う