30歳パパエンジニアのアウトプット帳

30歳に突入した1児のパパエンジニアのブログ

lambda(python)で定期的にAthenaのMSCK REPAIR TABLEを行う

Athenaを使うようにして、パーティションの更新を都度行うのが面倒だったので自動的に行われるようにした。

下記のようなlambda関数を作成して、Cloudwatchでcron式で定期実行ルールを設定した。

import boto3

client = boto3.client('athena')
 
def lambda_handler(event, context):
    sql = 'MSCK REPAIR TABLE テーブル名;'
    print('sql=' + sql)
    client.start_query_execution(
        QueryString=sql,
        QueryExecutionContext={
            'Database': 'データベース名'
        },
        ResultConfiguration={
            'OutputLocation': 's3://実行結果の保存先バケット'
        }
    )

CloudFormationでElasticache for redisの設定をする

CloudFormationで非クラスターモード(マルチAZ)の構成を試してみた。

プライマリーノード:1、リードレプリカ:2の3ノード構成でプライベートなVPCに配置する想定。


最終的には下記の公式ドキュメントのサンプルオペレーションをCloudFormation対応した感じ。

docs.aws.amazon.com

次のオペレーションでは、3 つのノード、1 つのプライマリ、2 つのレプリカを持つ Redis (クラスターモードが無効) レプリケーショングループ new-group を作成します。

一部抜粋だけどこんな感じになった。

  ECacheSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties: 
      GroupName: !Ref ECacheSecurityGroupName
      GroupDescription: Security Group for Elasticache Redis
      SecurityGroupIngress:
        - 
          IpProtocol: tcp
          CidrIp: '0.0.0.0/0'
          FromPort: 6379
          ToPort: 6379
        - 
          IpProtocol: tcp
          CidrIpv6: '::/0'
          FromPort: 6379
          ToPort: 6379
      Tags:
        - Key: Name
          Value: !Ref ECacheSecurityGroupName
      VpcId: !Ref VpcId
  ECacheSubnetGroup:
    Type: "AWS::ElastiCache::SubnetGroup"
    Properties:
      CacheSubnetGroupName: !Ref ECacheSubnetGroupName
      Description: Redis Subnet Group
      SubnetIds:
        - !Ref SubnetAId
        - !Ref SubnetCId
  ECacheRedis:
    Type: "AWS::ElastiCache::ReplicationGroup"
    Properties:
      AutomaticFailoverEnabled: true
      AutoMinorVersionUpgrade: true
      CacheNodeType: !Ref ECacheNodeType
      CacheParameterGroupName: default.redis3.2
      CacheSubnetGroupName: !Ref ECacheSubnetGroup
      Engine: redis
      EngineVersion: 3.2.10
      NumCacheClusters: 3
      ReplicationGroupDescription: 'Elasticache Redis'
      ReplicationGroupId: !Ref ECacheClusterName
      SecurityGroupIds:
        - !Ref ECacheSecurityGroup
      SnapshotRetentionLimit: 5
      SnapshotWindow: 'sun:13:30-sun:14:30'

VPC内に配置したい場合

所属するサブネットグループをAWS::ElastiCache::SubnetGroupで作成して、CacheSubnetGroupNameで指定してあげる。

マルチAZにしたい場合

ドキュメントに記載がある。

注記

2.8.6 より前のバージョンの Redis または T1 キャッシュノードタイプでは、自動フェイルオーバーを有効にすることはできません。
自動フェイルオーバーは、クラスターモードが有効で Redis バージョン 3.2.4 以降を実行している場合のみ、T2 ノードタイプでサポートされます。

つまりT2系の場合はクラスターモードが有効でないとマルチAZにできない。

m3系以上だとクラスターモードが無効でもマルチAZにできる。

キャッシュノード数を2以上にしたい場合

初めはAWS::ElastiCache::CacheClusterでRedisを構築しようとしていたが、ノード数2以上で作成しようとするの下記のようなエラーがでる。

NumCacheNodes should be 1 if engine is redis

キャッシュノード数を2以上にしたい場合は下記のAWS::ElastiCache::ReplicationGroupを使う必要があるらしい。

AWS::ElastiCache::ReplicationGroup - AWS CloudFormation

下記の記事も詳しくてよかった。

takatorix.hatenablog.com

クラスターモード有効時

検証用にクラスターモードの場合も構築してみた。

  ECacheRedis:
    Type: "AWS::ElastiCache::ReplicationGroup"
    Properties:
      AutomaticFailoverEnabled: true
      AutoMinorVersionUpgrade: true
      CacheNodeType: !Ref ECacheNodeType
      CacheParameterGroupName: default.redis3.2.cluster.on
      CacheSubnetGroupName: !Ref ECacheSubnetGroup
      Engine: redis
      EngineVersion: 3.2.10
      NumNodeGroups: 2
      NodeGroupConfiguration:
        - 
          PrimaryAvailabilityZone: ap-northeast-1a
          ReplicaAvailabilityZones:
            - ap-northeast-1a
            - ap-northeast-1c
        - 
          PrimaryAvailabilityZone: ap-northeast-1c
          ReplicaAvailabilityZones:
            - ap-northeast-1a
            - ap-northeast-1c
      ReplicasPerNodeGroup: 2
      ReplicationGroupDescription: 'Elasticache Redis'
      ReplicationGroupId: !Ref ECacheClusterName
      SecurityGroupIds:
        - !Ref ECacheSecurityGroup
      SnapshotRetentionLimit: 3
      SnapshotWindow: 'sun:13:30-sun:14:30'

CloudFormationのAWS::EC2::InstanceでNetworkInterfacesとSecurityGroupIdsは一緒に使えない

CloudFormationでEC2のインスタンスを作成しようとした時に下記のエラーが出てハマった。

Network interfaces and an instance-level security groups may not be specified on the same request

解決方法としては下記の通りNetworkInterfacesとSecurityGroupIdsは一緒に使えないのでNetworkInterfaces中のGroupSetで設定しましょう。

www.kabegiwablog.com

ActiveJob with sidekiqでリトライをしないようにする

非同期処理のど定番のsidekiq。

それをActiveJob経由で使っている場合は、sidekiq_optionsが使えないので細かな設定ができない。

今回、sidekiqにするにしたがってリトライは現時点では全てのジョブで不要なので、リトライしないようにしたかった。

結論としてはconfig/initializers/sidekiq.rbにSidekiq.options[:max_retries] = 0を設定してあげればいい。


sidekiqのwikiでこの設定見当たらなかったので、ソース調べたら見つけた。

https://github.com/mperham/sidekiq/blob/v5.1.3/lib/sidekiq/job_retry.rb#L46-L49

デフォルトが25らしいので、それを変更する際にもこの設定方法でいいと思われる。

Capybara::Poltergeist::StatusFailErrorが出たら

このエラーはローカルで

Capybara::Poltergeist::Driver.new(app, js_errors: true, timeout: 1)

のようにpoltergeistのtimeoutをすごく短くすると同様のエラーになる。


原因はassets compileに時間がかかっていてタイムアウトしている説らしい。

とりあえず、timeoutを伸ばして様子をみて、ダメなら先にassetファイルにアクセスするやテスト前にprecompileをするなどの方針を考える必要がある。

Capybara.register_driver :poltergeist do |app|
  Capybara::Poltergeist::Driver.new(app, js_errors: true, timeout: 60)
end

Capybara::Poltergeist::StatusFailError · Issue #791 · teampoltergeist/poltergeist · GitHub

Capybara::Poltergeist::TimeoutErrorが稀に起こる問題の対応 - Qiita

Timeout::Error: execution expiredの場合

このエラーの場合はどのgemがというよりはテスト内にTimeout.timeout(5)とかやっている場合がある。

自分の場合はajaxの処理が完了するまで待つみたいなやつがあった。

Aurora MySQLのmax_connectionsの設定

テスト環境でrailsのdatabase.ymlのpool設定を本番に合わせたいが、Auroraの方のmax_connectionsが45になっていた。

これでは足りないので45より多くしたい。


まず、Auroraのmax_connectionsはインスタンスタイプでデフォルトが決まるような設定がされている。

docs.aws.amazon.com

なので、これを変更する。


そのために、AWSのコンソールからRDS→パラメーターグループから対象RDSに対応するパラメーターグループを選択して、フィルターでmax_connectionsで検索して"パラメーターの編集"を押して変更すればOK。

特に RDSの再起動をしなくても設定が適応されている。(適用タイプがdynamicなので)

mysql> SHOW VARIABLES LIKE 'max_connections';で確認

logrotateを使ってローテションを行う

設定方法&確認

下記などを参考にした。

logrotateでログのローテーションをする - おもしろwebサービス開発日記

logrotate でデフォルト以外のフォーマットで日付ファイル名にしたいとき - Qiita


こんな感じで設定してみた。

日次で前の日のログをローテートするのに日付がローテートした日付なのがなんか気持ち悪いから、lastactionで前の日のファイル名にしてみた。

(これでいいかはちょっと自信ない)

追記(2018/04/12)

postrotateでやってないのは、compressを指定しているから。

ローテート→postrotate→compressの流れになるようなので、postrotateでrenameするとcompressがrename前のファイルを圧縮しようとしてエラーになった。

/my/rails/application/log/*.log {
    daily
    rotate 30
    missingok
    notifempty
    copytruncate
    dateext
    dateformat .%Y%m%d
    compress
    su root root

    lastaction
        for infile in $1; do
            if [ -f $infile.`date '+%Y%m%d'`.gz ] ; then
                mv $infile.`date '+%Y%m%d'`.gz $infile.`date --date '1 days ago' '+%Y%m%d'`.gz
            fi
        done
    endscript
}


logrotateのテストはf,dオプションをつけて確認する。

# dオプションを付けるとデバック実行で実際には実行されない
$ logrotate -d /etc/logrotate.d/rails

# fオプションだと実際に実行される
$ logrotate -f /etc/logrotate.d/rails

といあえず指定できるやつは下記をみたら意味がわかると思う。

@IT:logrotateの設定ファイルで指定できる主なコマンド

他のオプションはmanを見るなどします。

logrotate(8) - Linux man page

cronの設定は必要か?

下記のように、/etc/crontabか/etc/anacrontabを確認しましょう。

【logrotateの実行タイミング】/etc/crontabに無い時の確認方法 - Qiita


今回検証していたCentOSの場合は/etc/anacrontabに設定されているので特にcronの設定をしなくても動くはず。

https://daichan.club/linux/639

細かすぎて伝わらない anacron の挙動 - Qiita