移至主內容

把壓力溫度數據寫入DynamoDB:打造無伺服器歷史記錄資料庫

工廠IT技術人員專用AWS DynamoDB無伺服器資料庫ATLANTIS 自有品牌

把壓力溫度數據寫入DynamoDB:打造無伺服器歷史記錄資料庫

台灣31年工業儀錶製造商 ATLANTIS 昶特有限公司系列教學文章第六篇:前五篇我們完成了「感測器發布」「MQTT訂閱」「Lambda事件觸發」「封包解析」與「SNS即時告警」,資料流已經能即時反應異常。但異常發生前的趨勢去了哪裡?本篇教你如何用DynamoDB把每一筆壓力溫度數據存下來,打造一個不需要管理任何伺服器的歷史記錄資料庫,同時補上第五篇提到「告警疲勞抑制」所需的狀態儲存機制。

ATLANTIS的品牌使命「Re-Atlantis」,是重現古代理想文明對精密秩序的追求——而秩序的一個重要面向,是記憶。沒有歷史記錄的即時監控,就像沒有記憶的智慧,只能看見當下,卻無法從過去的模式中學習。這也是為什麼本篇要帶你認識DynamoDB這個無伺服器資料庫服務。詳見 ATLANTIS 品牌故事

一、為什麼選DynamoDB,而不是傳統的關聯式資料庫?

工廠IT技術人員多半熟悉MySQL、SQL Server這類關聯式資料庫,但IoT感測器數據有一個明顯特性:寫入頻繁、結構單純、依時間查詢。DynamoDB是AWS的無伺服器NoSQL資料庫服務,天生就是為這種「時間序列」數據設計的,不需要管理資料庫伺服器、不需要規劃儲存容量、也不需要煩惱擴充問題。

0台
需要自行維運的
資料庫伺服器
毫秒級
單筆讀寫延遲
(依請求容量模式)
自動
依流量自動擴充
(隨選容量模式)
TTL
內建自動過期機制
免寫刪除排程

DynamoDB vs 關聯式資料庫:核心差異

比較項目關聯式資料庫(如MySQL)DynamoDB
伺服器管理需自行維運或使用RDS代管完全無伺服器,AWS全權管理
擴充方式需規劃執行個體規格與儲存空間隨選容量模式自動依流量擴充
資料結構彈性需預先定義固定欄位結構(Schema)除主鍵外,每筆資料欄位可彈性不同
查詢彈性支援複雜JOIN、聚合查詢依主鍵設計查詢,複雜分析建議搭配其他服務
適合場景複雜關聯資料、報表分析高頻寫入的時間序列數據、鍵值查詢

對於「感測器每30秒回報一次數據」這種場景,DynamoDB的高頻寫入能力與免維運特性,正是工廠IT技術人員最需要的——你不需要成為資料庫管理員,也能打造一套穩定運作的歷史記錄系統。

二、架構總覽:兩種把資料寫入DynamoDB的方式

AWS IoT Core 規則引擎 MQTT訊息抵達 方式A:規則直接寫入 動作:DynamoDBv2 不需經過Lambda 適合簡單原始資料儲存 方式B:透過Lambda寫入 先解析/判斷異常 再呼叫put_item() 適合需要額外運算的情境 DynamoDB資料表 partition key:device_id sort key:timestamp TTL:自動清理舊資料 應用層 歷史趨勢查詢 儀表板/報表 S3 長期歸檔

兩種方式的選擇原則很單純:如果只是單純儲存原始數據,不需要額外判斷邏輯,用IoT Core規則直接寫入DynamoDB最省事;如果需要先解析封包、判斷異常再決定要不要記錄,就透過Lambda函式寫入,本篇會分別示範這兩種作法。

三、資料表設計:主鍵(Partition Key)與排序鍵(Sort Key)

DynamoDB的查詢效能高度依賴主鍵設計,這是整篇文章最關鍵的觀念。對於時間序列的感測器數據,業界最常見的設計是:Partition Key用裝置ID,Sort Key用時間戳記

欄位名稱角色範例值設計理由
device_idPartition Key(分區鍵)ATL-STT-001相同裝置的資料會被分到同一分區,方便依裝置查詢
timestampSort Key(排序鍵)1784812345同一裝置底下的資料依時間排序,方便查詢時間範圍
temperature一般屬性68.4實際量測數值
unit一般屬性"C"單位標記
ttlTTL屬性(選用)1787404345超過此Unix時間戳記後,DynamoDB自動刪除該筆資料

這樣的設計讓你可以用一次查詢,取得「某裝置在某時間範圍內」的所有歷史數據,例如「查詢ATL-STT-001裝置過去24小時的所有溫度記錄」,這是本篇後段查詢範例會實際示範的操作。

建立資料表:主控台設定重點

在DynamoDB主控台建立資料表時,只需要指定Partition Key(device_id,字串型態)與Sort Key(timestamp,數字型態),其餘欄位不需要事先定義,這正是NoSQL資料庫「結構彈性」的優勢——不同型號感測器可以有不同的屬性欄位,不需要統一的資料表結構。

四、方式一:用Lambda寫入DynamoDB(含判斷邏輯)

延續第三篇的最小Lambda函式,加上寫入DynamoDB的邏輯,這是最靈活、最容易理解的作法。

範例一:Lambda解析並寫入DynamoDB

import json
import time
import boto3
from decimal import Decimal

dynamodb = boto3.resource("dynamodb", region_name="ap-northeast-1")
table = dynamodb.Table("factory_temperature_history")

def lambda_handler(event, context):
    device_id = event.get("device_id", "unknown")
    temperature = event.get("temperature")
    timestamp = event.get("timestamp", int(time.time()))

    if temperature is None:
        return {"statusCode": 400, "body": "缺少temperature欄位"}

    # DynamoDB不接受Python float,需轉換為Decimal型態
    table.put_item(
        Item={
            "device_id": device_id,
            "timestamp": timestamp,
            "temperature": Decimal(str(temperature)),
            "unit": "C",
            "ttl": timestamp + (90 * 24 * 60 * 60)  # 保留90天
        }
    )

    print(f"已寫入DynamoDB:裝置{device_id} 溫度{temperature}°C")

    return {"statusCode": 200, "body": json.dumps("寫入完成")}

這裡有一個Python工程師常踩的坑:DynamoDB不接受Python原生的float型態,必須轉換為Decimal,否則boto3會直接拋出例外。另外,ttl欄位若在建立資料表時已啟用TTL功能並指定該屬性名稱,DynamoDB會在超過該時間戳記後自動刪除該筆資料,不需要額外寫排程刪除的程式。

IAM權限:Lambda需要哪些DynamoDB權限?

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": ["dynamodb:PutItem", "dynamodb:Query"],
            "Resource": "arn:aws:dynamodb:ap-northeast-1:123456789012:table/factory_temperature_history"
        }
    ]
}

五、方式二:IoT Core規則引擎直接寫入DynamoDB(不需要Lambda)

若你只需要單純儲存原始數據,不需要任何額外判斷邏輯,AWS IoT Core規則引擎本身就內建「DynamoDBv2」動作,可以直接把訊息寫入資料表,完全不需要撰寫或維護Lambda函式。

規則SQL語句(與第三篇相同的篩選邏輯)

SELECT device_id, temperature, timestamp() as ts
FROM 'factory/+/+/temperature/#'

在規則的「動作」設定中,選擇「將訊息寫入DynamoDB資料表(DynamoDBv2)」,並將訊息中的device_id對應到資料表的Partition Key、ts對應到Sort Key,其餘欄位會以JSON格式整筆存入。這種方式的好處是架構更簡單、少一層Lambda執行費用,缺點是無法在寫入前執行任何自訂運算邏輯(如封包解析)。

兩種寫入方式比較

比較項目方式A:規則直接寫入方式B:透過Lambda寫入
是否需要Lambda不需要需要
可否先做封包解析不行,僅能簡單欄位對應可以,Lambda內可執行任意邏輯
可否在寫入前判斷是否記錄僅能用規則SQL的WHERE條件可以在Lambda內做複雜條件判斷
費用僅IoT Core規則與DynamoDB費用額外增加Lambda執行費用
建議情境資料已是乾淨格式,僅需儲存需要解析封包、判斷告警邏輯後再儲存

六、查詢歷史數據:用Query取得某裝置過去24小時的溫度記錄

資料存進去後,下一步是查詢。DynamoDB的Query操作專門針對「已知Partition Key,查詢特定Sort Key範圍」的情境設計,效能遠優於全表掃描(Scan)。

範例二:查詢單一裝置過去24小時的溫度記錄

import boto3
import time
from boto3.dynamodb.conditions import Key

dynamodb = boto3.resource("dynamodb", region_name="ap-northeast-1")
table = dynamodb.Table("factory_temperature_history")

def query_last_24_hours(device_id: str):
    now = int(time.time())
    yesterday = now - (24 * 60 * 60)

    response = table.query(
        KeyConditionExpression=(
            Key("device_id").eq(device_id) &
            Key("timestamp").between(yesterday, now)
        )
    )

    return response.get("Items", [])

# 使用範例
records = query_last_24_hours("ATL-STT-001")
print(f"共取得 {len(records)} 筆歷史記錄")
for record in records:
    print(record["timestamp"], record["temperature"])

這段程式碼是後續系列文章「儀表板串接」的核心基礎——任何前端圖表或報表工具,最終都是呼叫類似這樣的Query操作取得歷史數據,再交給圖表函式庫繪製趨勢線。

七、補回第五篇的缺口:用DynamoDB實作告警狀態追蹤

第五篇中,我們提到「狀態變化觸發」與「冷卻時間」都需要外部狀態儲存,現在有了DynamoDB,可以正式補完這個機制。

範例三:用DynamoDB記錄裝置告警狀態,避免重複通知

import time
import boto3

dynamodb = boto3.resource("dynamodb", region_name="ap-northeast-1")
state_table = dynamodb.Table("factory_device_alert_state")
COOLDOWN_SECONDS = 900  # 15分鐘冷卻時間

def should_send_alert(device_id: str, is_abnormal: bool) -> bool:
    now = int(time.time())
    response = state_table.get_item(Key={"device_id": device_id})
    item = response.get("Item", {})

    last_state = item.get("last_state", "normal")
    last_alert_time = item.get("last_alert_time", 0)
    current_state = "abnormal" if is_abnormal else "normal"

    # 條件一:狀態由normal轉為abnormal,或
    # 條件二:持續異常但已超過冷卻時間
    newly_abnormal = (last_state == "normal" and current_state == "abnormal")
    cooldown_passed = (now - int(last_alert_time)) > COOLDOWN_SECONDS

    should_notify = current_state == "abnormal" and (newly_abnormal or cooldown_passed)

    update_expr = "SET last_state = :s"
    expr_values = {":s": current_state}
    if should_notify:
        update_expr += ", last_alert_time = :t"
        expr_values[":t"] = now

    state_table.update_item(
        Key={"device_id": device_id},
        UpdateExpression=update_expr,
        ExpressionAttributeValues=expr_values
    )

    return should_notify

把這個函式放進第五篇的Lambda函式中,在呼叫sns_client.publish()之前先呼叫should_send_alert()判斷,就能真正做到「只在異常剛發生時通知一次,且持續異常時每15分鐘提醒一次」,而不是每30秒轟炸值班人員的手機——這正是完整的事件驅動告警架構。

八、費用與容量模式:隨選 vs 預置

容量模式計費方式適合情境
隨選容量(On-Demand)依實際讀寫請求數計費,無需預先設定流量不穩定、剛起步的PoC專案,工廠IT入門首選
預置容量(Provisioned)預先設定讀寫容量單位,超出需另計費或被限流流量穩定可預測、長期大規模運行的正式環境

對於本系列文章設定的「工廠IT技術人員入門」情境,建議一律使用隨選容量模式,不需要預估流量、不會因設定過低而被限流,等系統規模穩定成長後,再評估是否切換至預置容量模式節省長期成本。實際費率請以AWS官網最新公告為準。

TTL與S3歸檔:長期歷史數據的儲存策略

DynamoDB適合儲存「近期、需要快速查詢」的數據(如過去90天),但若需要保留數年的完整歷史記錄用於稽核或長期趨勢分析,建議搭配TTL機制:資料超過設定天數後自動從DynamoDB刪除,刪除前可透過DynamoDB Streams觸發Lambda將資料同步寫入S3做低成本長期歸檔,兼顧查詢效能與儲存成本。

九、ATLANTIS 適合搭配歷史記錄系統的量測與記錄產品

TDL-R/D-6C 可攜式螢幕觸控溫度紀錄器(六組通道型)

TDL-R/D-6C 可攜式螢幕觸控溫度紀錄器(六組通道型)—— 每通道可獨立設定高/低溫警報並繪製溫度曲線,理念與雲端歷史記錄資料庫相通

DPG-X112 高精度藍芽數位壓力錶(可旋轉式)

DPG-X112 高精度藍芽數位壓力錶(可旋轉式)—— 支援Type-C或藍芽功能匯出記錄數據,適合作為DynamoDB歷史記錄的現場資料來源

LTPT-410RS系列 溫度液位傳送器

LTPT-410RS系列 溫度液位傳送器 —— 同時測量溫度與液位,適合需要多欄位歷史記錄的雲端資料庫應用

SLPTX系列 數位式HART智能型液位傳送器

SLPTX系列 數位式HART智能型液位傳送器 —— 三重保護功能防止結露問題,長期穩定輸出適合建立可信賴的歷史趨勢資料庫

十、案例分享:某桃園食品廠的溫度歷史數據導入過程

以下案例經匿名化處理,客戶為桃園一家食品加工廠,因應HACCP衛生管理規範要求,需要保留完整的冷藏冷凍溫度歷史記錄供稽核使用。

階段作法導入前導入後
資料儲存IoT Core規則直接寫入DynamoDB(方式A)紙本記錄,人工每小時抄寫一次每30秒自動記錄,資料完整度大幅提升
稽核查詢依裝置ID與時間範圍Query歷史數據稽核時需翻閱大量紙本表單稽核人員可即時查詢任意時間區間的完整記錄
長期保存設定TTL 2年,搭配DynamoDB Streams歸檔至S3紙本保存空間有限,容易佚失雲端永久保存,符合法規稽核追溯要求

資深工程師賴祥德分享:「食品業與製藥業的溫度記錄,往往不只是內部管理需求,更是法規稽核的硬性要求。過去看過工廠因為紙本記錄不完整被稽核單位開罰,導入雲端歷史記錄資料庫後,這類風險幾乎可以完全避免——重點是資料要『自動記錄』,而不是依賴人為記憶。」

資料來源與延伸閱讀

本文技術架構參考 AWS DynamoDB 官方文件(docs.aws.amazon.com/dynamodb)與 AWS IoT Core 規則引擎動作官方文件。費用與容量模式資訊請以AWS官網最新公告為準。ATLANTIS產品技術規格引用自內部產品規格書。

十二、20 大常見問題 FAQ(DynamoDB 歷史記錄資料庫)

1. DynamoDB的Partition Key選錯了,之後可以修改嗎?
不行,DynamoDB資料表建立後無法修改Partition Key或Sort Key的定義,若設計錯誤只能建立新資料表並遷移資料,因此建議在建立資料表前就依查詢需求審慎規劃主鍵結構。
2. 為什麼DynamoDB不接受Python的float型態?
DynamoDB內部使用高精度數字格式,boto3的DynamoDB資源介面要求數字必須以Decimal型態傳入,以避免浮點數精度誤差問題,直接傳入float會拋出型態錯誤例外。
3. TTL屬性刪除資料是立即發生的嗎?
不是立即的,TTL刪除是背景非同步程序,通常在超過設定時間戳記後的數小時內完成刪除,若應用邏輯依賴「資料絕對不存在」做判斷,建議額外加上應用層的時間範圍過濾。
4. Query和Scan有什麼差別?為什麼建議優先用Query?
Query只讀取符合指定Partition Key(及選擇性Sort Key條件)的資料,效能穩定且成本可預期;Scan則會掃描整張資料表,隨資料量增長效能會顯著下降且成本較高,一般查詢應優先設計為可用Query完成。
5. 隨選容量模式會不會比預置容量貴很多?
視流量穩定度而定,流量不穩定或難以預估時,隨選容量通常更划算且無需管理;流量穩定且可預測的大規模長期運行場景,預置容量搭配合理設定可能更省成本,建議依實際用量定期評估。
6. 我可以在同一張資料表存溫度和壓力兩種數據嗎?
可以,DynamoDB允許同一資料表內不同項目擁有不同屬性欄位,只要Partition Key與Sort Key的設計邏輯一致(如都用device_id與timestamp),即可在同一資料表混合儲存不同類型的感測數據。
7. 用IoT Core規則直接寫入DynamoDB,可以同時設定TTL欄位嗎?
規則的DynamoDBv2動作主要對應訊息欄位到資料表屬性,若需要動態計算的TTL時間戳記(如目前時間加90天),建議改用Lambda方式寫入,較能靈活處理這類運算邏輯。
8. DynamoDB Streams是什麼?跟資料歸檔有什麼關係?
DynamoDB Streams會記錄資料表的異動事件(新增、修改、刪除),可以設定觸發Lambda函式,在資料即將因TTL被刪除前,先將該筆資料寫入S3等長期儲存服務,達成歷史數據歸檔的效果。
9. 查詢超過24小時的數據,程式邏輯需要改動很多嗎?
不需要,只需調整範例二中yesterday變數的計算方式(例如改為7天或30天前的時間戳記),KeyConditionExpression的邏輯結構完全不變,這是Sort Key範圍查詢的彈性優勢。
10. 告警狀態表(factory_device_alert_state)需要保留歷史記錄嗎?
不需要,這張表只用於記錄「目前最新狀態」,每個裝置只會有一筆對應紀錄並持續被覆寫更新,與歷史數據表(每筆都保留)的設計目的完全不同,屬於「狀態表」而非「記錄表」。
11. get_item()和query()有什麼不同?
get_item()用於取得單一已知Partition Key(及Sort Key,若有的話)的單筆資料,效能最快;query()用於取得符合Partition Key且Sort Key符合條件範圍的多筆資料,本文範例二即為此類應用。
12. 我可以用DynamoDB做即時儀表板嗎,還是一定要另外用其他服務?
可以直接用DynamoDB搭配後端API(如API Gateway + Lambda)供前端儀表板查詢歷史數據,這也是本系列文章後續篇章「用API Gateway打造溫度數據查詢REST API」要展開的架構。
13. 資料表的讀寫權限,Lambda執行角色要怎麼設定才安全?
建議遵循最小權限原則,只授權該Lambda函式實際需要的動作(如僅dynamodb:PutItem而非全部權限),並將Resource範圍限定為特定資料表的ARN,避免過於寬鬆的萬用字元授權。
14. update_item()和put_item()有什麼差別?
put_item()會整筆覆寫(或新增)該主鍵對應的項目;update_item()則只更新指定的屬性欄位,保留其他既有欄位不變,本文範例三的告警狀態更新即使用update_item()以保留未變動的欄位。
15. 感測器離線一段時間後恢復,歷史數據會有缺口嗎?
會,DynamoDB只會記錄實際有寫入的資料,若感測器或通訊中斷期間沒有數據送達,對應時間範圍自然不會有記錄,這是正常現象,可在應用層另外標記或分析資料完整度。
16. 我需要為每一種感測器類型建立獨立的資料表嗎?
不一定需要,可依團隊管理習慣選擇:單一資料表混合儲存(依device_id區分裝置類型)較易維護;分開建表則有更清楚的權限與容量管理邊界,可依實際規模與治理需求選擇。
17. DynamoDB的資料一致性如何?寫入後馬上查詢得到嗎?
DynamoDB預設提供最終一致性讀取,多數情況下寫入後幾乎立即可查詢到,若應用需要絕對保證讀到最新寫入的資料,可以在查詢時指定「強一致性讀取」選項,但會消耗較多讀取容量。
18. 這套歷史記錄架構,資料保存期限要設多久比較合適?
依產業法規與內部管理需求而定,例如食品業HACCP或製藥業GMP可能要求保存數年;一般工廠設備監控若無特定法規要求,可先設定90天至1年,再視實際查詢需求調整TTL設定。
19. 我可以用DynamoDB做跨裝置的統計分析(如全廠平均溫度)嗎?
DynamoDB本身較適合鍵值查詢而非複雜聚合分析,若需要跨裝置的統計運算,建議搭配Amazon Athena查詢歸檔至S3的資料,或使用Amazon QuickSight等分析服務進行更複雜的跨裝置報表分析。
20. 學會DynamoDB歷史記錄後,下一步該學什麼?
建議接續學習IoT Core規則引擎的更多進階應用,以及如何用API Gateway搭配Lambda把DynamoDB中的歷史數據包裝成REST API,供工廠儀表板或第三方系統查詢使用,這是本系列文章後續篇章的主題。

十三、下一步:讓 ATLANTIS 協助你規劃符合稽核需求的雲端歷史記錄架構

31年工業儀錶製造經驗 × 數位化歷史記錄解決方案

從變送器選型、資料表主鍵設計,到符合HACCP/GMP稽核需求的長期保存規劃,我們可以陪工廠IT團隊打造完整的雲端歷史記錄資料庫。

📞 02-2820-3405 免費選型諮詢 📧 線上快速詢價

業務一部 Ian:ian@atlantis.com.tw | 業務二部 Nori:nori@atlantis.com.tw


文章更新時間:2026年7月|作者:ATLANTIS 應用工程團隊|本文為系列教學文章第六篇,下一篇將深入「AWS IoT Core規則引擎實戰:感測器資料自動路由到Lambda與S3」。