阿里雲IoT流轉到postgresql資料庫方案

波多爾斯基發表於2022-04-22

之前寫過一篇如使用阿里雲上部署.NET 3.1自定義執行時的文章,吐槽一下,雖然現在已經2022年了,但是阿里雲函式計算的支援依然停留在.NET Core 2.1,更新緩慢,由於程式解包大小的限制,也不能放太複雜的東西的上去,雖然現在.NET 6裁剪包能挺好地解決這個問題,但是心裡還是不爽。

需求

言歸正傳,有這麼一個情景:傳送資料想接入阿里雲的IoT平臺,然後直接插入postgresQL資料庫中。正常來說,只要資料傳送到了IoT平臺,然後定義轉發到RDS就可以了,不過阿里雲有幾個限制:

  1. 資料流轉到RDS資料庫,只能支援mysqlsql server
  2. 資料流轉只支援json形式的資料流轉,如果傳送的是透傳的資料,那麼傳送不了(更新:現在新版的資料流轉已經支援了。)

思前想後,可能只能掏出阿里雲的函式計算服務了,運用函式計算作為中轉,將透傳的資料流轉給函式計算,然後在函式計算中執行sql語句。

IoT平臺接收設定

阿里雲的物聯網平臺,設定了基本的產品和裝置之後,如果是物模型的話,那麼自行設定好對應的物模型。對於透傳就比較簡單了,支援MQTT的裝置方只需要定義:

  • 透傳的訊息傳送到/{productKey}/{deviceName}/user/update
  • 訂閱阿里雲的/{productKey}/{deviceName}/user/get
  • 設定阿里雲的Mqtt IoT例項終端節點:({YourProductKey}.iot-as-mqtt.{YourRegionId}.aliyuncs.com:1883
  • 設定裝置的ProductKey和ProductSecret

設定好之後,即可傳輸資料到阿里雲IoT端,資料傳輸過來,看下日誌,如果能看到:

img

那說明就已經傳送OK了,接收到的是普通的字串(不是json),需要進行進一步解析。

IoT流轉設定

雲產品流轉中,新建解析器,設定好資料來源,資料目的選擇函式計算:
img
解析器指令碼比較簡單:

var data = payload(); 
writeFc(1000, data);  

注意,payload函式payload(textEncoding)是內建的函式:

  • 不傳入引數:預設按照UTF-8編碼轉換為字串,即payload()等價於payload('utf-8')。
  • 'json':將payload資料轉換成Map格式變數。如果payload不是JSON格式,則返回異常。
  • 'binary':將payload資料轉換成二進位制變數進行透傳。
    這裡我使用文字透傳的形式,將資料轉成UTF8文字傳輸。writeFc指將轉換的內容傳遞給1000編號的目標函式。詳情見文件

當然還可以使用更為複雜的指令碼,實現對指令碼資料的初步處理,由於我這裡後面還有函式計算,我就直接將資料轉到下一個節點。

函式計算配置

按照官方文件新建函式,請注意不需要新建觸發器!我們這裡的函式使用python語言,通過psycopg2實現資料插入到postgres資料庫中。

由於函式計算中,預設並沒有該包,需要手動新增引用,官方建議使用Serverless Devs工具安裝部署,這個玩意非常不好用,嗯,我不接受他的建議。推薦大家使用vscode,安裝阿里雲serverless的外掛,這樣其實更加方便。

按照外掛的文件,自己建立好服務與函式,預設會給一個函式入口:

# To enable the initializer feature (https://help.aliyun.com/document_detail/158208.html)
# please implement the initializer function as below:
# def initializer(context):
#   logger = logging.getLogger()
#   logger.info('initializing')

def handler(event, context):
  logger = logging.getLogger()
  logger.info(event)
  return 'hello world'

我們首先在函式上右鍵,然後選擇Install Package,選擇pip安裝psycopg2,依賴就自動被安裝上了,這個非常方便。

請注意,通過IOT流轉過來的字串,是b'data'這樣的形式的形式,需要先decode一下,然後在處理,修改函式為:

# -*- coding: utf-8 -*-
import logging
import psycopg2
import uuid
import time

def insert_database(device_id,data):
    timest = int(time.time()*1000)
    guid = str(uuid.uuid1())
    conn = psycopg2.connect(database="", user="", password="", host="", port="")
    cur = conn.cursor()
    sql = 'INSERT INTO "data"("Id","DeviceId","Timestamp", "DataArray") VALUES (\'{id}\', \'{deviceid}\', \'{timestamp}\', array{data})'
    sql = sql.format(id= guid, deviceid= device_id, timestamp= timest, data= data)
    cur.execute(sql)
    conn.commit()
    print(" Records inserted successfully")
    conn.close() 
    
def extract_string_array(data: bytes):
    arr = data.decode().strip().split(' ')
    # 寫自己的邏輯
    return deviceid, resu   

def handler(event, context):
  logger = logging.getLogger()
  logger.info(event)
  device_id, result = extract_string_array(event)
  insert_database(device_id, result)
  return 'OK'

儲存,然後在vscode中deploy即可。

提示:vscode中也可以進行本地的debug,還是比較方便的,不過這些功能依賴docker,所以還是提前裝好比較好。

弄完了之後,應該是能看見這樣的畫面:

img

至此,資料就正常流轉成功。

要點

  1. 不要設定觸發器,當時為了配置這個觸發器弄了非常長的時間
  2. 函式計算與資料庫的VPC應該相同,並且賦予許可權,否則無法訪問。
  3. 函式計算預設無法保持狀態,如果有這個需求,最好試試別的方案,或者看下函式計算的預留例項(常駐例項)
  4. 提前在本地安裝好Docker,要不會有各種各樣的問題出現。
  5. Postgresql插入陣列格式的資料,需要注意格式,可以參考這篇文件
  6. 如果長時間不用docker,導致docker無法啟動,可以參考這篇文章

相關文章