最高のチャーシューがなくても最高のチャーハンを作る

個人的にチャーハンはチャーシューが主役の料理だと考えている。

チャーシューの脂身が高温によって溶け出し米と混ざって奥深い味わいを作り出す。

筆者にとって最高のチャーシューはラーメン/つけ麺屋のチャーシューだ。

しかし中華料理店でチャーハンを頼むとしばしばチャーシューが入っていない、もしくはハムが入っていることに驚く。それでいて奥深い味わいを作り出しているのだ。

これは一体どういう原理なのか。

試行錯誤すること20回以上、ついにチャーシューに頼ることなく店の味に近付くことに成功した。

そのレシピを書き残しておく。

器具

  • 中華鍋
  • コンロのリミッター解除モード

材料

  • 米 0.75合
  • ラード 大さじ2
  • 塩胡椒 1.5g
  • ハイミー 2.5g
  • 醤油 小さじ3/4
  • 酒 大さじ1/2
  • 長ネギ 白い部分 8cm, 緑の部分 4cm
  • ロースハム切り落とし2枚
  • たまご2個

作り方

  1. 米を固めに炊く。象印の炊飯器で言うところのしゃっきり炊き
  2. 長ネギの白い部分の8割くらいをみじん切り。残りの2割を輪切り。緑の部分すべてを輪切り(ここまでこだわる必要はなさそうだが美味しくできたときにこうしたのでそのまま書いている)
  3. ハムを米のサイズと同じぐらいにみじん切り
  4. すばやく投入できるように準備
    1. 塩胡椒とハイミーを混ぜて一つの皿に用意
    2. 醤油と酒を混ぜて一つの皿に用意
  5. 卵は混ぜずに割ったままの状態で準備
  6. 炊いた米を茶碗に移しておく
  7. 中華鍋にサラダ油を馴染ませ、馴染んだらラードを投入。最大火力にし、十分に温まるまで待つ
  8. 卵を投入。卵焼きを作るイメージで焼く白身が焦げ、黄身が生のままの状態になるまで焼く
  9. 黄身に向かって米を投入
  10. 米全体に黄身が行き渡るまで混ぜる
  11. 一旦弱火にする
  12. 塩胡椒とハイミーを投入して最大火力で全体に馴染むようにサッと混ぜる
  13. 一旦弱火にする
  14. ハムとネギを投入して最大火力でネギを焼くように混ぜる
  15. 一旦弱火にする
  16. 鍋肌を伝うように醤油と酒をかける
  17. 最大火力で全体が馴染むようにサッと混ぜる
  18. 完成!

ポイント

卵を混ぜてから焼くのではなく、白身を焦がすまで焼くようにしているのが最大のポイント。

これによって白身の香ばしさが出て全体に奥深さを与えてくれる。

中華料理店で出てくるチャーシューなしチャーハンの奥深さは実は白身の香ばしさなんじゃないかと思っている。

Datastreamのバックフィルを高速化する

データソースとBigQueryのレプリケーションサービスであるDatastreamのバックフィル(初期化処理)を高速化する手法を紹介する。前提としてデータソースにはAurora MySQLを利用している。

cloud.google.com

Datastreamのバックフィルには2種類ある。

  1. インクリメンタル
  2. フルダンプ

テーブルにプライマリキーがある場合にはインクリメンタルに、ない場合はフルダンプが使われると思われる(ドキュメントには明記されていない)。

インクリメンタルとは次のようなクエリを繰り返すことでちょっとずつBigQueryに連携していくということ。

select * from table
where id > ?
order by id asc
limit ?

これは巨大なテーブルのバックフィルには時間がかかることを示唆している。

実際に実験してみたところ2つの事実がわかった。

  1. インクリメンタルなバックフィルでは約800万レコード/時のペースで連携される
  2. Datastreamのバックフィルタスク数を増やしても巨大なテーブルの連携は高速にならない

事実2に対してもう少し詳しく説明する。

Datastreamにはバックフィルのタスク数を1~50の間で制御することができる。

cloud.google.com

このタスクは1タスク1テーブルを処理しているのか、タスク数を増やしても1テーブル当たりの処理時間は変わらなかった。 つまり、バックフィルの完了は一番大きいテーブルで律速するということ。

今回の要件では約20億レコードあるテーブルをDatastreamで連携する必要があったため、単純計算で10日(実験してみたところ本当に10日かかった)かかることになり高速化が求められた。

そこでDatastreamのバックフィルを使わずに、Auroraのクラスタースナップショットを利用してスナップショットのParquetファイルをBigQueryにロードすることでバックフィルを高速化した。

Auroraのクラスタースナップショットを利用しつつDatastreamのバックフィルと同等のことをするにはどうすればよいかを説明する。

Datastreamはバックフィル中に発生する変更をCDCによってキャプチャしている。 そのため、バックフィルが完了すれば滑らかに最新の変更に追従できるようになっている。

Auroraのクラスタースナップショットを利用するときにもこの動きを再現する必要がある。

これはDatastreamの、binlogの位置を指定してストリームを再開するAPIを利用することで実現できる。

リリースノートによると2023/11/9から利用できるようになっている。

cloud.google.com

以上からAuroraのクラスタースナップショットによる高速化の手順は次の通り。

  1. データベース上で show master status してbinlogの位置を記録する
  2. AuroraのクラスタースナップショットをParquet形式でS3にエクスポートする
  3. CloudStorageにStorage Transfer Serviceを使うなどしてParquetをコピーする
  4. Datastreamのストリームを一時停止する
  5. Parquetを bq load する
  6. 1で記録しておいたbinlogの位置を指定してストリームを再開する

ただし注意点が2つある。

まず、手順5ではParquetによって作られるカラムの型とDatastreamによって作られるカラムの型が不一致になるケースを考慮する必要がある。

例えば、MySQLDATETIME 型はParquetでは TIMESTAMP 型になり、Datastreamでは DATETIME 型となる。

不一致になる場合はDatastreamの型に合わせる必要があるので明示的に DATETIME 型を指定する必要がある。

次に、手順6ではCDCによってスナップショットに含まれる変更が再度実行される可能性を考慮する必要がある。つまり冪等である必要がある。

Datastreamではデータベースのテーブルにプライマリキーがある場合は冪等であるが、ない場合は冪等ではなく重複するレコードが作られる。

詳しくは以下の記事を参照してほしい。

zenn.dev

以上の取り組みの結果として、約20億レコードあるテーブルのバックフィルに10日かかっていたのが16時間ほどで終わるようになり時間とお金を節約できた。

内訳はスナップショットの作成に16時間 + Storage Transfer Serviceによるコピーに5分 + Parquetの bq load に10分なのでほとんどスナップショットの作成待ち。

2023/11に出たbinlogの位置指定によってDatastreamの柔軟性が大幅に上がっていると思うので広めていきたい。

コロナになった

4回目のワクチンから6ヶ月たったし5回目のワクチン受けるかー、あれ接種対象者じゃないから受けれないのか、と言っているうちにコロナになってしまった。

発症当日は喉の痛みだけで発症したことに気付いていなかった。 その日は一日中会話していたのでその会話によって喉を痛めたのだと思いこんでいた。

コロナは本当につらく、寝ようとしても39.5度近くの高熱のせいか「1つのことを無限に考えさせられる状態」に陥って寝れないときが一番つらかった。 このとき自分は何故かサッカーのイングランド代表のことしか考えられなかった。

さらに喉の痛みも普通の風邪とは比にならない痛みで、つばを飲み込むだけでも痛かった。喉は痛いけど薬は飲まないといけないしで地獄だった。

体温と体調(10段階)を記録していたのでグラフにすると次のようになった。

体温と体調の時間変化

まだ味覚、嗅覚が1~2割しかない状態なのと働きすぎると後遺症が発生しうるらしい(ググった情報)のでしばらくはゆったりと暮らしたい。