Gentooでamf-amdgpu-proを利用してGPUで動画エンコードを行えるffmpegを作る方法のメモ

AMDGPUのハードウェアエンコード支援機能としてAMFというものがあり、それを利用できるffmpegをビルドする方法。

AMDのサイトからubuntu用のRadeon Software for Linuxを落とす。

ex. Radeon™ Software for Linux® 21.30 Release Notes | AMD

展開して、amf-amdgpu-pro-.debファイルを更に展開する。

$ ar vx amf-amdgpu-pro_21.20-1271047_amd64.deb
$ tar xvf data.tar.xz

展開された libamfrt64.so libamfrt64.so.0 libamfrt64.so.0.0.0 を /usr/libにコピー。

ldconfigを実行。

以下のリポジトリからAMF SDKをダウンロード。

github.com

展開されたファイルの中からamf/public/includeディレクトリを/usr/include/AMFにコピー。

後はffmpegをemergeでビルドしなおせば、勝手に判別してh264_amfとhevc_amfが使える様になる。

Kafkaに接続するJavaアプリケーションをGravitonインスタンスへ移行してパフォーマンスを改善する

社内向けのドキュメントと兼用したので、前提とかメンバー向けの解説が含まれているので、前後のパフォーマンスの変化だけを見たい人は、下の方のグラフ画像までスクロールしてください。

gravitonインスタンスを活用するモチベーション

ワークロードによる相性はあるが、特にマルチスレッド性能で既存のインスタンスより性能向上が見られる上にコストが安いため、うまくフィットすれば性能改善とコスト削減の双方でメリットがある。

また、周辺ハードウェアもアップデートされているため、エフェメラルストレージ付きのインスタンスのストレージサイズが増えているなどのメリットもある。

特に現時点ではr6gdインスタンスが利用したかった。

gravitonインスタンスを利用するためarm64アーキテクチャへの対応

gravitonインスタンスはarm64 (aarch64) アーキテクチャのCPUのため、既存のx86_64アーキテクチャでビルドされたアプリケーションは動作しない。

現状、弊社ではほとんどのアプリケーションはコンテナとして動作しているのでコンテナイメージをarm64アーキテクチャで構築しなおす必要がある。

arm64でコンテナイメージを作成する主な方法として以下の様なものがある。

arm64アーキテクチャで動作するビルドサーバーを構築する

弊社ではこの方針を採用している。元々docker imageのキャッシュ管理やインフラリソースの自由度のためにDockerイメージビルドサーバーがあったので、arm64対応のために新規でビルドサーバーを増築した。

arm64アーキテクチャで動作するビルドサーバー上でイメージを構築すれば自動的にarm64アーキテクチャのコンテナイメージが構築できる。

構築済みのイメージのアーキテクチャは以下のコマンドで確認できる。

docker inspect <image-id> | jq '.[].Architecture'
"arm64"

docker buildx

Dockerの実験的機能として実装されているbuildxを利用することでマルチアーキテクチャイメージを構築することができる。

docker buildx create --name arm64builder --platform linux/arm64
docker buildx use arm64builder
docker buildx inspect --bootstrap

これでビルド準備が出来る。 ビルドする時は以下のコマンドを利用する。

docker buildx build --platform linux/arm64 -t imagetag --load .

しかし、手元で実験した所、何故かgradleによるビルドでqemuが死んでビルド出来ないというエラーが発生した。

dockerやqemuのバージョンで結構動作状況が違う可能性があり、まだ安定して何にでも使えるという感じではない。

arm64で動作するCIサービスの利用

例えば、circleciではmachineタイプのexecutorを指定することでarm64インスタンスを利用してCIを実行できる。 このmachine executor上でdockerを直接操作してイメージ構築とプッシュを実行できる。

https://circleci.com/docs/2.0/arm-resources/

arm64アーキテクチャのAMI構築

弊社ではpackerを利用してAMIを構築しているが、AMI構築時にもCPUアーキテクチャの変更を考慮する必要がある。 base AMIにarm64アーキテクチャ対応のものを指定し、gravitonインスタンスを設定してビルドする。

ビルド上の注意

graviton上でより良いパフォーマンスを出すためには、いくつかの最適化が必要になる場合がある。具体的には以下のドキュメントを一通り読んでおくことを推奨する。

https://github.com/aws/aws-graviton-getting-started

特にコンパイルが必要な言語に関しては、推奨されるコンパイルフラグがあるため、より意識しておく必要がある。

Javaアプリケーションに関しては、Java11以降のOpenJDKなら概ねarm64アーキテクチャを十分にサポートしているが、Java8以前のアプリケーションでパフォーマンスを十分に発揮させるためにはAmazon CorrettoというJDKの利用を検討してみると良いと書かれています。

また、graviton2の分岐予測に影響があるため、 tiered compilationとコードキャッシュの制限を変更するオプションが有効である場合があることが記載されています。 ワークロードによって有利・不利があるので適宜検証しつつ有効化するのが良いらしい。

-XX:-TieredCompilation -XX:ReservedCodeCacheSize=64M -XX:InitialCodeCacheSize=64M

弊社では、USE_GRAVITON_OPTIMIZATION環境変数に値を入れてコンテナを起動すると、アプリケーション起動時に上記オプションを有効にする様にエントリポイントスクリプトを更新した。

移行の流れ

以下の流れでインスタンスを移行していく。

build時にターゲットのCPUアーキテクチャを選択可能にする

環境変数USE_ARM64に値を入れてcapistranoを実行すると、arm64インスタンスでdocker buildを行う様に設定する。

こんな感じで実行する。

USE_ARM64=1 bundle exec cap dev_staging docker:push

ECRはdocker manifestを設定することでマルチアーキテクチャイメージを登録できるが、現状その辺りに対応するのが面倒なため、タグ名に-arm64 suffixを付与することでイメージを分ける。上記の環境変数で判別してsuffixが付与される様に分岐してある。

今回、amazon corretto JVMを利用できる様にarm64向けの新しいDockerfile-arm64を追加した。 落ち着いたらDockerfile側に統合する予定。

arm64対応のautoscaling groupとECS clusterを追加

terraformで新しいクラスタとそのためのautoscaling groupを追加する。 AMIも新しくarm64に構築したものに変更する。 クラスタごと分けるのはインスタンスに対する配置戦略等を設定するのが面倒で、混在していると移行期に分かりにくいので、箱ごと分けることにする。

デプロイ対象のイメージとクラスターを変更し新しい環境にECSサービスを作る

arm64用のクラスタでアプリケーションを起動できる準備をする

arm64クラスタでアプリケーションを起動しつつ徐々に入れ替える

動作自体は、staging環境で事前に確認している。

datadogでモニタしているCPU利用率やメモリ消費のメトリックを中心に入れ替え前後で負荷にどういった変化があったか確認する。

性能比較

r5.xlarge -> r6g.xlargeに変更し数日稼動させた後、2日分のメトリックを1週間前のCPU負荷と比較。 メトリックはdatadog-agentで取得できるdocker.cpu.usageを使う。 (メトリック比較はproduction環境にて実施)

コスト参考: 0.304 USD /hour -> 0.2432 USD

appA (JVM, KafkaStreams, メインスレッド数: 4)

不規則にスパイクが発生するタイプのワークロード。 ベースラインのCPU利用率の減少とスパイク時の利用率のの減少が確認できた。 ただし、日によって負荷傾向に差があるため、安定した性能変化は次のアプリで見た方が良い。

graviton_compare2.png (294.4 kB)

app2 (JVM, KafkaStreams, メインスレッド数: 4)

定常的にデータ受信数に比例した負荷がかかるが概ね一定の負荷傾向で、昼や夕方に高負荷になり夜間は低負荷になる。 負荷が低い時間帯ではほぼ差が無いが、高負荷になる時間帯では20ポイント以上利用率が減少している。中間ぐらいの負荷になる時間帯でも10ポイント前後利用率が減少。 高負荷時にかなりの余裕が出来た。

graviton_compare.png (188.6 kB)

ちなみに、その他のメトリックについては顕著な差分は発生しなかった。

申し訳ありません、適当なこと言ってました

当初、色々作業してすぐだったのでごちゃごちゃしていて、前後比較の対象を間違って見ていたらしく、下記の様なツイートをしていました。

週明けに、ダッシュボードをちゃんと整理してたら、あれ?ちゃんとイメージ通りの結果になったなということが分かり、どうやら私が盛大に勘違いしていた可能性が濃厚です。

AWSさん、間違ったデータを元にネガティブな発言をしてしまい申し訳ありません。ちゃんとパフォーマンス出ました。最高です。ありがとうございます。これからもお世話になります。

皆もgravitonインスタンスをガンガン試していきましょう。

まとめ

インスタンスの変更だけで得られるパフォーマンス改善としてはかなりの効果があった上に1台当たりの基本コストは80%程度にまで抑えられるので、かなりコストパフォーマンスが良くなったと言える。

イメージビルドラインを複数用意したり移行にあたって別クラスタを用意する等の手間をかける必要はあるが、やる価値は十分になると思う。特にマルチスレッドに強いらしいので、GoやJava等のCPUバウンドなアプリケーションでメリットが大きいだろう。

注意点は、インスタンスのワークロード次第ではgravitonを採用できないケースもまだまだ多いので、当分の間arm64とx86_64が混在することは避けられないため、どちらでビルドしているのかをちゃんと意識しておかないとハマる可能性があること。

Embulk v0.11.0, v1.0に向けたMavenプラグインのCI環境構築とMavenプラグインの導入方法 (2021/5/28版)

現在、Embulkは次の安定版であるv0.11.0に向けた開発版としてv0.10がリリースされています。

メンテナであるdmikurubeさんのアナウンスに依ると、0.11.0以降はJRubyがデフォルトでembulkに組込まれなくなるため、プラグインは基本的にJavaで作ることが推奨される様になります。 また、JRubyがデフォルトで入らなくなるため、基本となるプラグインの配布プラットフォームはMavenリポジトリになる予定です。

JavaプラグインAPIもいくつか変更されており、新しいバージョンに対応するためには多少の修正が必要になります。

基本的な開発ガイドについては、以下の記事を参考にすると良いでしょう。

zenn.dev

zenn.dev

ある程度embulkのプラグイン開発に慣れていれば、上記の記事で実装とビルドまでは何とかなるんですが、当分の間0.9系が生き続けることは間違いないため、プラグイン開発者としては出来るなら0.9系と0.11系で両対応できる様にしたいと考えるのは自然なことでしょう。

そのため、複数のembulkバージョンを利用してCIを実行できる様にしたいと思い、実際に構築したのですが、その過程で結構ハマる箇所があったので、その辺りについて解説します。

先に、実際に作業したリポジトリを紹介しておきます。

github.com

CI環境での実行確認は各バージョンのembulkをインストールした後、シンプルなコンフィグを実際に実行してみてエラーが無ければOKというシンプルなものです。(別途JUnitで書いたテストはある)

また、ここで紹介する方法はバリバリのbeta版という感じの内容なので、今後のembulkの開発次第で大きく変更になる可能性があります。ご注意ください。

Embulk System Propertiesについて

v0.9系であれば普通にビルドした時の生成物のパスをCLIオプションでLOAD PATHに追加すれば、rubygemsの仕組みを経由してembulkに読み込むことができ、それで実行できました。 circleciの設定を抜粋するとこんな感じ。

# 省略
      - run: ./gradlew gem

      - run:
          name: run-embulk
          command: ~/repo/embulk run -I ../../../build/gemContents/lib config_acceptance.yml
          working_directory: src/test/resources

しかし、v0.10以降だとJRubyがデフォルトで存在しないため、jrubyを追加するかmavenプラグインとしてインストールするかのどちらかをやる必要があります。

この時に利用するのがEmbulk System Propertiesです。

詳しくは、以下の記事に書かれているのですが、.embulk/embulk.propertiesというファイルを作っておくと、embulkの基本設定をjavaのpropertyファイル形式で記述できます。

zenn.dev

このembulk.propertiesにjrubyのjarファイルの所在を指定することで、embulkでJRubyが利用可能になります。そうすれば、以前と同じ様にrubygems経由でプラグインの読み込みが出来る様になります。

一方で、gemプラグインは今後プラグイン開発の本流では無くなりそうなので、このタイミングでmavenプラグインの活用方法について学んでおきたいと思い、embulk-output-kafkaではmavenプラグインとしてプラグインを導入する方法を調査しました。

で、めちゃくちゃハマったのが、そもそもドキュメントが現時点では全く無いということですw まだ開発版なのでプラグインインストールのための機構そのものが未整備であり、正にこれから作られている最中です。 一般ユーザーならここで諦めても別に良いのですが、プラグインをちょくちょく開発していて、出来れば新しいバージョンにも速やかに対応したいと考えている開発者としては、ここでキャッチアップしておきたいので、頑張って探し当てた結果や質問して得られた回答を共有していきます。

CI環境におけるMavenプラグインの導入方法

1. プラグイン情報の記述

まず、Embulk System Propertiesかyamlのconfigファイルに利用したいプラグインの情報を記述します。

embulk-output-kafkaの例だと以下の様になります。

embulk.propertiesの例

plugins.output.kafka=maven:io.github.joker1007:kafka:0.3.0

重要なのがgroupIdの後のブロックです。ここはembulk-output-kafkaにはなりません。plugins.outputで始まっているキーの場合、kafkaと入れておくと自動でartifactIdがembulk-output-kafkaマッピングされてMavenリポジトリの探索が行われます。ここでembulk-output-kafkaと書いてしまうとembulk-output-embulk-output-kafkaが探索されることになるので注意しましょう。

config fileの例

out:
  type: { source: maven, group: io.github.joker1007, type: kafka, version: 0.3.0 }
  # other config parameters

ちなみにこのフォーマットについてですが、現在ガイドが全然無くて、embulkのソースコードを漁ってたらMavenPluginTypeというクラス内でそれを見つけることができました。

2. プラグインの配置

現在、プラグインを実際にMaven Centralからダウンロードしてくる仕組みがそもそも存在しません。ローカルでビルドしたものも、どうやってそこに読み込ませるかはパッと分かる仕組みやドキュメントはありません。

実際のところ、現時点ではどうやれば良いかというと、以下の様になります。

開発中のプラグインであれば、gradleのmaven-publishプラグインを利用してpublishToMavenLocalを実行すると、ローカルのMavenリポジトリキャッシュにビルド済みのプラグインがpublishされます。 デフォルトでは~/.m2/repositoryになるはずです。

そして、上記のユーザー向けv0.11ガイドに依ると、embulk.propertiesにはm2_repoというものを指定できます。 m2_repoにそのローカルMavenリポジトリキャッシュを指定すれば、読み込みのためのパスが通ります。

しかし、これだけでは十分ではありません。

publishToMavenLocalだけではプラグインが依存しているライブラリのjarがローカルのMavenリポジトリに書き込まれないため、現時点では自力でそれらをダウンロードしてくる必要があります。

publishToMavenLocalを実施すると、build/publications/<task name>/pom-default.xmlというファイルが生成されます。そのpomファイルをコピーしてきて、mvnコマンドを使って依存関係を解決します。pom.xmlのあるディレクトリでmvn installを実行することで、依存ライブラリも全てローカルリポジトリにインストールされます。

その上でembulk runを実行すると、無事にmavenプラグイン形式でプラグインを読み込み、実行することができます。

開発中のプラグインで無い場合は、ダミーのpom.xmlを用意して、そこに利用したいプラグインmaven dependencyを記述しmvn installした上で、embulk.propertiesを設定すれば利用できる様になるはずです。

3. CI環境用のヘルパー

embulk.propertiesにgroupIdやバージョン指定が必要になるため、gradleに現在のプロジェクト定義情報からembulk.propertiesを生成するヘルパータスクを追加しました。

task generateEmbulkProperties {
    doLast {
        mkdir ".embulk"
        def f = file(".embulk/embulk.properties")
        f.write("m2_repo=${System.properties["user.home"]}/.m2/repository\nplugins.output.kafka=maven:${project.group}:kafka:${project.version}")
    }
}

4. circleciの設定例

kafkaの起動等も含むため、余計なものが入っていますがembulk-output-kafkaでは以下の様な設定でCircleCIを動かすことにしました。

  embulk-0.10:
    docker:
      - image: circleci/openjdk:8-jdk
      - image: wurstmeister/zookeeper
      - image: wurstmeister/kafka:2.13-2.7.0
        environment:
          KAFKA_ADVERTISED_HOST_NAME: localhost
          KAFKA_ADVERTISED_PORT: 9092
          KAFKA_PORT: 9092
          KAFKA_ZOOKEEPER_CONNECT: localhost:2181
          KAFKA_DELETE_TOPIC_ENABLE: true
          KAFKA_CREATE_TOPICS: "json-topic:1:1"

    working_directory: ~/repo
    environment:
      # Customize the JVM maximum heap limit
      JVM_OPTS: -Xmx3200m
      TERM: dumb
      SKIP_SIGNING: true

    steps:
      - checkout

      - run: curl -o ./embulk -L https://github.com/embulk/embulk/releases/download/v0.10.31/embulk-0.10.31.jar
      - run: chmod +x ./embulk

      # Download and cache dependencies
      - restore_cache:
          keys:
            - v1-dependencies-{{ checksum "build.gradle" }}
            # fallback to using the latest cache if no exact match is found
            - v1-dependencies-

      - run: ./gradlew dependencies

      - save_cache:
          paths:
            - ~/.gradle
          key: v1-dependencies-{{ checksum "build.gradle" }}

      - run: ./gradlew publishToMavenLocal

      - run: cp build/publications/embulkPluginMaven/pom-default.xml pom.xml

      - restore_cache:
          keys:
            - m2-v1-{{ checksum "pom.xml" }}
            - m2-v1-

      - run: mvn install

      - save_cache:
          paths:
            - ~/.m2
          key: m2-v1-{{ checksum "pom.xml" }}

      - run: ./gradlew generateEmbulkProperties

      - run:
          name: run-embulk
          command: ~/repo/embulk run config_acceptance.yml
          working_directory: src/test/resources

5. その他の注意点

CI環境でpublishToMavenLocalを行う時に、生成されるpomファイルの定義にちゃんとgroupIdやartifactIdが設定される様に、以下の公式ドキュメントを参照して必要な情報を定義しておきましょう。

docs.gradle.org

必要な情報が足りないと、配置されるファイル名やリポジトリ内のディレクトリ名が環境依存で変化する場合があるので、embulkのプラグインローダーが正しくプラグインを見つけられなくなります。自分は、そもそもプラグインの読み込みの挙動が良く分かっていなかったこともあって、しょうもないことで1時間ぐらい無駄にしました。(artifactIdが抜けていて、jarが見つからなくなっていた)

CI環境で引っかかるもう一つのポイントが署名でした。

実際にMaven Centralにpublishするためにはgpg鍵による署名が必要になるんですが、それをgradleで実施するsigningというプラグインを使うと、publishToMavenLocal実行時にも自動的に署名処理が走る様になります。 しかし、別にCI環境で鍵署名とか必要無いし、そのためにgpgの秘密鍵をどうこうするのは危ないので、CI環境ではスキップさせる様にしました。

tasks.withType(Sign) {
    onlyIf { System.getenv().get("SKIP_SIGNING") == null }
}

CI環境ではSKIP_SIGNING環境変数を設定してスキップさせます。

Gradleに慣れてればサッと書けると思うんですが、Gradleにあんまり詳しくないので自分はちょっと悩みました。

最後に

これでv0.9系とv0.11系のMavenプラグインの両方を実際に動かして検証する準備が出来ました。

現時点ではMavenプラグインの導入方法は、ほとんどドキュメント化されておらず、またエコシステムやインストール支援機能の構築もまだまだこれからといった状況なので、ここで紹介した方法はどこかのタイミングで不要になることでしょう。(少なくとも一般ユーザーにとっては)

しかし、早い内から次期バージョンのAPIに対応したembulkプラグインを作っておきたい、利用しているプラグインを新しいembulkに対応させるパッチを書きたいといった開発者にとっては、しばらくは使えるノウハウになると思います。

自分は大体現状の動作については理解したので、自分がメンテしているプラグインは暇を見て対応していこうと思っています。

その他の参考資料: GitHub - embulk/embulk-input-s3: S3 file input plugin for Embulk

Gaming on Gentoo Linux

最近は、LinuxでPCゲームをやるのもかなり現実的になってきたので、その知見についてまとめた記事を書こうと思う。

自分がGentooユーザーなので、細かい部分はGentooを前提にした話になっているが、概要はLinux全般でモダンなPCゲームをやる時の参考程度にはなるだろう。

前提

GPUドライバのインストール

普通入ってると思うが、GPUに合わせてxf86-video-amdgpuかnvidia-driversをインストールしておく。

vulkan driverのインストール

mesa (OpenGL-like graphic library for Linux) でvulkanフラグを有効化しておく。

vulkanは、DirectXとかOpenGLと同じレイヤーのAPIで、3Dグラフィックのためのlow level API。概ねOpenGLをよりモダンな方向に刷新するための規格という認識で良いと思う。

(少し調べてみた所によると、ハードウェアを直接制御するレベルのlow level APIなので、めちゃくちゃ難しいらしい……。)

で、何故これが必要かというと、詳しくは後述するがDirectXを利用したプログラムを動かすための、互換実装がvulkanに依存しているからだ。

vulkanがちゃんと動作しているかを確認するために、vulkan-toolsをインストールしておくこともオススメする。

sudo emerge -a vulkan-tools

vulkan-toolsのvulkaninfoというツールでvulkan driverの情報が取得できれば、正しくvulkanが動作する準備が出来ているはずだ。

vulkaninfo
==========
VULKANINFO
==========

Vulkan Instance Version: 1.2.162


Instance Extensions: count = 17
===============================
    VK_EXT_acquire_xlib_display            : extension revision 1
    VK_EXT_debug_report                    : extension revision 9
    VK_EXT_debug_utils                     : extension revision 2
    VK_EXT_direct_mode_display             : extension revision 1
    VK_EXT_display_surface_counter         : extension revision 1
    VK_KHR_device_group_creation           : extension revision 1
    VK_KHR_display                         : extension revision 23
    VK_KHR_external_fence_capabilities     : extension revision 1
    VK_KHR_external_memory_capabilities    : extension revision 1
    VK_KHR_external_semaphore_capabilities : extension revision 1
    VK_KHR_get_display_properties2         : extension revision 1
    VK_KHR_get_physical_device_properties2 : extension revision 2
    VK_KHR_get_surface_capabilities2       : extension revision 1
    VK_KHR_surface                         : extension revision 25
    VK_KHR_wayland_surface                 : extension revision 6
    VK_KHR_xcb_surface                     : extension revision 6
    VK_KHR_xlib_surface                    : extension revision 6

Steamをインストールする

最近のPCゲームプラットフォームは、ほとんどSteamかEpic Gamesのどっちかだと思う。Epic Gamesについては自分が手を出していないので、後でLinuxでプレイするための方法を軽く紹介だけしておく。

GentooでSteamクライアントをインストールするにはPortage Overlayを使う必要がある。所謂サードパーティリポジトリみたいなもの。

GentooでOverlayを使う方法はいくつかあるが、laymanを使うのが簡単だと思う。入っていないならインストールしておこう。

laymanを利用して、steam-overlayリポジトリを追加する。

sudo layman -a steam-overlay

これでsteam関係のコンポーネントがインストール可能になる。

steamのクライアントをインストールするにはsteam-launcherパッケージをインストールする。

use flagはこんな感じ。全部ONで良い。

equery uses steam-launcher
[ Legend : U - final flag setting for installation]
[        : I - package is installed with flag     ]
[ Colors : set, unset                             ]
 * Found these USE flags for games-util/steam-launcher-1.0.0.69:
 U I
 + + joystick     : Add support for joysticks in all packages
 + + steamruntime : Use the official steam runtime libraries
 + + udev         : Enable virtual/udev integration (device discovery, power and storage device support, etc)
sudo emerge -a steam-launcher

インストールが終わったらsteamコマンドで起動できる。/usr/share/applicationsにもエントリが追加されているはずなので、任意のデスクトップランチャーからも起動できるだろう。

Steam Play設定

Steamが起動できたら、Steam Playの設定を行う。Steamにはcompatibility toolという概念があり、それを利用してWindowsゲームをLinuxでも起動できる様にしてくれる。それを有効化しておく。この設定はゲームごとに上書きできるので、ゲームによっては設定を変える必要があるかもしれない。

f:id:joker1007:20210410204114p:plain

Protonについて

Linux上でWindowゲームを起動するためには基本的にProtonを利用することになる。Protonはwineをベースに作られたWindowsアプリケーションを起動するためのツールである。Protonではwineにゲーム周りで利用されるコンポーネントが諸々追加されている。

Protonは非常に優秀で、Steamで20本ぐらいゲームを買って試したが、全く起動すらしないというゲームはほとんど存在しなかった。一方で大体Window OSで直接起動するのに比べて、10%〜20%ぐらいの性能低下がある。

(追記: 優秀だというのは、wineに比べてという意味で、ゲームの種類によっては非常に苦手なジャンルがある。特にメモリ監視系のアンチチートツールが必須になる様なPvPのネットワーク対戦型ゲームは対応が困難だと思われる。自分が余りそのジャンルをやらないので、個人的には余り困っていない。)

WindowsのゲームではDirectXが必要なケースが大半だが、ProtonではDirectXの互換APIがデフォルトで組込まれている。昔はwined3dというコンポーネントDirectXの互換APIを提供していたが、最近のDirectX10以降はvulkanをベースにしたコンポーネントによって実装されている。そのためvulkan driverをインストールしておく必要があり、mesaのvulkanフラグを有効にしておく必要がある。

また、DirectXのバージョンによって微妙に実装しているコンポーネントが異なるのでややこしい。DirectX9, 10, 11はdxvkというツールによって実装されており、DirectX12はvkd3dというツールによって実装されている。

github.com

github.com

コントローラーの利用方法

自分が動作確認したのはPS4のDualShock4と、XBox One S Controllerなので、この二つを利用する方法を解説する。

PS4のコントローラーのドライバはLinuxカーネルに組込まれているので、それを有効にすれば認識する。具体的にはCONFIG_HID_SONYとCONFIG_SONY_FFを有効にすれば良い。

カーネルコンフィグの項目で言うと、 Device Drivers -> HID support -> HID bus support -> Special HID drivers にある。

XBoxの互換コントローラーの場合も組込みドライバがあり、JOYSTICK_XPADを有効にすれば良いのだが、これはかなり古いXBoxコントローラー限定で、XBox One S以降のコントローラーだと上手く動作しない。古いXBoxコントローラーや、サードパーティの互換コントローラーなら組込みのドライバで動作するはずなので、その場合はこちらを有効にすると良い。場所は、 Device Drivers -> Input device support -> Generic input layer -> Joysticks/Gamepads にある。

では、XBox One S Controllerならどうするかというと、xpadneoというオープンソースのドライバがあるのでこれをコンパイルしてインストールする必要がある。他にもいくつかドライバ実装があったのだが、これが一番ちゃんと動作した。

github.com

Gentooなら基本的にKernelは自前でコンパイルしているので、kernelモジュールをコンパイルする環境は揃っているはずなので、余り苦労は無いと思う。

リポジトリをクローンしてきて、hid-xpadneoディレクトリに移動し以下のコマンドを実行する。

make modules
sudo make modules_install

ちなみに、このドライバは何故かBluetooth専用なので、xpadneoを利用したい場合はBluetoothを利用できる様にしておく必要がある。

BTを利用する方法はこちらが参考になるだろう。

Bluetooth - Gentoo Wiki

BTが利用できる様になったら、ERTMと呼ばれる機能を無効化しておく必要がある。cat /sys/module/bluetooth/parameters/disable_ertmの出力がYになっていれば良い。無効になっていないなら、boot時のkernelパラメーターかmodprobeのconfigで設定を変更しておく。

例えばboot時のkernelパラメーターなら/etc/default/grubでこんな感じに設定する。

GRUB_CMDLINE_LINUX_DEFAULT=" bluetooth.disable_ertm=1"

xpadneoはかなりBluetoothドングルとの相性がシビアで、自分の環境だとBroadcomのチップの安定性が高く、CSR(Qualcomm傘下)製のチップはかなり不安定で微妙だった。

コントローラーや環境によって、ボタンのマッピングがおかしくなってる可能性があるので、レイアウト設定を確認しておく。

f:id:joker1007:20210410215506p:plain

f:id:joker1007:20210410215511p:plain

動作確認したゲーム一覧

大体、上記のことを実施すれば大抵のゲームは動作する。自分が実際にLinuxでプレイしたゲームは以下の通り。

  • Cyberpunk 2077
  • Dead Cells
  • DIRT Rally 2.0
  • Dyson Sphere Program
  • Ghostrunner
  • Hades
  • Hollow Knight
  • Metro Exodus
  • Noita
  • Nova Drift
  • Orwell
  • Oxygen Not Included
  • Satisfactory
  • ScourgeBringer
  • Skul: The Hero Slayer
  • Stellaris
  • ハードコア・メカ

(Linuxネイティブに対応しているものも含む)

何故かゲームによってはLinux Native対応を謳っていても、Windows互換モードじゃないと起動しないものが結構多くある。Dead CellsとかSkulとかはそんな感じだった。

また、Protonのバージョン次第ではコントローラーがちゃんと認識しない可能性がある。その場合、コントローラー設定をゲームごとに弄る必要があるかもしれない。

上記のゲームの中ではCyberpunk 2077が一番設定がシビアで2番目がMetro Exodusだった。設定が適切なら快適なのだが、噛み合わないとGPUごとハングアップしてPCが固まる場合がある。そうなると再起動するしかないので、AAAゲームを起動するのは結構大変。普通にWindowsデュアルブート可能にした方が楽と言えなくもない……。

Advance: mangohud, vkbasalt

mangohud: vulkan driverの情報や現在のfpsをoverlay表示できるツール

github.com

vkbasalt: vulkanのpost processingツール。レンダリングされた3Dグラフィックにシェードをかけたり、シャープフィルタかけたりできる。かなり画質が変わるのでゲームのよっては見た目がかなり綺麗になる。

github.com

上記の様なvulkan周りのツールを利用することで、ゲームの表示をカスタマイズできる。コンパイルしてインストールしたら、環境変数でオン・オフを制御できる。

ゲームごとの設定で、起動オプションを制御することができるので、そこに以下の様に設定する。

f:id:joker1007:20210410222346p:plain

ENABLE_VKBASALT=1 %command% 

vkbasaltはゲームによって多少相性があり、Cyberpunkみたいな設定がシビアなゲームで利用するとGPUごとクラッシュする可能性があるので、何でもかんでも使える訳ではないが、上手く動作するゲームならHDRモードみたいに色彩強化したり、かなりポリゴンの見た目を改善することができる。

Advance: SteamTinkerLauncher

Steam関連ツールは他にも結構色々あるみたいで、Vortexというmod管理ツールとか、ReplaySorceryというBackgroundでリプレイ動画をキャプチャしてくれるツールなどもある。

こういうのを逐一設定するのは面倒なので、SteamTinkerLauncher (stl) を利用して一括でオン・オフを管理することができる。

github.com

ここまでやる必要はあんまり無いのだが、関連ツールの情報が色々あるのでリポジトリを見ておくと便利なものが見つかるかもしれない。

stlはyadというgnomeのdialogウインドウを作るツールを使って色々設定できる様にしたshell scriptで、steamの起動の途中に挟み込んでゲームごとに色々な設定を読み込むランチャーとして動作する。

上記の起動オプションの項目を以下の様に設定する。

stl %command%

そしてゲームごとに色々設定するにはstl menuで起動した後、対象ゲームを選択し、GAME MENUから色々とオンオフしていく。異様に設定できる項目が多いので、正直自分も良く分かっていない。

Epic Gamesについて

自分はEpic Gamesを利用したことが無いので、実際どんな感じで動作させるのか良く分かっていないが、lutrisというツールを使うことで、Epic Gamesのゲームもプレイできるらしい。 Steamのprotonを利用することもできるはず。

Lutris - Open Gaming Platform

Linux:「Lutris」最強?のゲーム管理ツール | SlackNote

Linuxでのビデオ会議のためのオーディオ環境

Linuxに乗り換えようかなと思っている人向けにビデオ会議のためのオーディオ環境構築の一例を紹介する。

ハードウェア

Audio I/F: Focusrite Scarlett Solo 3rd Gen

focusrite.com

1万円ちょっとで買えるし、ダイレクトモニターも付いてるし、Linuxのusbaudioドライバで問題無く動作する。 音声入力に対して不満は無いが、ヘッドホンを刺して普通に音楽を鳴らすとめっちゃ硬い音がするので、入力にのみ利用している。

マイク: Shure SM58

www.shure.com

大分昔に買ったボーカルマイクを流用。コンデンサマイクではないが、1万円ぐらいで安い、単一指向性、丈夫、定番、という安定感のあるマイク。 これをテーブル置きのマイクスタンドに設置して利用している。 マイクヘッドを顔側に向けて、インターフェースのゲインを上げれば、30cmぐらい離れていても普通に拾う。

カメラ: Logitech C920 HD Pro Webcam

www.logicool.co.jp

これも1万円ぐらい。既に結構古いが大抵のノートPCのカメラよりは綺麗に映る。Linuxのuvcvideoドライバで問題無く動作する。オートフォーカスも問題なく動く。

ソフトウェア

ノイズ除去: noise-suppression-for-voice

github.com

ニューラルネットワークを利用したRNNoiseというノイズリダクションライブラリを利用したリアルタイムノイズ低減プラグインOSS (GPL-3.0)。

DAW等で良く利用されるVSTプラグインか、Linuxのpulseaudioで利用できるladspaとしてコンパイルできる。

しばらく利用しているがかなり優秀で、環境音はかなり低減できてキーボードをカチャカチャやる音はほぼ消せるし、マイクの側で呼吸しても呼吸音が聞こえなくなる。咳とかはタイプに依る感じ。乾いた咳は結構消えてくれる。

コンパイルの手間はあるが、使う価値はある。

pulseaudio設定: pagraphcontrol

github.com

pulseaudioの設定は基本テキストなので、グラフィカルにやれる様にしてくれるツール。ただ、自分はjack audioに乗り換えたので、こちらは余り利用していない。

pulseaudioをちゃんと設定すれば、特定のオーディオラインにだけエフェクトをかけたりできるし、zoomから流れてくる音声に対して自分のマシンでノイズ除去をかけたりできるのだが、そういうのを視覚的に楽にしてくれる。

jack audio設定: Carla

kx.studio

普通Jack Audioとか使わないと思うんだけど、もし利用したいならCarlaを使うと設定が楽になる。pagraphcontrolみたいにグラフィカルに線を繋げてエフェクトをかけられる。

Jack Audioを使う利点はpulseaudioより遥かにレイテンシを下げられたり、プラグインの幅が広がるところ。

おまけ: PulseEffects

github.com

もし、声や音に色々エフェクトかけて遊びたいなら、PulseEffectsを使うのが手軽で良い。エコーかけたりイコライザ通したり歪ませたり、基本のプラグインだけでも結構色々できる。

ビデオ会議ツールについて

zoomとかdiscordとかは普通に利用できる。ブラウザ系のミーティングツールも基本問題は無い。

ただwaylandを使っているとデスクトップキャプチャが結構面倒なことになる。pipewireとかを駆使すれば出来るらしいが、自分はwaylandを常用していないので余り試せていない。

まとめ

実際、音声周りはプロフェッショナルクオリティを求めないのであれば、Macよりよっぽど自由にやりやすいので、むしろMacより環境が良くなったと思う。

個人的には音声の聞き取り易さというのは結構会議中のストレスに影響するので、ちゃんとしたマイクとノイズ低減の工夫はした方が良いと思う訳で、何かしら参考になれば良いと思う。

2021年を戦うためのRyzen9 5900Xマッシーンを組んだ

年末、たまたま見つけたRyzen9 5900Xを勢いで買ってしまったので、そのまま流れで新しいPCを組むことにしました。 年始っぽくて良いかなとも思ったり。

構成は以下の通り。

Mother: ASUS ROG Strix X570-F Gaming (27k円)
CPU: Ryzen9 5900X (89k円)
Memory: ADATA DDR4-3200 64GB (non-ECC)  (24k円)
GPU: Sapphire AMD RADEON RX6900XT (150k円)
Cooler: NZXT Kraken X73 (24k円)
CASE: Fractal Designe Define 7 (23k円)
NVMe: CFDの1TB (16k円)
Power Supply: Owltech seasonic FOCUS PX-850 (21k)

合計で375000円ぐらい。全部増しMac Book Proよりちょっと高く付いたか、という感じです。 ノートPCと違ってディスプレイが別であることを考えると、割と奮発してしまった気がする……。

というかRADEON RX 6XXX系が全然売ってなくて、たまたま見つけたRX6900XTをこれまた勢いで買ってしまったので、予算が5万ぐらい増額されてしまった。 まあ、年始に今後数年使うものを組み上げるなら、範疇だろうとは思います。

中味はこんな感じ。

f:id:joker1007:20210108235739j:plain f:id:joker1007:20210110180657j:plain

結構レイアウトが工夫できるケースを買ってしまったので配線に悩んだり、先にAll-In-One水冷クーラー付けてしまってラジエーターの設置にえらい苦労したりしましたが、無事完成し起動しました。

top - 22:30:20 up  8:32,  3 users,  load average: 0.00, 0.16, 1.37
Tasks: 281 total,   1 running, 280 sleeping,   0 stopped,   0 zombie
%Cpu0  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu1  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu2  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu3  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu4  :  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu5  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu6  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu7  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu8  :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu9  :  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu10 :  0.3 us,  0.3 sy,  0.0 ni, 99.3 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu11 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu12 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu13 :  0.0 us,  0.3 sy,  0.0 ni, 99.7 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu14 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu15 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu16 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu17 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu18 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu19 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu20 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu21 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu22 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
%Cpu23 :  0.0 us,  0.0 sy,  0.0 ni,100.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
MiB Mem :  64283.2 total,  61441.9 free,    585.0 used,   2256.3 buff/cache
MiB Swap:      0.0 total,      0.0 free,      0.0 used.  63090.7 avail Mem

良いですね、12コア24スレッドと64GBのメモリ。

OSはいつもの様にGentoo Linuxを入れました。

% uname -a
Linux durandal 5.10.6-gentoo #1 SMP PREEMPT Mon Jan 11 02:51:36 JST 2021 x86_64 AMD Ryzen 9 5900X 12-Core Processor AuthenticAMD GNU/Linux

(良く見ると分かりますが、hostnameはdurandal。前のPCがfragarachだったのでジャンル的に近いものにした。代々続く厨二ネーミングです。)

Gentoo入れる時のトラブル

そもそも、zen3のCPUとRDNA2のRADEONが新し過ぎるので、Linuxカーネルはかなり新しいところを突っ込まないと色々と認識してくれませんでした。

5.4系でもCPU自体は認識して、FrameBufferのコンソールまでは立ち上げられます。 しかし、CPUの温度センサーが認識しなかったり、GPUカーネルモジュールがカードを認識してくれなかったりと、流石に運用できない感じですね。

なので、現行のgentoo-sourcesの中でほぼ最新まで上げました。まあ5.10系はLTSなのでその内Gentooでstable扱いの奴が出るでしょう。

その他のディストリだと、ArchかUbuntuFedoraの最新辺りを使えば、大体5.9以上になってるバージョンだと思うので多分大丈夫だと思う。

カーネルコンパイル時のconfigは、 AMDGPU - Gentoo Wikiに書かれている内容を良く読めば何とかなりました。(都度カーネルコンパイルしてる人はGentooユーザーぐらいだと思いますが……。)

忘れ易いのがfirmware類です。linux-fimwareパッケージを入れて、Firmware Loaderの設定にbinファイルの相対パスを入れてfirmwareを組み込んでkernel compileする必要があります。

その他、センサー類はCONFIG_K10TEMPとCONFIG_NVT6775を有効にしておけば大体問題無いと思います。

最近は、大体NVMeで共通のモジュールでストレージも動くので、後はそんなに困ることは無いと思います。

後は、水冷クーラーの流量調節ですが、 以下のツールを使うと良さそうです。 github.com

# liquidctl status
NZXT Kraken X (X53, X63 or X73) (experimental)
├── Liquid temperature    31.2  °C
├── Pump speed            1600  rpm
└── Pump duty               50  %

こんな感じです。

アイドル時はCPUは35度ぐらいで安定。全コアをフルでぶん回したら75度ぐらいで安定って感じです。 流石にフルパワー出すと、それなりに温度が上がる。

Terminal回りは大分使える様になったので、後はGUI回りを色々と整備していく所です。 この際だからwayland試してみようかなあとか思ってますが、上手くいくだろうか……。waylandだとawesome-wmが使えないんだよなあ……。

おまけ: Rubyベンチマーク

TwitterRubyコミッタのk0kubunさんから、Ryzen 9 5XXXでのoptcarrotベンチの結果が気になるという話を伺ったので、軽くベンチを取ってみました。 結果は以下の通り。

gist.github.com

1000万件オーバーのレコードのデータをカジュアルに扱うための心構え

自分が所属している会社のメンバーの教育用資料として、それなりの規模のデータを扱う時に前提として意識しておかなければいけないことをざっくりまとめたので、弊社特有の話は除外して公開用に整理してみました。

大規模データ処理、分散処理に慣れている人にとっては今更改めて言うことじゃないだろ、みたいな話ばかりだと思いますが、急激にデータスケールが増大してしまったりすると環境に開発者の意識が追い付かないこともあるかと思います。

そういったケースで参考にできるかもしれません。

弊社は基本的にAWSによって運用されているので、AWSを前提にした様なキーワードやサービス名が出てきます。後、句読点があったり無かったりしますが、ご容赦ください。

追記: 社内用の資料の編集なのでかなりハイコンテキストな内容だから誤解するかもしれませんが、これらはそもそもRDBの話ではありません。(関係無くは無いけど) 1000万オーバーの件数から数件取るとかそういう話ではなく数億件の中から1000万件を取得して数分以内に処理を終わらせるとかそういう処理を頻繁に(カジュアルに)実装しなければならない弊社の話でした。

1ノード, 1コアで処理してはいけない

  • 1件が200byteとしても1000万件を処理するなら2GB。これだけならメモリに乗り切らない程ではないが、オブジェクトにマッピングすると数GBを余裕で越えたりするし、1億件なら数十GBを越えるかもしれない。
  • 1件処理するのにかかる時間が1msecでも1000万件を処理すると1万秒 (3時間弱) かかる。
  • RubyはGILに引っかかるのでそもそも余り向いてない。可能ならマルチスレッドで処理を行い易いGoかJava辺りの利用を検討すること。(別にRustとかC++でも良いけど)
  • 上記以上の規模や負荷がかかる場合はノードごと分散することを検討する

通信回数を減らせ

  • 1度の通信が1msecで完了しても、1000万件を処理すると1万秒 (3時間弱) かかる。
  • 通信レイテンシやラウンドトリップタイムによってスループットの限界が決まる。通信回数が多いとワイヤースピードよりも遥かに低速で律速する。
  • redisキャッシュに接続してデータ取るのにもコストがかかる。

通信は常に失敗する可能性がある

  • 通信の信頼性はそんなに高くない。AWSの中でも度々不可解なネットワークの断絶が起きる。
  • 突然通信が終了すると、片側で終わったということすら検知できない場合があるため、状態遷移が中途半端な状態で処理が止まる可能性を考慮しなければならない

エラー対象を特定可能にしておく

  • エラーが起きた時に、どのデータに異常があったか判別できないと1000万オーバーのデータから大体の検討で探すことになり、非常に時間がかかる
  • 実装に不具合があった場合、特定パターンのデータが到達したら即座にシステムごと死ぬケースもある。
  • エラートラッキングサービスに必要なメタデータを付与してエラーを送る様にする
  • 一方で、ignoreして処理継続可能なエラーを都度トラッカーに送ると、一瞬で数十万のエラーが積み重なって課金額がえらいことになる危険があるので、注意すること。

リトライ可能ポイントを考慮しろ

  • リトライ機構は常に必要である
  • 1000万件処理している時の990万件目で処理が死んだ時、残りの10万件でリトライ可能にできるかを考慮する
  • 処理が複数ステップに跨る時は、ステップごとにコンポーネントを分けワークフローエンジンによってコントロールすること
    • 個別のステップを独立して実行可能にしてリトライ可能ポイントやテストデータ投入ポイントを挟む
  • 仕組みの単純化トレードオフになるケースもあるので、フルリトライが最善であるケースもある

羃等性の維持

  • リトライ時に状態の回復を要求すると自動リトライが困難になる
  • 処理の最初から流せば常に同じ状態になる様に設計することで、リトライに関わる処理が単純化できる
  • at least onceはexactly onceより圧倒的に処理負荷が軽い、羃等であるならat least onceで安全に処理できる
  • 羃等にすることが難しい処理に注意
    • カウントアップ等の今のデータからの差分を書き込む処理

分散処理ではロカリティ(データの所在)を意識する

  • 複数データのJOINが必要な場合、同一のキーであらかじめデータを同じ箇所に集めておいてから結合しないと、データの再配置が必要になる。再配置 = 大容量の通信処理であり高負荷。
  • 出力の全件Orderingは基本的に全てのデータを集約しないとソートできない

モニタリング必須

  • 関連するコンポーネントが増えるとボトルネックが分かり辛くなる。全ての箇所でモニタリング機構を整備すること。
  • コンポーネントに跨る様な処理の場合はdatadogに全体を俯瞰できる専用のdashboardを作る。
  • 最低限下記のリソースをモニタリングすること

    • CPU利用率とiowait
    • Disk I/O (iopsとスループット)
    • ストレージ消費
    • メモリ消費
    • ネットワークスループット
    • GC統計
    • 通信レイテンシ (中央値・最大値、90〜95パーセンタイル辺り)
  • 追加でモニタしておきたいもの

    • 無視できるエラーの回数、異常データの数や出現頻度
    • 処理遅延 (キューイングから処理されるまでの待ち時間)
    • DBへのqps
    • キャッシュヒット率 (キャッシュ機構がある場合)

余裕を持ったリソース確保 (staticかオートスケーリング かを問わない)

  • 唐突に大きな顧客からのアクセスが増えることがあるため、常に最低でも2倍ぐらいの負荷に耐えられる余地を残しておきたい
  • staticなノードの場合は、上記の様にモニタリングをしっかり整備し、早い段階でノード追加、スケールアップを行える様にアラートを整備する
  • それ以外のノードはオートスケーリングもしくは処理のキューイングに応じて自動的に必要なリソースを確保する機構が必須である
    • FargateやLambdaも活用できるし、リソース確保が簡単になる。それらの制約に対応出来る場合は検討の余地がある。
    • オートスケーリングの基本は増やす時は大胆に増やし、減らす時は少しづつ減らす

工程毎のログを吐け

  • バルク処理は長時間動作する上、複数ステップを伴うことがあるので、適宜ログを吐かないと、どこまで進んでいるか分からない。
    • 特定処理でスタックしてエラーにもならなかった場合に、進捗が確認できなくなる状態を避けたい
  • 一方で一件単位で詳細なログを吐くとログのデータサイズやログ出力の負荷が馬鹿にならないので、レコード個別のログについては必要性を考慮すること

汎用的なETL基盤を構築すること

  • importやexport等を個別の機能ごとに作るべきではない
  • 個別に作るとスケーラビリティの問題に個別で対処しなければならなくなる
  • 現状だとembulkをラップして実行できる基盤を準備し、必要があれば適宜プラグインを書くと概ね対応できる。

既存のコードを信用するな

  • 誰が書いたコードであっても1年以上前のコードがベースになっている箇所を信用してはならない
    • 実装を理解し現時点でも問題無いかどうかを確認すること
  • 1年あれば提供規模や顧客規模も変わるし、会社として注力している箇所も変わる。

    手癖で書くな

  • 量が変われば解決方法が変わる
  • 1年前と同じ方法では機能提供できないケースが多い
  • 特にWebシステム開発の手癖をバルク処理に持ち込んでは駄目。

クラウドサービスを使え

  • クラウドサービスの機能を理解し、不要な開発工程を減らすこと
  • ちょっとでも関係しそうなサービスを見かけたらとりあえずドキュメントを読む癖を付けておかないと、いざという時に思い付かなくなる。
  • 以下のサービスはデータ処理基盤において特に重要で、日常的に検討対象に入るので定期的に復習し新機能をキャッチアップすること
    • S3
    • SQS
    • SNS
    • Elasticsearch
    • ElastiCache
    • ECS/Fargate
    • StepFunctions
    • CloudWatchEvents

追記: 社内用の資料から対象を絞り込んだ時に消えてたもの

  • EMR
  • Athena