OpenResty XRay がどのようにしてアプリケーションの問題特定と効率化を支援するかをご覧ください。

詳細はこちら LIVE DEMO

このチュートリアルでは、OpenResty におけるユーザー Lua コードのベンチマークの正しい方法と誤った方法を説明します。

cd ~
mkdir time-lua
cd time-lua/

まず、CPU が常にフル稼働状態であることを確認する必要があります。

echo performance | sudo tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

截图 2

通常、デフォルト値は powersave ですが、performance に設定する必要があります。

Lua コードの時間を測定する最も簡単な方法は、time コマンドと resty コマンドを使用することです。

time resty -e 'ngx.re.find("hello, world.", [[\w+\.]], "jo")'

截图 4

しかし、この方法には問題があります。resty コマンド自体に起動と終了のオーバーヘッドがあります。

time resty -e ''

截图 6

このマシンでは、そのオーバーヘッドが約 11 ミリ秒であることがわかります。

代わりに、OpenResty が提供する ngx.now Lua API 関数を使用すべきです。

restydoc -s ngx.now

截图 8

Lua コードを ./bench.lua というファイルに入れて、より読みやすくしましょう。

以下の編集を行います:

  1. まず、nginx 内のキャッシュ時間が最新であることを確認します。
  2. 次に、ミリ秒の精度で開始時間を記録します。
  3. その後、前述の正規表現マッチング呼び出しを行います。
  4. そして、再度キャッシュ時間を更新します。
  5. 最後に、時間の差分を計算して経過時間を出力します。
  6. ファイルを保存しましょう。
ngx.update_time()
local begin = ngx.now()
ngx.re.find("hello, world.", [[\w+\.]], "jo")
ngx.update_time()
ngx.say("elapsed seconds: ", ngx.now() - begin)

截图 15

次に、resty シェルコマンドを実行します。

resty bench.lua

截图 18

記録された遅延時間は約 1 ミリ秒です。しかし、これが非常に不正確であることがすぐにわかります。

正しい方法は、bench.lua ファイルを以下のように編集することです:

  1. 呼び出しを target という名前の Lua 関数に入れます。
  2. その後、この関数を 100 回呼び出してウォームアップします。これで target 関数はこのループ実行後に JIT コンパイルされるはずです。
  3. 次に、タイミング計測部分で、1000 万回繰り返し呼び出します。
  4. 最後に平均時間を計算します。
local function target()
    ngx.re.find("hello, world.", [[\w+\.]], "jo")
end

for i = 1, 100 do
    target()
end

ngx.update_time()
local begin = ngx.now()

local N = 1e7
for i = 1, N do
    target()
end

ngx.update_time()
ngx.say("elapsed: ", (ngx.now() - begin) / N)

截图 25

このスクリプトを再度実行してみましょう。

resty bench.lua

截图 26

各呼び出しにかかる時間が約 30 ナノ秒程度であることがわかります。以前の結果よりもはるかに高速です!

実際、コードの時間を測定する前に、まだ回収されていない死んだ GC オブジェクトがないことを確認するために、最初の ngx.update_time() 呼び出しの前に以下の行を挿入することができます。

collectgarbage()

截图 29

ここでは、開始時間を記録する前に完全な GC サイクルを強制的に実行します。

ただし、この例ではあまり役に立ちません。これは、タイミング計測対象のコードが多くの GC オブジェクトを作成しないためです。

不要な Lua テーブル検索操作を避けることで、target 関数をさらに高速化することができます。

local re_find = ngx.re.find

local function target()
    re_find("hello, world.", [[\w+\.]], "jo")
end

截图 33

しかし、ここでの違いは小さいかもしれません。

截图 35

以上が本日お伝えしたい内容です。興味深く感じていただければ幸いです。

著者について

章亦春(Zhang Yichun)は、オープンソースの OpenResty® プロジェクトの創始者であり、OpenResty Inc. の CEO および創業者です。

章亦春(GitHub ID: agentzh)は中国江蘇省生まれで、現在は米国ベイエリアに在住しております。彼は中国における初期のオープンソース技術と文化の提唱者およびリーダーの一人であり、Cloudflare、Yahoo!、Alibaba など、国際的に有名なハイテク企業に勤務した経験があります。「エッジコンピューティング」、「動的トレーシング」、「機械プログラミング」 の先駆者であり、22 年以上のプログラミング経験と 16 年以上のオープンソース経験を持っております。世界中で 4000 万以上のドメイン名を持つユーザーを抱えるオープンソースプロジェクトのリーダーとして、彼は OpenResty® オープンソースプロジェクトをベースに、米国シリコンバレーの中心部にハイテク企業 OpenResty Inc. を設立いたしました。同社の主力製品である OpenResty XRay動的トレーシング技術を利用した非侵襲的な障害分析および排除ツール)と OpenResty XRay(マイクロサービスおよび分散トラフィックに最適化された多機能ゲートウェイソフトウェア)は、世界中の多くの上場企業および大企業から高い評価を得ております。OpenResty 以外にも、章亦春は Linux カーネル、Nginx、LuaJITGDBSystemTapLLVM、Perl など、複数のオープンソースプロジェクトに累計 100 万行以上のコードを寄与し、60 以上のオープンソースソフトウェアライブラリを執筆しております。

翻訳

英語版の原文と日本語訳版(本文)をご用意しております。読者の皆様による他の言語への翻訳版も歓迎いたします。全文翻訳で省略がなければ、採用を検討させていただきます。心より感謝申し上げます!