Javascriptのコンテナ性能比較
ちょっとスピード狂をやる必要があって色々調査した。
こういう選択は用途によってコンテナのアルゴリズムが決まる。 しかしJS標準ではC/C++のSTLのようなアルゴリズムの選択肢が無くNPMに頼ることになるが実装まで読まないと何をしているのか解らないモジュールや効率的に実装されているかどうかも解らない。 一々性能試験をしなきゃならず面倒だが、やらない訳にもいかない。。
想定状況
- 数値データ
- 値は重複する
- insert / delete が頻繁に発生する
- 指定値による参照が大量に発生する
- 範囲検索が起きる
- 長時間安定稼働する必要がある
分岐検索とイテレータブルを両立し、かつ効率的な挿入削除ができること。が必要。
アルゴリズムとしてはバイナリーツリーとデータ量によってはソート済み配列が候補になる。
AVLやRedBlackはinsert / deleteがランダムに入る状況では採用したくないので除外。
テストコード
GitHub - crumbjp/test_js_containers
テスト対象モジュール
期待しているのは、★ だけ。あとはネタ枠。ほんの少しだけ掘り出し物を期待。
標準Array(比較対象)
ソートせずにpush。線形探索。spliceで削除。
★ 標準Arrayをソート済みに保つ
ソート済みを保ちlodashのsortedIndexByで2分探索。 insert / delete はsplice。位置の特定までは早いが、spliceのindex付け替えコストが高い。
★ @tylerbu/sorted-btree-es
sorted-btree
のクローン。
ウクライナの問題もあって、本家がCommonJS形式で読み込めなくなっている状態に対処している。’
そのままでは、値の重複が許されないため、データ構造側で少し工夫をしている
taffydb
GPT4oが教えてくれた。古すぎる・・・ インデックスを指定しなくともクエリーを最適化してくれるらしい。(そんな馬鹿な)
★ LokiJS
コンテナというよりインメモリーデータベース。有名どころだが、もう何年も更新がない。
柔軟にインデックスを貼れるので便利。
ただクエリーが思ったように動かない事があり、複雑が故にその解析も大変で、多く個人的には好きではない。
nedb(比較対象)
昔気になっていたもの。インメモリーでも使えるデータベース。
TingoDB
昔気になっていたもの。MongoDB互換のクエリーを謳ったインメモリーデータベース。
この頃流行ったスタイルだなぁ・・・と懐かしくなる。
結果
M3 Mackbook pro で計測
コンテナに保持しているデータ数毎、各処理を1000回試行した際の処理時間(ms) ただしrange処理は1回だけ試行
insert

class | 1067 | 5257 | 10744 | 53009 | 105667 | 317043 | 528166 | 739974 | 1056478 |
---|---|---|---|---|---|---|---|---|---|
TestArray | 0 | 0 | 1 | 0 | 1 | 14 | 1 | 1 | 2 |
TestLoki | 1 | 1 | 3 | 6 | 11 | 88 | 153 | 206 | 325 |
TestNedb | 23 | 21 | 20 | 25 | 24 | 26 | 30 | 30 | 27 |
TestTingodb | 8 | 5 | 4 | 8 | 4 | 6 | 13 | 5 | 12 |
TestBTree | 1 | 1 | 1 | 0 | 2 | 1 | 1 | 1 | 2 |
TestSortedArray | 1 | 0 | 0 | 15 | 19 | 404 | 709 | 976 | 1707 |
TestTaffy | 6 | 5 | 6 | 6 | 6 | 5 | 5 | 5 | 5 |
SortedArrayはデータが大きくなるとspliceの処理が如実に効いてくる。
Lokiはインデックス構築のコストが高い。
adaptiveBinaryIndices: false
を指定するとindexの処理を遅延実行(その後の最初のfind時)してくれるためbulkinsertで使えると思いきや、indexへの挿入ではなく完全再構築になり余計遅くなる。
findOne

class | 1067 | 5257 | 10744 | 53009 | 105667 | 317043 | 528166 | 739974 | 1056478 |
---|---|---|---|---|---|---|---|---|---|
TestArray | 9 | 28 | 53 | 237 | 446 | 1204 | 1730 | 2326 | 2815 |
TestLoki | 3 | 1 | 2 | 2 | 4 | 3 | 3 | 2 | 4 |
TestNedb | 44 | 42 | 42 | 50 | 42 | 41 | 42 | 46 | 49 |
TestTingodb | 63 | 58 | 59 | 64 | 59 | 58 | 72 | 73 | 75 |
TestBTree | 2 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
TestSortedArray | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 | 2 |
TestTaffy | 234 | 727 | 1337 | 6192 | 12202 | 36712 | 61332 | 87991 | 127708 |
単純に2分探索を実現できているものとそうでないものに分かれる。
線形探索より遅いtaffyはどうした(笑)。GPTもこんなものを勧めるんじゃないよ。
rangeGet

class | 1081 | 5314 | 10585 | 52874 | 105466 | 317402 | 528743 | 739463 | 1057958 |
---|---|---|---|---|---|---|---|---|---|
TestArray | 1 | 0 | 0 | 1 | 2 | 5 | 14 | 10 | 16 |
TestLoki | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 6 | 6 |
TestNedb | 2 | 1 | 1 | 3 | 3 | 12 | 20 | 26 | 36 |
TestTingodb | 12 | 12 | 14 | 35 | 56 | 148 | 250 | 325 | 613 |
TestBTree | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 2 | 2 |
TestSortedArray | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
TestTaffy | 1 | 1 | 1 | 9 | 15 | 43 | 73 | 119 | 142 |
線形探索が侮れない速さ。下手にインデックスを追う処理より全部舐めた方が早いケースも多々あるということ。
delete
class | 1081 | 5314 | 10585 | 52874 | 105466 | 317402 | 528743 | 739463 | 1057958 |
---|---|---|---|---|---|---|---|---|---|
TestArray | 6 | 27 | 35 | 255 | 477 | 1006 | 2534 | 2264 | 3012 |
TestLoki | 7 | 9 | 13 | 40 | 108 | 282 | 502 | 655 | 896 |
TestNedb | 45 | 43 | 48 | 46 | 48 | 50 | 51 | 58 | 56 |
TestTingodb | 117 | 114 | 115 | 164 | 140 | 118 | 129 | 126 | 131 |
TestBTree | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 3 | 3 |
TestSortedArray | 1 | 1 | 1 | 24 | 51 | 411 | 664 | 980 | 1502 |
TestTaffy | 455 | 1675 | 3293 | 17075 | 35283 | 102415 | 12309541 | 29964609 | 17357942 |
やはりspliceのコストが目立つ
まとめ
- sorted-btreeの実装は期待通りだった。
- 期待していなかったnedbは完成度が高かった。もっと複雑な用途でインデックスを複数貼りたいようなケースでは検討できる
- LokiJSはinsert / delete に弱く、クエリーは早い。データ量が少なかったり、更新頻度が低いならば検討できる
- やはりNPMモジュールは期待通りに動かないので、検証活動は必須
コマンド直列化スクリプト
並列で動いているバッチプロセスが叩く外部コマンド(ffmpeg)がメモリーをバカ食いするケースが有って、タイミングが重なるとサーバーメモリーが枯渇するのでそこだけ直列化した。
作ってみたら便利だったので記事にした
#!/usr/bin/bash set +e PID_FILE=/tmp/`echo $1 | sed 's/\//_/g'`.pid LOCK_FILE=/tmp/`echo $1 | sed 's/\//_/g'`.lock WAITING='1' while [ "$WAITING" = '1' ]; do if [ -e $LOCK_FILE ]; then echo 'Locked' sleep 1 continue fi touch $LOCK_FILE exec 9> $LOCK_FILE flock -n 9 if [ "$?" = "1" ]; then echo 'Flocked' sleep 1 continue fi WAITING="0" echo touch $LOCK_FILE if [ -e $PID_FILE ]; then PID=`cat $PID_FILE` if [ "$PID" != '' ]; then ps -v -p $PID | grep -c $1 > /dev/null if [ "$?" = "0" ]; then echo "Wait for $PID ($1)" WAITING='1' rm $LOCK_FILE sleep 1 fi fi fi done echo '====START====' echo "$*" $* & echo $! > $PID_FILE rm $LOCK_FILE set -e wait `cat $PID_FILE` echo '====END===='
mac の場合は brew install flock
が必要。
axiosのソケットリークでハマった
このシンプルなコードでソケットリークが起こる事に気付いた。
実際には膨大なコードの中からココに疑いも持った段階で9合目って感じだが・・・
const axios = require('axios'); const consumers = require('stream/consumers'); const get = (url) => { return new Promise(async (resolve, reject) => { try { const res = await axios.get(url, {responseType: 'stream'}); resolve(await consumers.buffer(res.data)); } catch (e) { reject(e); } }); };
responseType: 'stream'
を指定した場合は、Stream (Socket)がまだ開いていて自前で処理してあげなきゃならない。
consumers.buffer(res.data)
は、普通にchunk処理してBlobに渡してるだけだが、Streamを最後まで読んでいるのでcloseまで到達しているはずである。
ここは問題ない
問題はここ
} catch (e) { reject(e); }
盲点だったのだが、接続エラーで到達するならば問題ないが、なんとBad Request などでも到達するのだ。当然ペイロードがある。
そして responseType: 'stream'
ならば未処理のStreamである。
コイツがリークする!!
例外で飛んできてるので、response が受け取れてないが、例外の中に埋められている。
const _ = require('lodash'); const axios = require('axios'); const consumers = require('stream/consumers'); const get = (url) => { return new Promise(async (resolve, reject) => { try { const res = await axios.get(url, {responseType: 'stream'}); resolve(await consumers.buffer(res.data)); } catch (e) { const socket = _.get(e, 'response.data.socket'); if (socket) { socket.destroy(); } reject(e); } }); };
これで解決。
全然情報が無かったのだけど、、
レスポンスが正常に返ってくれば問題ないから気付き難いだけで、みんなリーク喰らってるんじゃないかな?
dockerコンテナ(ubuntu 20.04 LTS arm64)内でChromiumを動かすのが大変だった件
経緯
ubuntu 18.04 LTSのサポートが1年を切ったのでubuntu 20.04 LTSにアップデートしようとしていた。
実サーバー側の検証はそれ程大きな問題はなかったがCI環境でE2Eテストを行う部分で、コンテナ内でChromium headlessを使っており、これが思いの外難産だった。
技術的背景
1. Google Chromeが使えない
本来、googleがバイナリ配布しているChromeが使えれば良いのだが、Linux arm64バイナリは提供されていない。 なのでChromiumを使う必要がある
2. Ubuntu 19.10以降、ChromiumのAPT(deb)パッケージが廃止
バイナリはsnap版に移行し、debパッケージはsnap installに迂回するようになった。
3. Dockerコンテナ内でsnapが使えない
普通にDocker buildするとsnapdが立てられないのでsnap install が失敗する。
# snap install chromium error: cannot communicate with server: Post http://localhost/v2/snaps/chromium: dial unix /run/snapd.socket: connect: no such file or directory
解決法
Dockerコンテナでsnapdを動かす
偉い人が作ったDockerコンテナジェネレータがあったので、これを改造して使ってみた。
これを紐解くと以下のようなDockerfileになる。
なるほど、、systemd経由でsnapdを起動する構造はそのままで、/sbin/init
から上げて行くわけね。
Dockerfile
FROM --platform=linux/arm64 ubuntu:20.04 ENV container docker ENV PATH "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin" ENV LANG C.UTF-8 ENV LC_ALL C.UTF-8 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y fuse snapd snap-confine squashfuse sudo init && apt-get clean && dpkg-divert --local --rename --add /sbin/udevadm && ln -s /bin/true /sbin/udevadm RUN systemctl enable snapd VOLUME ["/sys/fs/cgroup"] STOPSIGNAL SIGRTMIN+3 CMD ["/sbin/init"]
ハマった点
無事snapdは上がり、snapコマンドは通る
snap list Name Version Rev Tracking Publisher Notes core 16-2.56.2+git3949.06393d8a6 13434 latest/edge canonical** core
ところが、実際のinstallは失敗する
# snap install chromium error: cannot perform the following tasks: - Run configure hook of "chromium" snap if present (run hook "configure": aa_is_enabled() failed unexpectedly (No such file or directory): No such file or directory)
調べていくと、workaroundを提示している人が居た
# mount -t securityfs securityfs /sys/kernel/security
確かに、/sys/kernel/security
が空だったのでmountすることで見事に解決した。
# snap install chromium chromium 102.0.5005.115 from Canonical✓ installed
しかしDockerfileで解決出来ないのは困ったな。。
MongoDBの統一トポロジー(useUnifiedTopology)について
最近のMongoDBドライバーはエラーが出る
(node:8746) [MONGODB DRIVER] Warning: Current Server Discovery and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to the MongoClient constructor.
で、その新トポロジーの説明はこれ。
すごくザックリ内容を紹介すると
- 接続中(connected)という状態とはなんぞや?
- 実際のネットワークが接続状態という事に意味はあるのか?
- 別にになっていなくても処理可能な状態を保っていれば良いよね?
- だからisConnectedも将来廃止するよ。
- 直ちに処理出来ない状態でもドライバー内でなんとか辻褄取るよ
- でも失敗したら30秒位でエラー返すよ
なので、useUnifiedTopology
と autoReconnect
を両方指定すると怒られる。
(node:8962) [MONGODB DRIVER] DeprecationWarning: The option `autoReconnect` is incompatible with the unified topology, please read more by visiting http://bit.ly/2D8WfT6
新しいトポロジーでは、利用者側は接続状態を気にしなくて良い事になっているからね。
ザックリ図解
現行ReplicaSet
readPreferenceに合致するコネクションを割り当てる事しかしない。
一度コネクションを取得した後は素通し。
コネクションプール内のコネクションが全部エラーで破棄されるまでエラーが続く。
新統一トポロジー
1層咬んでいるのでエラーにならない所を勝手に探してくれる。
全部ダメならタイムアウトserverSelectionTimeoutMS
までリトライする。
実際の挙動
createConnection
現行ReplicaSet
require('mongoose').createConnection('mongodb://localhost:27017/foo', { autoReconnect: true, readPreference: 'secondaryPreferred' })
直ちにエラーが帰る
MongoNetworkError: failed to connect to server [localhost:27017] on first connect [Error: connect ECONNREFUSED 127.0.0.1:27017 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1161:16) at TCPConnectWrap.callbackTrampoline (node:internal/async_hooks:130:17) { name: 'MongoNetworkError' }]
新統一トポロジー
require('mongoose').createConnection('mongodb://localhost:27017/foo', { useUnifiedTopology: true, readPreference: 'secondaryPreferred', serverSelectionTimeoutMS: 30000, })
約30秒後にこうなる
> Uncaught MongooseServerSelectionError: connect ECONNREFUSED 127.0.0.1:27017 at NativeConnection.Connection.openUri (/****/node_modules/mongoose/lib/connection.js:847:32) at Mongoose.createConnection (/****/node_modules/mongoose/lib/index.js:291:17) { reason: TopologyDescription { type: 'Unknown', setName: null, maxSetVersion: null, maxElectionId: null, servers: Map(1) { 'localhost:27017' => [ServerDescription] }, stale: false, compatible: true, compatibilityError: null, logicalSessionTimeoutMinutes: null, heartbeatFrequencyMS: 10000, localThresholdMS: 15, commonWireVersion: null } }
fetch
図解の通りに動くので、動作確認のコード例だけ。
このコードを動かしてレプリカセットのノードを落としたり上げたりすればいい。
新統一トポロジーの方は全ノードを落として、再起動せずにタイムアウトに抵触するまではエラーが出ない。
現行ReplicaSet
let conn = null; require('mongoose').createConnection('mongodb://localhost:27018/foo', { replicaSet: 'RS', autoReconnect: true, readPreference: 'secondaryPreferred'}).then(r => conn=r).catch(r => console.log('---', r)); (async () => { for(let i = 0; i < 100000;i++) { try { let r = await conn.db.collection('tests').findOne({i: 1}); console.log(i, r); } catch(e) { console.log(e); } } })();
新統一トポロジー
let conn = null; require('mongoose').createConnection('mongodb://localhost:27018/foo', { replicaSet: 'RS', useUnifiedTopology: true, readPreference: 'secondaryPreferred'}).then(r => conn=r).catch(r => console.log('---', r)); (async () => { for(let i = 0; i < 100000;i++) { try { let r = await conn.db.collection('tests').findOne({i: 1}); console.log(i, r); } catch(e) { console.log(e); } } })();
注意
良い改善だとは思うが、ハイロードな環境下では、30秒ものオペレーションを貯めたり再送して重複処理するのは危険極まりない。
しっかり設計せずに移行するのは危険だ。
10TBクラスのmongodb ReplicaSet 運用ナレッジ
オススメの構成
[primary] - priority = 2 [secondary] - priority = 1 : (必要なだけ) : [backup] - priority = 0 - hidden = true
POINT
1. Primaryが好き勝手変動すると運用上の取り回しが悪いのでなるべく同じノードがPrimaryになるようにする
2. バックアップ中はOplog反映遅延が起こるのでクライアントクエリーをさせないhidden属性にしておく
3. 増強やバックアップや復旧を円滑に行うため、全てのノードでデータディレクトリは別のEBSボリュームにしておく
例えば10TBクラスのEBSでヘビーユースのReplicaSetだと毎日差分スナップショットを取っても4時間ほど掛かりバックアップ後にOpTimeが追いつくまで5~6時間かかる。
スナップショット(バックアップ)のとり方
データ整合性を確保するために、スナップショット中の書き込みを抑止する必要がある。
rs:PRIMARY> db.fsyncLock(); ** ここでスナップショットを取る ** rs:PRIMARY> db.fsyncUnlock();
スクリプトにしてcron.dailyにでも放り込んでおくと良い
#!/bin/bash cd /path/to bash snapshot.sh --tmp mongo --host backup-prd1 -u root -p `cat safe_file` <<<'db.fsyncLock()'; bash snapshot.sh mongo --host backup-prd1 -u root -p `cat safe_file` <<<'db.fsyncUnlock()';
EBSの場合、差分スナップショットなので直前に一回捨てスナップショットを取っておくと差分が小さくなり、lock期間を短くする事が出来る。
snapshot.shは、awsコマンドなりSDKなりで適当に実装すればいい
Oplog設定・設計
config
replication: oplogSizeMB: 614400 #600GB
起動中に変更する場合
db.adminCommand({replSetResizeOplog: 1, size: 614400})
サイズの決め方
以下のコマンドで確認しながら最低3日分位は確保する。理由は当記事を読んでいけば解る。出来れば7日分程度欲しいが更新が激しい場合は非効率になってしまう場合もある。
rs:PRIMARY> rs.printReplicationInfo() configured oplog size: 614400MB log length start to end: 183206secs (50.89hrs) oplog first event time: Mon Jul 05 2021 21:52:36 GMT+0900 (JST) oplog last event time: Thu Jul 08 2021 00:46:02 GMT+0900 (JST) now: Thu Jul 08 2021 00:46:02 GMT+0900 (JST)
うわ。。足りてないね・・・
oplog first event time
がこのノードが保持している一番古いOplogなのでこれ以上遅れてしまったSecondaryはもう同期出来なくなる。
遅延状態の確認方法
rs:PRIMARY> rs.status().members.map((member)=> [member.name, member.optimeDate.toLocaleString()]) [ [ "primary-prd1:27017", "Thu Jul 8 00:16:10 2021" ], [ "secondary-prd1-prd4:27017", "Thu Jul 8 00:16:09 2021" ], [ "secondary-prd2:27017", "Thu Jul 8 00:16:09 2021" ], [ "secondary--prd3:27017", "Thu Jul 8 00:16:09 2021" ], [ "backup-prd1:27017", "Wed Jul 7 16:18:33 2021" ] ]
ノードが壊れた場合
パターン
1. データファイル破損
エラーになってmongodが起動しない
→ ノード再構築
2. [rsBackgroundSync] replSet error RS102 too stale to catchup...
反映しなければならないOplog古すぎ、ReplicaSetメンバーの誰も持っていない
状態は1. と同じ。
3. [initandlisten] Taking 999 samples and assuming that each section of oplog contains approximately...
mongodを再起動した際に、エラーにはならないがこのログで止まる
→ ひたすら待つ。1日待っても良い。Secondary復帰後もOplog反映が遅くどんどん遅延して行くが1日位で正常なパフォーマンスに戻り追いつき始める
ノード再構築
1. 単純にデータディレクトリ以下を全て消す
この場合のmongodの挙動は以下
1. mongod起動(STARTUP2)
2. 他のreplicaSetメンバーから接続され同期が始まる(STARTUP2)
3. 同期元のノードからCollection毎にデータ取得 -> Index構築
を繰り返す(STARTUP2)
4. 全てのDB/Collectionの構築が終わったら2.時点のOplogを起点に差分を反映する(STARTUP2)
5. Oplogが追いついたら完了(SECONDARY)
大きなCollectionでIndexが大量あれば、3.は時間がかかる。
私の運用しているReplicaSetでは余裕で2週間はかかるのでOplogを巨大にしない限り4.の段階で Stale
となる。
それをやったとしてもOplogが追い付くまでに掛かる時間も膨大で完了まで1ヶ月以上は覚悟しなければならない。
TBクラス以上の大きなReplicaSetでは現実的ではない。
2. なるべく新しいスナップショットからデータディレクトリを復旧(本命)
この場合のmongodの挙動は以下
1. mongod起動(STARTUP2)
2. データディレクトリ上の最後のcheckpointの状態でデータ復旧。1日近く掛かる事もある
3. 2.終了時に直ちにSECONDARYとなるがSnapshotを取った時点のデータなのでOpTimeが激しく古い状態(SECONDARY)
4. 通常のReplicaSetメンバーと同様の扱いでOplog反映を始める(SECONDARY)
3. の時点でクライアントクエリーを処理するとセマンティック上の問題が起きるので、プロセス起動前に rs.reconfig()
を行いhiddenノードにしておく必要がある
4.が始まっても原因不明のパフォーマンス劣化状態が続く。1日程度で通常のパフォーマンスになるので3日分程度のOplogは必ず確保する必要がある。
Oplog遅延見積もり
snapshotに掛かる時間(5時間)+(3.)に掛かる時間(24時間)+(4.)開始後24時間で2時間程度しか反映が進まない = 5 + 24 + 24 - 2 = 最大51時間遅延する
手順
SECONDARYが壊れたら?
1. rs.reconfig()
で壊れたノードをhiddenに変更する
2. dailyで取っているバックアップノードのスナップショットからノード再構築
3. rs.reconfig()
で再構築したノードのhiddenを解除する
バックアップノードが壊れたら?
1. rs.reconfig()
で1つのSECONDARYをhiddenに変更する
2. hiddenセカンダリーの捨てスナップショットを2〜3回取る(1回目はフルスナップショット、2回目は長時間のフルスナップショット分の差分、3回目は2回目のスナップショットも本来最短で取れる差分よりは大きい分の差)
3. fsyncLock()
を掛けて本スナップショットを取り完了後にfsyncUnlock()
4.3.のスナップショットからバックアップノード再構築
5.3.で起きた遅延が解消したら、rs.reconfig()
で再構築したノードのhiddenを解除する
ARM環境まとめ
最近のARM(aarch64)周り
この1年で本番環境を全てarm64サーバーに切り替えたりDocker環境を作ったりしてarm64周りのナレッジが溜まってきた。
ハマり続けたメモ。思い出したら追記する
ブチ当たった問題の情報がネットに無い場合も多く、もしかしたらarm64周りを弄ってるエンジニアの中でもカッティングエッジに近い所まで来てるんじゃないかな・・・・
ビジネス環境
勢いがある。時間を先行投資する価値を感じる。
株主不安
SoftbankがARMの競合と目されているNVIDIAへ売却
AWS
Graviton2インスタンスが提供されており、intel CPUインスタンスより2割程安く、HWアクセラレータ周りも充実している
ElasticCache(Redis)
5%程割安で、しかし明らかに2倍くらい速度が遅い。
Redisは1CPUしか使わないので影響が出やすいのと、Speculative_executionの差なのか?
Apple
M1チップ搭載のMacが販売開始
Linux
amd64 / arm64
良く目検に失敗する・・・aarch64に統一してほしい・・・
Ubuntuパッケージ
ミラーサーバーがaarch64をサポートしていない場合がある
原因特定までメチャクチャ時間がかかる
Ubuntu 日本語環境
ubuntu-ja.listが使えない
Docker on Mac
ARM版のLinuxも一応動く
しかしカーネルエミュレータ周りの互換性がイマイチでそこかしこでエラーを吐く
遅い、固有の問題多すぎ。
互換性に問題のあるdockerコンテナなぞ価値なし!
Chrome
Chromeが提供されておらず、Chromiumを使うしかない
Ruby webdrivers
何も考えずx86_64のライブラリを引っ張ってきて起動でコケる
Feature specではOSにインストール済みのChromiumをバイナリを使う
JS karma
環境変数CHROME_BINにインストール済みのChromiumバイナリのパスを指定
JS puppeteer
launchのパラメータexecutablePathにインストール済みのChromiumバイナリのパスを指定
screen
化石エンジニア御用達の仮想コンソール
なぜかアタッチに分単位の時間がかかる
ElasticSearch
docker imageは7.8以降のみ対応
完全対応は7.13以降
大体、2020年6月以前のバージョンは非対応
7.13も起動が異常に遅い問題を確認している
rubyjs/libv8
https://github.com/rubyjs/libv8/issues/261
RailsでJS実行する際に必要だがビルド出来ない問題が2018年から放置
docker使って自前ビルドしたlibv8をvender/cacheに放り込ん動かす