1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ESP32 × Azure Functions!gRPC (Protobuf) vs JSON 通信比較検証(クラウド連携)

Posted at

前回の記事では、Nanopbを使ってESP-IDFのビルドシステムにgRPCを統合し、ローカル環境での疎通を確認しました。
前回:ESP32でgRPC(Protobuf)通信!Nanopbを使って爆速・軽量な自動ビルド環境を構築する(ローカル疎通)

今回は、舞台をクラウドへ移します。エンドポイントを Azure Functions に構築し、モダンな JSON通信gRPCバイナリ通信 を実環境でぶつけ、そのパフォーマンスを徹底比較します。

理論的背景の解説はこちら
実装に入る前に、gRPCの仕組みやJSONとの比較を詳しく知りたい方は、以下の概念図解記事を併せてご覧ください。
マイコン開発の新常識?ESP32でgRPCを動かすための「理論のハブ」

1. 比較検証のシステム構成

今回の検証環境の全体像です。ESP32からインターネット経由でAzureへデータを飛ばします。

Azure Functions側の実装(Python)

Azure側も uv を活用してモダンな環境を構築します。第1回で作成した定義ファイルから生成された sensor_pb2.py をデプロイ先に配置し、リクエストの req.get_body() からバイナリデータを直接パースします。

function_app.py
import azure.functions as func
import logging
import sensor_pb2

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)

# --- 1. JSON用エンドポイント(比較用) ---
@app.route(route="esp_data_json")
def http_trigger_json(req: func.HttpRequest) -> func.HttpResponse:
    try:
        req_body = req.get_json()
        logging.info(f"[JSON] Received: {req_body}")
        return func.HttpResponse(f"JSON Success", status_code=200)
    except ValueError:
        return func.HttpResponse("Invalid JSON", status_code=400)

# --- 2. gRPC (Protobuf) 用エンドポイント(本命) ---
@app.route(route="esp_data_grpc")
def http_trigger_grpc(req: func.HttpRequest) -> func.HttpResponse:
    try:
        # HTTPボディから生のバイナリ(bytes)を直接取得
        body = req.get_body()
        
        # Protobufとしてデコード
        sensor_msg = sensor_pb2.SensorData()
        sensor_msg.ParseFromString(body)

        logging.info(f"[gRPC] Decoded: {sensor_msg.device_id}, Temp: {sensor_msg.temperature}")
        return func.HttpResponse(f"gRPC Success: {len(body)} bytes", status_code=200)
    except Exception as e:
        logging.error(f"Decode Error: {e}")
        return func.HttpResponse(f"Decode Failed", status_code=500)

2. ESP32側の実装:比較用ループ

ESP32-S3上で、同じ内容のデータをJSON形式とProtobuf形式で交互にHTTPS POST送信するループを実装しました。シリアライズにかかる純粋な処理時間を esp_timer_get_time() で計測し、その「軽さ」を可視化します。

main.c (抜粋)
// --- JSONシリアライズ ---
int64_t j_start = esp_timer_get_time();
int j_len = snprintf(json_data, sizeof(json_data), 
                     "{\"device_id\":\"ESP32-S3-LAB\",\"temperature\":%.2f,\"humidity\":%d}", temp, hum);
int64_t j_end = esp_timer_get_time();
ESP_LOGI(TAG, "[JSON] Serialize Time: %lld us", (j_end - j_start));

// --- gRPC (Protobuf) シリアライズ ---
int64_t p_start = esp_timer_get_time();
pb_ostream_t stream = pb_ostream_from_buffer(pb_buffer, sizeof(pb_buffer));
if (pb_encode(&stream, SensorData_fields, &msg)) {
    int64_t p_end = esp_timer_get_time();
    ESP_LOGI(TAG, "[gRPC] Serialize Time: %lld us", (p_end - p_start));
}

3. 【実測結果】gRPC vs JSON 徹底比較

Azure Functions(HTTPS環境)へ送信した際のログから得られた、平均的な実測データです。

項目 JSON通信 gRPC (Nanopb) 改善率
シリアライズ時間 約424 μs 約157 μs 2.7倍高速
ペイロードサイズ 62 bytes 21 bytes 約1/3に凝縮
ネットワーク通信時間 約1.3 sec 約1.3 sec 差なし

【考察】ネットワークタイムが変わらない「巨象」の正体

実測の結果、トータルの通信時間はどちらも約1.3秒前後でほぼ差が出ませんでした。
これは、通信時間の大部分を TLSハンドシェイク(HTTPSの暗号化確立) が占めているためです。
image.png

現代のインターネット環境において、21バイトと62バイトというデータの差は、TLSハンドシェイクという「巨象」の前では誤差に埋もれてしまうのが現実です。

4. なぜ「トータルタイムが変わらなくても」gRPCを選ぶのか

数値だけ見ると「JSONでいいのでは?」と思われがちですが、マイコン開発という制約の多い環境では、数値以上に重要な3つのメリットがあります。

① CPU稼働時間の削減(省電力化の鍵)

シリアライズ時間はgRPCが 約2.7倍も高速 です。
1回あたりの差はわずかですが、数万回の送信を繰り返すバッテリー駆動デバイスにおいて、CPUが「フルパワー」で動く時間を削れることは、Deep Sleepへの移行を早め、稼働寿命の延長に直結します。

② ペイロードサイズ 1/3 のメリット

  • 回線コスト: LTE-MやNB-IoTのような従量課金回線では、この数バイトの差が累積コストに効きます。
  • 成功率: パケットが小さいほど、電波強度が弱い場所での送信成功率(パケットロス耐性)が向上します。

③ 型安全という「開発効率」

JSONのような文字列パースではなく、設計図(.proto)から生成された構造体に値を流し込むだけで通信が完結します。サーバーとクライアントで共通の定義を使うため、「型違いによるランタイムエラー」をコンパイル段階で防げる堅牢性は、IoT開発において大きな武器になります。

5. 遭遇した技術的課題:Stack Overflow

検証中、A stack overflow in task main has been detected というクラッシュに頻繁に遭遇しました。

原因:
HTTPS通信(TLS)は内部で巨大なバッファ(Mbed TLSの送受信バッファなど)を消費します。app_main のデフォルトスタックサイズ(通常4KB程度)では、この巨大な「器」を支えきれません。

対策:
sdkconfig にて、メインタスクのスタックサイズを 8192以上(今回は安全を見て16KBを推奨) に拡張することで安定稼働しました。gRPC自体のメモリ消費が少ない分、通信レイヤーにリソースを割く余裕を作ることが重要です。

6. まとめ

Azure Functionsとの比較により、「速度(トータルタイム)そのものはHTTPSのオーバーヘッドに支配される」 という不都合な実態が明らかになりました。

しかし、「CPU負荷の低減」と「パケットの極小化」 においてgRPC(Nanopb)が圧倒的に有利であることも同時に証明されました。リソースが限られたエッジデバイスと、パワフルなクラウドを繋ぐ「接合点」として、gRPCは非常に洗練された選択肢と言えます。

📦 ソースコード

比較検証に使用したESP32側のコードと、Azure Functionsのプロジェクトを公開しています。
GitHub: esp32-grpc-vs-json-azure

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?