儲存位置數據
手繪圖由 Nitya Narasimhan 提供。點擊圖片查看大圖。
課前測驗
簡介
在上一課中,你學會了如何使用 GPS 感測器來捕捉位置數據。要使用這些數據來可視化載滿食物的卡車的位置及其行程,需要將其發送到雲端的 IoT 服務,然後存儲在某處。
在本課中,你將學習不同的 IoT 數據存儲方式,並學習如何使用無伺服器代碼來存儲來自 IoT 服務的數據。
在本課中,我們將涵蓋:
結構化和非結構化數據
計算機系統處理數據,而這些數據有各種不同的形狀和大小。它可以從單個數字到大量文本、視頻和圖像,再到 IoT 數據。數據通常可以分為兩類 - 結構化 數據和 非結構化 數據。
-
結構化數據 是具有明確定義的、固定結構的數據,通常映射到具有關係的數據表。 一個例子是個人的詳細信息,包括姓名、出生日期和地址。
-
非結構化數據 是沒有明確定義的、固定結構的數據,包括結構經常變化的數據。一個例子是文檔,如書面文檔或電子表格。
✅ 做一些研究:你能想到其他一些結構化和非結構化數據的例子嗎?
💁 還有半結構化數據,它是結構化的,但不適合固定的數據表
IoT 數據通常被認為是非結構化數據。
想像一下,你正在為一家大型商業農場的車隊添加 IoT 設備。你可能希望為不同類型的車輛使用不同的設備。例如:
- 對於農用車輛,如拖拉機,你希望獲取 GPS 數據以確保它們在正確的田地上工作
- 對於運送食物到倉庫的送貨卡車,你希望獲取 GPS 數據以及速度和加速度數據,以確保司機安全駕駛,並獲取駕駛身份和啟動/停止數據,以確保駕駛符合當地的工作時間法律
- 對於冷藏卡車,你還希望獲取溫度數據,以確保食物在運輸過程中不會過熱或過冷而變質
這些數據可以不斷變化。例如,如果 IoT 設備在卡車駕駛室中,那麼它發送的數據可能會隨著拖車的變化而變化,例如僅在使用冷藏拖車時發送溫度數據。
✅ 可能還會捕捉到哪些其他 IoT 數據?考慮卡車可以運載的各種貨物以及維護數據。
這些數據因車輛而異,但它們都被發送到同一個 IoT 服務進行處理。IoT 服務需要能夠處理這些非結構化數據,並以允許搜索或分析的方式存儲它,但需要處理這些數據的不同結構。
SQL 與 NoSQL 存儲
數據庫是允許你存儲和查詢數據的服務。數據庫有兩種類型 - SQL 和 NoSQL
SQL 數據庫
最早的數據庫是關係數據庫管理系統 (RDBMS),或關係數據庫。這些數據庫也被稱為 SQL 數據庫,因為它們使用結構化查詢語言 (SQL) 與它們進行交互以添加、刪除、更新或查詢數據。這些數據庫由一個模式組成 - 一組明確定義的數據表,類似於電子表格。每個表有多個命名列。當你插入數據時,你會向表中添加一行,將值放入每個列中。這使得數據保持非常嚴格的結構 - 雖然你可以留空列,但如果你想添加新列,必須在數據庫上執行此操作,並為現有行填充值。這些數據庫是關聯的 - 一個表可以與另一個表有關係。
例如,如果你在一個表中存儲用戶的個人詳細信息,你會為每個用戶設置某種內部唯一 ID,該 ID 用於包含用戶姓名和地址的表中的一行。如果你想在另一個表中存儲該用戶的其他詳細信息,例如他們的購買記錄,你會在新表中為該用戶的 ID 設置一列。當你查找用戶時,可以使用他們的 ID 從一個表中獲取他們的個人詳細信息,從另一個表中獲取他們的購買記錄。
SQL 數據庫非常適合存儲結構化數據,並且當你想確保數據符合你的模式時非常有用。
✅ 如果你以前沒有使用過 SQL,請花點時間在 Wikipedia 的 SQL 頁面 上閱讀相關內容。
一些知名的 SQL 數據庫包括 Microsoft SQL Server、MySQL 和 PostgreSQL。
✅ 做一些研究:閱讀一些這些 SQL 數據庫及其功能。
NoSQL 數據庫
NoSQL 數據庫之所以被稱為 NoSQL,是因為它們沒有 SQL 數據庫的那種嚴格結構。它們也被稱為文檔數據庫,因為它們可以存儲非結構化數據,如文檔。
💁 儘管名稱如此,一些 NoSQL 數據庫允許你使用 SQL 查詢數據。
NoSQL 數據庫沒有預定義的模式來限制數據的存儲方式,相反,你可以插入任何非結構化數據,通常使用 JSON 文檔。這些文檔可以組織成文件夾,類似於計算機上的文件。每個文檔可以與其他文檔有不同的字段 - 例如,如果你存儲來自農場車輛的 IoT 數據,有些可能有加速度計和速度數據字段,其他可能有拖車溫度字段。如果你要添加一種新型卡車,例如內置秤來跟踪運載的產品重量,那麼你的 IoT 設備可以添加這個新字段,並且可以在不對數據庫進行任何更改的情況下存儲它。
一些知名的 NoSQL 數據庫包括 Azure CosmosDB、MongoDB 和 CouchDB。
✅ 做一些研究:閱讀一些這些 NoSQL 數據庫及其功能。
在本課中,你將使用 NoSQL 存儲來存儲 IoT 數據。
將 GPS 數據發送到 IoT 中心
在上一課中,你從連接到 IoT 設備的 GPS 感測器捕捉了 GPS 數據。要將這些 IoT 數據存儲在雲端,你需要將其發送到 IoT 服務。你將再次使用 Azure IoT 中心,這是你在上一個項目中使用的相同 IoT 雲服務。
任務 - 將 GPS 數據發送到 IoT 中心
-
使用免費層創建一個新的 IoT 中心。
⚠️ 如果需要,你可以參考 項目 2,第 4 課中創建 IoT 中心的說明。
記得創建一個新的資源組。將新資源組命名為
gps-sensor
,並將新的 IoT 中心命名為基於gps-sensor
的唯一名稱,例如gps-sensor-<你的名字>
。💁 如果你仍然有上一個項目的 IoT 中心,可以重複使用它。創建其他服務時,請記住使用此 IoT 中心的名稱及其所在的資源組。
-
向 IoT 中心添加一個新設備。將此設備命名為
gps-sensor
。獲取設備的連接字符串。 -
更新你的設備代碼,使用上一個步驟中的設備連接字符串將 GPS 數據發送到新的 IoT 中心。
⚠️ 如果需要,你可以參考 項目 2,第 4 課中將設備連接到 IoT 的說明。
-
發送 GPS 數據時,請使用以下格式的 JSON:
{
"gps" :
{
"lat" : <latitude>,
"lon" : <longitude>
}
} -
每分鐘發送一次 GPS 數據,以免用完每日消息配額。
如果你使用 Wio Terminal,請記得添加所有必要的庫,並使用 NTP 伺服器設置時間。在發送 GPS 位置之前,你的代碼還需要確保已經從串行端口讀取了所有數據,使用上一課的現有代碼。使用以下代碼構建 JSON 文檔:
DynamicJsonDocument doc(1024);
doc["gps"]["lat"] = gps.location.lat();
doc["gps"]["lon"] = gps.location.lng();
如果你使用虛擬 IoT 設備,請記得使用虛擬環境安裝所有必要的庫。
對於 Raspberry Pi 和虛擬 IoT 設備,使用上一課的現有代碼來獲取緯度和經度值,然後使用以下代碼以正確的 JSON 格式發送它們:
message_json = { "gps" : { "lat":lat, "lon":lon } }
print("Sending telemetry", message_json)
message = Message(json.dumps(message_json))
💁 你可以在 code/wio-terminal、code/pi 或 code/virtual-device 資料夾中找到這段程式碼。
運行你的設備代碼,並使用 az iot hub monitor-events
CLI 命令確保消息流入 IoT 中心。
熱路徑、暖路徑和冷路徑
從 IoT 設備流向雲端的數據並不總是實時處理的。有些數據需要實時處理,有些數據可以稍後處理,有些數據可以更晚處理。數據流向不同服務並在不同時間處理的過程被稱為熱路徑、暖路徑和冷路徑。
熱路 徑
熱路徑指的是需要實時或近實時處理的數據。你可以使用熱路徑數據來發出警報,例如接收到車輛接近倉庫的警報,或冷藏卡車內的溫度過高的警報。
要使用熱路徑數據,你的代碼應該在雲服務接收到事件後立即做出響應。
暖路徑
暖路徑指的是可以在接收後稍後處理的數據,例如用於報告或短期分析。你可以使用暖路徑數據來生成車輛里程的每日報告,使用前一天收集的數據。
暖路徑數據在被雲服務接收後會被存儲在某種可以快速訪問的存儲中。
冷路徑
冷路徑指的是歷史數據,將數據長期存儲以便隨時處理。例如,你可以使用冷路徑來獲取車輛的年度里程報告,或對路線進行分析以找到最優路線來降低燃料成本。
冷路徑數據存儲在數據倉庫中——這些數據庫設計用於存儲大量不會改變的數據,並且可以快速輕鬆地查詢。通常,你的雲應用程序中會有一個定期運行的任務,每天、每週或每月定期將數據從暖路徑存儲移動到數據倉庫中。
✅ 思考一下你在這些課程中捕獲的數據。它是熱路徑、暖路徑還是冷路徑數據?
使用無伺服器代碼處理 GPS 事件
一旦數據流入你的 IoT 中心,你可以編寫一些無伺服器代碼來監聽發佈到與事件中心兼容的端點的事件。這是暖路徑——這些數據將被存儲並在下一課中用於報告行程。
任務 - 使用無伺服器代碼處理 GPS 事件
-
使用 Azure Functions CLI 創建一個 Azure Functions 應用。使用 Python 運行時,並在名為
gps-trigger
的資料夾中創建它,並使用相同的名稱作為 Functions 應用項目名稱。確保你創建了一個虛擬環境來使用它。⚠️ 如果需要,你可以參考 項目 2,第 5 課中創建 Azure Functions 項目的說明。
-
添加一個使用 IoT 中心的事件中心兼容端點的 IoT 中心事件觸發器。
⚠️ 如果需要,你可以參考 項目 2,第 5 課中創建 IoT 中心事件觸發器的說明。
-
在
local.settings.json
文件中設置事件中心兼容端點連接字符串,並在function.json
文件中使用該條目的鍵。 -
使用 Azurite 應用作為本地存儲模擬器
-
運行你的 Functions 應用,確保它正在接收來自你的 GPS 設備的事件。確保你的 IoT 設備也在運行並發送 GPS 數據。
Python EventHub trigger processed an event: {"gps": {"lat": 47.73481, "lon": -122.25701}}
Azure 存儲帳戶
Azure 存儲帳戶是一種通用存儲服務,可以以多種不同方式存儲數據。你可以將數據存儲為 blob、隊列、表或文件,並且可以同時存儲所有這些數據。
Blob 存儲
“Blob”這個詞意味著二進制大型對象,但已成為任何非結構化數據的術語。你可以將任何數據存儲在 blob 存儲中,從包含 IoT 數據的 JSON 文檔到圖像和電影文件。Blob 存儲具有“容器”的概念,這些命名的桶可以用來存儲數據,類似於關係數據庫中的表。這些容器可以有一個或多個文件夾來存儲 blob,每個文件夾可以包含其他文件夾,類似於文件存儲在你的計算機硬盤上的方式。
在本課中,你將使用 blob 存儲來存儲 IoT 數據。
✅ 做一些研究:閱讀 Azure Blob 存儲
表存儲
表存儲允許你存儲半結構化數據。表存儲實際上是一個 NoSQL 數據庫,因此不需要預先定義一組表,但它設計用於在一個或多個表中存儲數據,每行都有唯一的鍵來定義。
✅ 做一些研究:閱讀 Azure 表存儲
隊列存儲
隊列存儲允許你將大小最多為 64KB 的消息存儲在隊列中。你可以將消息添加到隊列的後面,並從前面讀取它們。隊列會無限期地存儲消息,只要還有存儲空間,因此允許消息長期存儲,然後在需要時讀取。例如,如果你想運行每月一次的作業來處理 GPS 數據,你可以每天將其添加到隊列中,然後在月底處理隊列中的所有消息。
✅ 做一些研究:閱讀 Azure 隊列存儲
文件存儲
文件存儲是雲中的文件存儲,任何應用程序或設備都可以使用行業標準協議進行連接。你可以將文件寫入文件存儲,然後將其掛載為 PC 或 Mac 上的驅動器。
✅ 做一些研究:閱讀 Azure 文件存儲
將你的無伺服器代碼連接到存儲
你的 Functions 應用現在需要連接到 blob 存儲以存儲來自 IoT 中心的消息。有兩種方法可以做到這一點:
- 在函數代碼內部,使用 blob 存儲 Python SDK 連接到 blob 存儲並將數據寫入 blob
- 使用輸出函數綁定將函數的返回值綁定到 blob 存儲,並自動保存 blob
在本課中,你將使用 Python SDK 來了解如何與 blob 存儲進行交互。
數據將以 JSON blob 的格式保存,格式如下:
{
"device_id": <device_id>,
"timestamp" : <time>,
"gps" :
{
"lat" : <latitude>,
"lon" : <longitude>
}
}
任務 - 將你的無伺服器代碼連接到存儲
-
創建一個 Azure 存儲帳戶。將其命名為類似
gps<你的名字>
的名稱。⚠️ 如果需要,你可以參考項目 2,課程 5 中創建存儲帳戶的說明。
如果你在上一個項目中仍然有一個存儲帳戶,你可以重複使用這個帳戶。
💁 你將能夠在本課程的後面使用相同的存儲帳戶來部署你的 Azure Functions 應用。
-
運行以下命令以獲取存儲帳戶的連接字符串:
az storage account show-connection-string --output table \
--name <storage_name>將
<storage_name>
替換為你在上一步中創建的存儲帳戶的名稱。 -
為你的存儲帳戶連接字符串在
local.settings.json
文件中添加一個新條目,名稱為STORAGE_CONNECTION_STRING
-
在
requirements.txt
文件中添加以下內容以安裝 Azure 存儲 Pip 包:azure-storage-blob
在你的虛擬環境中從此文件安裝包。
如果你遇到錯誤,請在你的虛擬環境中使用以下命令將 Pip 版本升級到最新版本,然後重試:
pip install --upgrade pip
-
在
iot-hub-trigger
的__init__.py
文件中添加以下導入語句:import json
import os
import uuid
from azure.storage.blob import BlobServiceClient, PublicAccessjson
系統模塊將用於讀取和寫入 JSON,os
系統模塊將用於讀取連接字符串,uuid
系統模塊將用於生成 GPS 讀數的唯一 ID。azure.storage.blob
包含用於與 blob 存儲交互的 Python SDK。 -
在
main
方法之前,添加以下輔助函數:def get_or_create_container(name):
connection_str = os.environ['STORAGE_CONNECTION_STRING']
blob_service_client = BlobServiceClient.from_connection_string(connection_str)
for container in blob_service_client.list_containers():
if container.name == name:
return blob_service_client.get_container_client(container.name)
return blob_service_client.create_container(name, public_access=PublicAccess.Container)Python blob SDK 沒有輔助方法來創建一個不存在的容器。此代碼將從
local.settings.json
文件(或部署到雲後的應用程序設置)中加載連接字符串,然後從中創建一個BlobServiceClient
類來與 blob 存儲帳戶交互。然後它會遍歷 blob 存儲帳戶的所有容器,尋找具有提供名稱的容器 - 如果找到,它將返回一個ContainerClient
類,可以與容器交互以創建 blob。如果找不到,則創建容器並返回新容器的客戶端。當創建新容器時,將授予公共訪問權限以查詢容器中的 blob。這將在下一課中用於在地圖上可視化 GPS 數據。
-
與土壤濕度不同,這段代碼我們希望存儲每個事件,因此在
main
函數中的for event in events:
循環內,在logging
語句下添加以下代碼:device_id = event.iothub_metadata['connection-device-id']
blob_name = f'{device_id}/{str(uuid.uuid1())}.json'此代碼從事件元數據中獲取設備 ID,然後使用它創建 blob 名稱。Blob 可以存儲在文件夾中,設備 ID 將用於文件夾名稱,因此每個設備將所有 GPS 事件存儲在一個文件夾中。Blob 名稱是這個文件夾,後面跟著一個文檔名稱,用正斜杠分隔,類似於 Linux 和 macOS 路徑(也類似於 Windows,但 Windows 使用反斜杠)。文檔名稱是使用 Python
uuid
模塊生成的唯一 ID,文件類型為json
。例如,對於
gps-sensor
設備 ID,blob 名稱可能是gps-sensor/a9487ac2-b9cf-11eb-b5cd-1e00621e3648.json
。 -
在此代碼下方添加以下代碼:
container_client = get_or_create_container('gps-data')
blob = container_client.get_blob_client(blob_name)此代碼使用
get_or_create_container
輔助類獲取容器客戶端,然後使用 blob 名稱獲取 blob 客戶端對象。這些 blob 客戶端可以引用現有的 blob,或者像這種情況一樣,引用新的 blob。 -
在此代碼後添加以下代碼:
event_body = json.loads(event.get_body().decode('utf-8'))
blob_body = {
'device_id' : device_id,
'timestamp' : event.iothub_metadata['enqueuedtime'],
'gps': event_body['gps']
}這將構建將寫入 blob 存儲的 blob 主體。它是一個 JSON 文檔,包含設備 ID、將遙測發送到 IoT Hub 的時間以及遙測中的 GPS 坐標。
💁 使用消息的入隊時間而不是當前時間來獲取消息發送的時間非常重要。如果 Functions 應用未運行,消息可能會在中心上停留一段時間。
-
在此代碼下方添加以下代碼:
logging.info(f'Writing blob to {blob_name} - {blob_body}')
blob.upload_blob(json.dumps(blob_body).encode('utf-8'))此代碼記錄即將寫入的 blob 及其詳細信息,然後將 blob 主體上傳為新 blob 的內容。
-
運行 Functions 應用。你將在輸出中看到為所有 GPS 事件寫入的 blob:
[2021-05-21T01:31:14.325Z] Python EventHub trigger processed an event: {"gps": {"lat": 47.73092, "lon": -122.26206}}
...
[2021-05-21T01:31:14.351Z] Writing blob to gps-sensor/4b6089fe-ba8d-11eb-bc7b-1e00621e3648.json - {'device_id': 'gps-sensor', 'timestamp': '2021-05-21T00:57:53.878Z', 'gps': {'lat': 47.73092, 'lon': -122.26206}}💁 確保你沒有同時運行 IoT Hub 事件監視器。
💁 你可以在 code/functions 文件夾中找到此代碼。
任務 - 驗證上傳的 blob
-
要查看創建的 blob,你可以使用 Azure Storage Explorer,這是一個免費工具,允許你查看和管理存儲帳戶,或從 CLI 查看。
-
要使用 CLI,首先你需要一個帳戶密鑰。運行以下命令以獲取此密鑰:
az storage account keys list --output table \
--account-name <storage_name>將
<storage_name>
替換為存儲帳戶的名稱。複製
key1
的值。 -
運行以下命令以列出容器中的 blob:
az storage blob list --container-name gps-data \
--output table \
--account-name <storage_name> \
--account-key <key1>將
<storage_name>
替換為存儲帳戶的名稱,將<key1>
替換為你在上一步中複製的key1
的值。這將列出容器中的所有 blob:
Name Blob Type Blob Tier Length Content Type Last Modified Snapshot
---------------------------------------------------- ----------- ----------- -------- ------------------------ ------------------------- ----------
gps-sensor/1810d55e-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:27+00:00
gps-sensor/18293e46-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:28+00:00
gps-sensor/1844549c-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:28+00:00
gps-sensor/1894d714-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:28+00:00 -
使用以下命令下載其中一個 blob:
az storage blob download --container-name gps-data \
--account-name <storage_name> \
--account-key <key1> \
--name <blob_name> \
--file <file_name>將
<storage_name>
替換為存儲帳戶的名稱,將<key1>
替換為你在前一步中複製的key1
的值。將
<blob_name>
替換為上一步輸出中Name
列的完整名稱,包括文件夾名稱。將<file_name>
替換為本地文件的名稱以保存 blob。
下載後,你可以在 VS Code 中打開 JSON 文件,你將看到包含 GPS 位置詳細信息的 blob:
{"device_id": "gps-sensor", "timestamp": "2021-05-21T00:57:53.878Z", "gps": {"lat": 47.73092, "lon": -122.26206}}
-
任務 - 將你的 Functions 應用部署到雲端
現在你的 Functions 應用已經可以工作,你可以將其部署到雲端。
-
使用你之前創建的存儲帳戶創建一個新的 Azure Functions 應用。將其命名為類似
gps-sensor-
並在末尾添加一個唯一標識符,例如一些隨機單詞或你的名字。⚠️ 如果需要,你可以參考項目 2,課程 5 中創建 Functions 應用的說明。
-
將
IOT_HUB_CONNECTION_STRING
和STORAGE_CONNECTION_STRING
值上傳到應用程序設置⚠️ 如果需要,你可以參考項目 2,課程 5 中上傳應用程序設置的說明。
-
將你的本地 Functions 應用部署到雲端。
⚠️ 如果需要,你可以參考項目 2,課程 5 中部署 Functions 應用的說明。