6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

fluentdでS3に転送しているならば、無駄なGETリクエストに気をつけろ!

Posted at

概要

FluentdでS3にログ転送している場合で、以下の条件に当てはまると無駄なS3のGETリクエストを消費することがあります

  • check_objecttrue(指定なしはtrue)
  • s3_object_key_format%{index}を含めている
    S3に出力される際に同名のファイルがある時に自動的に枝番を付与される
    brunch.png

S3のGETリクエスト単価($0.0037/10,000リクエスト)は安いので、なかなか無駄に気づかないことが多い
私も気づくまでに1年かかりましたw
ただ、無駄なものは無駄なのできちんと設定して無駄を無くしましょう!

正しい設定

  • check_objectfalse
  • %{index}を利用せずに出力するファイル名が必ず一意になるようにs3_object_key_formatを指定する
    ファイル名に秒まで含めるのが良いでしょう

fluent-plugin-s3のリファレンス
※時間フォーマットの詳しい設定はこちらを参照

fluent.conf

<match pattern>
  @type s3

  path logs/
  
  # 存在確認を無効
  check_object false

  # hms_sliceは時間
  s3_object_key_format %{path}%{time_slice}_%{hms_slice}.log

  # 日時(2020-02-18)
  time_slice_format %Y-%m-%d

</match>

※なお、バージョンによっては副作用として上記のs3_object_key_formatcheck_objectを併用するとfluentdログにWARNが記録されます

なぜ

前述の条件によりS3に同一ファイル名が存在する場合は、自動的に枝番を付与してくれます
ただし、枝番を採番する際に都度GETリクエストを発行して枝番ごとにファイルの存在確認していく処理になっている

実際にCloudTrialログを添えて、流れを追っていきます

  1. S3に2020-02-19.log_02020-02-19.log_1がある前提

  2. さらに同名のログ(2020-02-19.log)をPUTする

  3. 2020-02-19.log_0をGETリクエスト(HeadObject)する

  4. エラーがなかったので、存在すると判定し、2020-02-19.log_1でGETリクエストする

    CloudTrialログ
    {
      "eventVersion": "1.06",
      "eventTime": "2020-02-19T09:12:01Z",
      "eventSource": "s3.amazonaws.com",
      "eventName": "HeadObject",
      "awsRegion": "ap-northeast-1",
      "requestParameters": {
        "bucketName": "hogehoge",
        "Host": "hogehoge.s3.ap-northeast-1.amazonaws.com",
        "key": "logs/2020-02-19_0.log"
      },
      "responseElements": null,
      "readOnly": true,
      "resources": [
        {
          "type": "AWS::S3::Object",
          "ARN": "arn:aws:s3:::hogehoge/logs/2020-02-19_0.log"
        },
        {
          "type": "AWS::S3::Bucket",
          "ARN": "arn:aws:s3:::hogehoge"
        }
      ],
      "eventType": "AwsApiCall",
      "managementEvent": false
    }
    
  5. 同様にエラーがなかったので、存在すると判定し、2020-02-19.log_2でGETリクエストする

    CloudTrialログ
    {
      "eventVersion": "1.06",
      "eventTime": "2020-02-19T09:12:01Z",
      "eventSource": "s3.amazonaws.com",
      "eventName": "HeadObject",
      "awsRegion": "ap-northeast-1",
      "requestParameters": {
        "bucketName": "hogehoge",
        "Host": "hogehoge.s3.ap-northeast-1.amazonaws.com",
        "key": "logs/2020-02-19_1.log"
      },
      "responseElements": null,
      "readOnly": true,
      "resources": [
        {
          "type": "AWS::S3::Object",
          "ARN": "arn:aws:s3:::hogehoge/logs/2020-02-19_1.log"
        },
        {
          "type": "AWS::S3::Bucket",
          "ARN": "arn:aws:s3:::hogehoge"
        }
      ],
      "eventType": "AwsApiCall",
      "managementEvent": false
    }
    
  6. エラー("errorCode": "NoSuchKey")が発生したので、存在しないと判定し、2020-02-19.log_2でPUTリクエストする

    CloudTrialログ
    {
      "eventVersion": "1.06",
      "eventTime": "2020-02-19T09:12:02Z",
      "eventSource": "s3.amazonaws.com",
      "eventName": "HeadObject",
      "awsRegion": "ap-northeast-1",
      "errorCode": "NoSuchKey",
      "errorMessage": "The specified key does not exist.",
      "requestParameters": {
        "bucketName": "hogehoge",
        "Host": "hogehoge.s3.ap-northeast-1.amazonaws.com",
        "key": "logs/2020-02-19_2.log"
      },
      "responseElements": null,
      "readOnly": true,
      "resources": [
        {
          "type": "AWS::S3::Object",
          "ARN": "arn:aws:s3:::hogehoge/logs/2020-02-19_2.log"
        },
        {
          "type": "AWS::S3::Bucket",
          "ARN": "arn:aws:s3:::hogehoge"
        }
      ],
      "eventType": "AwsApiCall",
      "managementEvent": false
    },
    {
      "eventVersion": "1.06",
      "eventTime": "2020-02-19T09:12:02Z",
      "eventSource": "s3.amazonaws.com",
      "eventName": "PutObject",
      "awsRegion": "ap-northeast-1",
      "requestParameters": {
        "bucketName": "hogehoge",
        "Host": "hogehoge.s3.ap-northeast-1.amazonaws.com",
        "key": "logs/2020-02-19_2.log"
      },
      "readOnly": false,
      "resources": [
        {
          "type": "AWS::S3::Object",
          "ARN": "arn:aws:s3:::hogehoge/logs/2020-02-19_2.log"
        },
        {
          "type": "AWS::S3::Bucket",
          "ARN": "arn:aws:s3:::hogehoge"
        }
      ],
      "eventType": "AwsApiCall",
      "managementEvent": false
    }
    

という流れになっています

なので枝番が増えれば増えるほどGETリクエスト数も1+2+3+4+5・・・と増えていきます
ファイル名が被らなくてもcheck_objectが有効な場合は、必ず1回はGETリクエストが発生するので、falseを検討してもよいかもしれない
万が一に上書きの心配があるならば念のために有効のままにしておくのもいいかもしれない

ちなみに自社のS3の請求欄です
S3にはログしか保存していないのにもかかわらず、GETリクエストがPUTの25倍もある
幸い単価が安いので助かっています( ;∀;)

s3_cost.png

検証用

検証用にサンプルコードを作成したので、そちらで簡単に動作確認ができるかと思います
手順はReadmeを参照ください
https://github.com/comefigo/fluentd-s3

CloudTrial以外にもバケットのメトリックス(CloudWatchの有料メトリックス)でリクエスト数の確認もできますので、必要であればご確認ください

6
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?