Upgrade to Pro — share decks privately, control downloads, hide ads and more …

多様なプロトコルと 駆動モデルをサポートするIoTゲートウェイの開発と運用の知見

多様なプロトコルと 駆動モデルをサポートするIoTゲートウェイの開発と運用の知見

Go Conference 2023, "Go"ld Sponsor Session
https://gocon.jp/2023/sessions/A5-SP/

Takeshi Shinoda

June 02, 2023
Tweet

More Decks by Takeshi Shinoda

Other Decks in Programming

Transcript

  1. ©2023 MODE, Inc.

    多様なプロトコルと

    駆動モデルをサポートする

    IoTゲートウェイの開発と運用の知見

    Takeshi Shinoda 2023-06-02


    View Slide

  2. ©2023 MODE, Inc.

    ● MODE, Inc.に勤務

    ● テックリード・エンジニア

    ● 2018年9月よりMODE社

    ● Go歴はMODE歴と同じ約4年と10ヶ月

    ● 組み込み関数では len() が好き

    ● https://twitter.com/takeshinoda

    篠田 健 (しのだ たけし)


    View Slide

  3. ©2023 MODE, Inc.

    会社概要

    社名
 MODE, Inc.

    設立
 2014年創業

    (2017年日本オフィス開設)

    事業内容
 統合 IoT ソリューションの企画・ 

    開発・運営

    創立者
 Gaku Ueda / Ethan Kan

    所在地
 サンフランシスコ / 東京


    View Slide

  4. ©2023 MODE, Inc.

    AGENDA

    1. MODE社における汎用IoTゲートウェイの働く現場

    2. 当初のIoTゲートウェイの実装パターンと問題

    3. Goroutine を中心としたモジュールの設計

    4. まとめ


    View Slide

  5. ©2023 MODE, Inc.

    01

    MODE社における汎用IoTゲートウェイの働く現場


    View Slide

  6. ©2023 MODE, Inc.

    IoTゲートウェイのはたらく場所

    現場
    クラウド


    View Slide

  7. ©2023 MODE, Inc.

    IoTゲートウェイのはたらく場所

    現場
    クラウド

    こっち

    View Slide

  8. ©2023 MODE, Inc.

    現場ではたらくコンピュータ

    ● 過酷な環境で動くこともある。

    ○ トンネルの中。

    ○ エンジンを切ると電源が落ちる自動車。

    ○ 工事現場の重機の中。

    ○ 電波の悪い工場の中。

    ● H/Wは現場の物理環境に合わせて異なる。

    ○ ユーザーが稼働させているロボットの中。

    ○ IntelもあればArmもある。

    ● 遠くにあるので基本的にネットの切れ目が縁の切れ目。

    ○ LTEとかの接続で何かの不都合で復旧しない場合手動で直す。

    ○ 最悪山奥のトンネルにある。


    View Slide

  9. ©2023 MODE, Inc.

    IoTゲートウェイは現場で何をしているの

    BLE

    EnOcean

    Twilite

    Serial

    TCP/UDP

    OBD-II

    BACNet

    NMEA Sentence

    CSV/JSON

    etc…

    各種センサー

    工場・生産設備

    建設現場

    重機

    輸送車両

    倉庫

    ロボット

    エンタメ演出

    etc…

    MQTT

    Gateway!
    MODE Cloud


    View Slide

  10. ©2023 MODE, Inc.

    ソフトウェアとしての動作環境の特徴

    ● 動的なスケールアウト・アップはできない。

    ● インターネットへの接続が必ずしも安定しない。

    ○ 太い回線であることも期待できない。

    ● IoTゲートウェイと接続する機器のプロトコルと動作モデルは機器による。

    ○ 単純なセンサーは一方的にデータを送信してくる。

    ○ データを要求してデータを非同期に返すプロトコル。

    ○ ペアリングが必要なパターンもある。

    ○ データを要求してその後消すオペレーションなど。

    ○ CIFSなどを通じた単なるファイル連携もある。

    ● エラーがあっても止めず、常に最後の遠隔操作手段は残したい。

    ● Go製アプリケーションをLinuxの上で動かせるくらいはリッチ。


    View Slide

  11. ©2023 MODE, Inc.

    02

    当初のIoTゲートウェイの実装パターンと問題


    View Slide

  12. ©2023 MODE, Inc.

    機器との通信

    ←データ送信

    機器設定→

    各機器のハンドリング 

    色んな働きをする
    Goroutine
    いっぱい!
    不定期にデータは
    来るしクラウドから
    指示が来る💦
    go func() {
    for {
    read()
    write()
    }
    }()
    go func() {
    for {
    read()
    write()
    }
    }()

    View Slide

  13. ©2023 MODE, Inc.

    各制御機器のモジュール内のデータ保護

    go func() {
    for {
    read()
    write()
    }
    }()
    ● 不定期にデータは機器からゲートウェイに上がる。 

    ● 不定期にクラウドから設定変更などの割込み処理がゲートウェイでは発生する。 

    ● 各対応機器のモジュール内のデータ保護の為の Mutexロックなどが煩雑になりがち。 

    main(){}
    モジュール

    View Slide

  14. ©2023 MODE, Inc.

    各種機器を制御するモジュールのGoroutine

    func (d *Device) Start() {
    go func() {
    for {
    select {
    case fn := <-d.message:
    fn()
    case data := <- d.inputCh:
    d.upstream <- data
    case <- d.doneCh:
    return
    }
    }
    }()
    }
    各機器は常にひとつ以上の専用Goroutineで制御

    1. コードがどのGoroutineで動くかがモジュールの開発
    者が把握しやすい

    2. 機器の駆動モデルに合わせた開発がしやすい

    3. ハンドリングの為の割り込みを制御しやすい

    func (d *Device) ChangeInterval()) {
    d.message <- func() { /* Do something */ }
    }

    View Slide

  15. ©2023 MODE, Inc.

    初期の頃のIoTゲートウェイ内のGoroutineヒエラルキー

    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    MQTT
 MQTT

    通信制御

    ● センサーGoroutineハンド
    リング

    ● データ収集・変換

    ● 制御指示

    Channel

    Channel

    Channel

    ● 各Goroutine間はChannelを通じてデータと指示を伝搬。 

    ● それぞれのモジュールはひとつ以上の Goroutineが独自に動いており、
    制御対象の機器実行モデルは Goroutine内で閉じていたため、上流のハ
    ンドリングモジュールは起動と停止とクラウドからの指示を伝搬することだ
    けを気にすることができた。 

    Channel

    ホントはも
    少し多段

    View Slide

  16. ©2023 MODE, Inc.

    一度Channelが詰まると全部詰まる

    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    go func() {
    for { ... }
    }()
    Channel

    Channel

    ● 多様な現場で多様な用途に使われるので、様々な要因でラ
    ンダムに詰まりがち

    ○ データのアップロードが単に追いつかない 

    ○ センサーをぶら下げすぎる 

    ○ 不定期なクラウドからの指示が何故か秘孔を突く 

    ○ どこかの考慮不足のコード 

    upstreamCh <- data
 みんなここで止まる


    View Slide

  17. ©2023 MODE, Inc.

    これを全モジュールのデータ伝搬に入れてしのぐのも限界がある

    select {
    case upstreamCh <- data:
    default:
    // error logging, buffering
    }

    ● そもそも大事なデータが抜け落ちる。 

    ● defaultに入るような状態になって自動的に回復することもあまり期待できない。 

    ● あちこちにこれがあるのは何かがおかしい。 

    ● コードには upstream 方向と downstream 方向のデータの流れも、それらを考慮すると詰ま
    り要因を全部洗い出したり考慮をしていると開発が立ちゆかない懸念。 

    ×


    View Slide

  18. ©2023 MODE, Inc.

    03

    Goroutine を中心としたモジュールの設計


    View Slide

  19. ©2023 MODE, Inc.

    問題の整理と設計の方針の整理

    問題の整理

    IoTゲートウェイの動作環境はユーザーにより多様なため様々なデータの流通パターンがあり、ランダ
    ムにChannel詰まりの不具合を掴みやすい。

    方針の整理

    Option1: Channelによるデータ伝搬をやめる

    対応機器の駆動モデルを事前に予測できないので Goroutine単位のモジュール開発パターンを取れない
    のはつらい

    Option2: チャンネルによる連結はやめずにモジュールの独立性を高める ← 方針はこちらで

    モジュール外の出来事に気を配るような開発は様々な現場と機器に対応するため無理がある 


    View Slide

  20. ©2023 MODE, Inc.

    channel

    goroutine

    構造を次のように変える

    前
 後


    View Slide

  21. ©2023 MODE, Inc.

    突然ですが Scratch を参考にしてみる

    Mouse
    Click!!

    View Slide

  22. ©2023 MODE, Inc.

    各スプライトは他スプライトのことをしらない

    - 各スプライトはそれぞれスレッドを持ち、自分へのイベント (この場合メッセージの受信 )に基づいて各
    自独自に振る舞う。

    - これでもかなり複雑なゲームを作れる。 


    View Slide

  23. ©2023 MODE, Inc.

    イベント受信に基づいたモジュール設計

    1. イベントの送受信だけを結節点にするモジュール設計。

    2. Goroutine の良いところは軽量にしかもChannelにより簡単に動作を制御できるところにあ
    る。

    3. 各モジュールの独立性を高める
    Scratchの設計は、GoroutineとChannelの特性とかなりマッ
    チして参考にできる。

    a. 独立性を高める:

    i. 他のモジュールの動作次第で全部詰まることを考えない 

    ii. 別のモジュールの設計に依存しない (気にせず開発できる )

    iii. 処理対象機器の動作モデルに全体設計が引きずられない 

    4. 最初の実装は実行そのものを関数として
    Goroutineに渡していたがやりすぎだった

    a. テストがやりにくい

    b. 引数に柔軟性がない (ぜんぶクロージャとして渡す )

    c. ふつうの開発モデルから逸脱している 


    View Slide

  24. ©2023 MODE, Inc.

    イベントを受け取りイベントを送出するのがモジュール

    Channel Filter Module Channel
    ● モジュールはイベントを受け取り、イベントの内容に基づき独自に処理をする。 

    機器から受信したデータや 

    自分の状態を知らせるイベントの発行 

    受信データの加工

    特定条件データのドロップ 

    などの前処理


    View Slide

  25. ©2023 MODE, Inc.

    イベントの種類は基本的に固定

    ● IoTゲートウェイという用途限定のユースケースと割切り、自由なイベントは作れない。

    ● 自由にすると関数を実行させる最初のモデルに近くなるし、他のモジュールの仕様を知る必要が
    出てくる。

    const (
    DiscoveredModuleType EventType = "discoveredModule"
    UnregisterKernelModuleType EventType = "unregisterKernelModule"
    KernelType EventType = "kernel"
    MeasuredType EventType = "measured"
    LargeDataType EventType = "largeData"
    ModeEventType EventType = "modeEvent"
    ModeCommandType EventType = "modeCommand"
    ModeKVNotifyType EventType = "modeKVNotify"
    < ...省略... >
    NotificationType EventType = "notification"
    BroadcastNotificationType EventType = "broadcastNotification"
    )

    View Slide

  26. ©2023 MODE, Inc.

    基本的にはEventはブロードキャストされる

    Core
    Module
    MQTT
    Module
    CO2 Sensor
    Module
    Thermometer
    Module
    Event Router
    Channel
    Channel
    ● すべてのイベントはEvent Routerに投げられる。

    ● MeasuredEvent が欲しいとインターフェース定義を満たせばそのす
    べてのモジュールに伝搬される。 

    type MeasuredEventReceivable interface {
    MeasuredEventCh() chan<- MeasuredEvent
    }
    温度測ったから
    MeasuredEvent送った
    よ!あとは知らないよ!
    測定値が欲しいよ!必要
    だったらこっちで判断して
    クラウドに送るね!

    View Slide

  27. ©2023 MODE, Inc.

    基本的にはEventはブロードキャストされる

    Core
    Module
    MQTT
    Module
    CO2 Sensor
    Module
    UdevEvent
    Module
    Event Router
    Channel Channel
    新しいデバイスが見つかっ
    たよ!
    もしかして自分のかもしれ
    ないからデバイス系のイベ
    ント全部拾うよ!

    View Slide

  28. ©2023 MODE, Inc.

    新しい設計でのモジュールのGoroutineの雰囲気

    func (m *DriverModule) Start() error {
    if err := m.initializeDevice(); err != nil {...}
    go func() {
    select {
    case event := <- m.eventReceiverCh:
    m.doSomethingBy(event)
    case data := <- m.deviceMeasuredCh:
    m.sendCh <- parseData(data)
    case <- m.doneCh:
    // Do something to stop the process gracefully
    return
    }
    }()
    }

    View Slide

  29. ©2023 MODE, Inc.

    別Goroutineから呼び出されうるポイントを限定

    ● これを満たすとモジュールとして動作できる。

    ● この関数以外から知らないGoroutineの呼び出しはない。

    type Module interface {
    Start(Configs) error
    Stop(context.Context) error
    Status() ModuleStatus
    }

    View Slide

  30. ©2023 MODE, Inc.

    結局 EventRouter で詰まるのでは?

    Core
    Module
    MQTT
    Module
    CO2 Sensor
    Module
    TooBusySensor
    Module
    Event Router
    Channel
    Channel
    ● 少なくとも詰まりポイントは EventRouterだけ見ればいいのでランダム
    に詰まられるよりはよい。

    ● バッファリングでできるだけ突発的・各現場での様々なデータ流量に対
    応できるようにはしている。

    ● 転送先がBusyの時は捨てる。

    ○ 各モジュールは用途的にたくさんデータが来ると予想されるならそれなり
    の実装にするという期待を前提とする。 


    View Slide

  31. ©2023 MODE, Inc.

    04

    まとめ


    View Slide

  32. ©2023 MODE, Inc.

    まとめ

    ● GoroutineとChannelの良いところを組み合わせれば、独立性の高いモジュール機
    構を採用しても難しくなく実装できる。

    ● 分散システムとかでは無く、単体プロセスで頑張るソフトウェアの場合、Channelのパ
    イプラインは考えがちだが詰まりポイントを見つけにくいので要注意。


    View Slide

  33. ©2023 MODE, Inc.

    05

    さいごに…


    View Slide

  34. ©2023 MODE, Inc.

    We are hiring!


    View Slide

  35. ©2023 MODE, Inc.

    We are hiring!

    MODE社ではエンジニアを広く募集しております!!

    ● IoTエッジサイドのシステムプログラミングを楽しみたい。

    ● IoTプラットフォームのクラウドシステムをビシバシ作りたい方。

    ● サンフランシスコと東京オフィスの
    2拠点でグローバルな開発を体験できます。

    ● 基本的にはリモートワークです。
    IoTなので現場に出ることはあります。

    このあと13:30-14:00まで、ベイエリア在住のCEO (日本語でも英語でも可) が企業ブースでお待
    ちしておりますのでお話ししてみてください!

    上記以外の時間帯にも弊社エンジニアと
    HR担当がお待ちいたしております!

    View Slide

  36. ©2023 MODE, Inc.

    ありがとうございました!!


    View Slide