- Serverless從入門到進階:架構、原理與實踐
- 方坤丁 孫遠高
- 1959字
- 2021-06-24 11:19:11
4.3 Serverless和數據庫
數據庫作為后端數據查詢和落盤的服務,是Serverless架構中必不可少的一部分。本節通過介紹數據庫服務中關系型數據庫和非關系型數據庫的概念及這兩種數據庫和FaaS服務的聯動方案,為Serverless架構中需要連接數據庫的場景提供參考。
4.3.1 基本概念
大多數軟件架構都涉及數據的存儲和查詢,因此,數據庫聯動是Serverless架構不可或缺的一部分。數據庫相關的知識廣泛且復雜,本節只簡要介紹典型的關系型數據庫MySQL和非關系型數據庫MongoDB,并以二者為例,闡述它們和FaaS的聯動方式及適用場景。
當前軟件產生的數據很大一部分由關系數據管理系統(RDBMS)處理,關系型數據庫便于理解和維護,并且具有事務一致性,遵循ACID的原則,即原子性(Atomicity)、一致性(Consistency)、獨立性(Isolation)和持久性(Durability)。這種特點使得關系型數據庫能滿足所有要求強一致性的場景,例如銀行交易。但這些特性,也導致了關系型數據庫在高并發讀寫、高擴展性的場景下不能很好的適配。此外,隨著用戶生成數據(UGD)和操作日志成倍增加,在很多場景下并不需要保持關系型數據庫的事務一致性或讀寫實時性。此時非關系型數據庫應運而生,可用于海量數據查詢場景,支持高性能、高可用和彈性伸縮,并且基于BASE原則,即基本可用(Basically Available)、軟狀態/柔性事務(Soft-state)和最終一致性(Eventually Consistent)。
關系型數據庫和非關系型數據庫的功能和特性對比如表4-2所示。
表4-2 關系型和非關系型數據庫對比

① CAP即一致性(Consistency)、數據可用性(Availability)、分區耐受性(Partition Tolerance)。CAP原理認為一個提供數據服務的存儲系統無法同時完美滿足一致性、數據可用性和分區耐受性這三個條件。
關系型數據庫和非關系型數據庫各有適用場景和典型的開源/商業化產品,在Serverless中,也需要基于這兩種典型的數據庫設計架構并提供服務。
4.3.2 數據庫和FaaS的聯動
為了確保數據庫連接的安全性,在FaaS平臺訪問數據庫時,需要配置私有網絡VPC,將數據庫和函數放置在相同的VPC內,可以通過私有網絡安全連接云數據庫。
1. 關系型數據庫
FaaS訪問關系型數據庫時,在開通對應訪問權限、配置網絡后,可以通過對應的數據庫客戶端直接連接。代碼清單4-5所示是一個基于Python連接MySQL數據庫。
代碼清單4-5 FaaS連接MySQL數據庫示例
# -*- coding: utf8 -*- import datetime import pymysql.cursors import logging import sys import pytz # MySQL數據庫賬號信息,需要提前創建數據庫,建議用環境變量方式傳參 Host = '******' User = '****' Password = '****' Port = 63054 DB = u'SCF_Demo' logging.basicConfig(level=logging.INFO, stream=sys.stdout) logger = logging.getLogger() logger.setLevel(level=logging.INFO) #更改時區為北京時區 tz = pytz.timezone('Asia/Shanghai') g_connection = None g_connection_errno = 0 def connect_mysql(): global g_connection global g_connection_errno try: g_connection = pymysql.connect(host=Host, user=User, password=Password, port=Port, db=DB, charset='utf8', cursorclass=pymysql.cursors.DictCursor) except Exception as e: g_connection = None g_connection_errno = e[0] print("connect database error:%s"%e) print("connect database") connect_mysql() def main_handler(event, context): print('Start function') print("{%s}" % datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")) print("g_connection is %s" % g_connection) if not g_connection: connect_mysql() if not g_connection: return {"code": 409, "errorMsg": "internal error %s" % g_connection_errno} with g_connection.cursor() as cursor: sql = 'show databases' cursor.execute(sql) res = cursor.fetchall() print res sql = 'use %s'%DB cursor.execute(sql) #創建數據表 cursor.execute("DROP TABLE IF EXISTS Test") cursor.execute("CREATE TABLE Test (Msg TEXT NOT NULL,Time Datetime)") time = datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S") sql = "insert INTO Test ('Msg', 'Time') VALUES (%s, %s)" cursor.execute(sql, ("test", time)) g_connection.commit() sql = "select count(*) from Test" cursor.execute(sql) result = cursor.fetchall() print(result) cursor.close() print("{%s}" % datetime.datetime.now(tz).strftime("%Y-%m-%d %H:%M:%S")) return "test"
需要注意的是,一般在FaaS連接關系型數據庫時,需要管理連接池,實現連接復用。
- 通過Redis進行數據緩存,從而有效控制實際的數據庫連接。
- 調整數據庫的超時時間,同時在代碼中針對斷開的連接做重連策略。
- 適當限制FaaS函數的并發,使其小于數據庫承載的最大連接數,防止數據庫高負載。
- 通過限制連接用戶數、擴容并增加數據庫max_connections等方式進行優化。
對于用戶來說,最好的方案當然是不需要考慮數據庫的連接管理,在數據庫層也能夠實現Serverless化。針對這個需求,AWS發布了Aurora Serverless for MySQL,實現了關系型數據庫的彈性伸縮和按需付費(無請求時銷毀數據庫實例),并且支持HTTP方式的連接和訪問,降低了數據庫使用的門檻。
2. 非關系型數據庫
在Serverless和非關系型數據庫的聯動中,AWS Lambda和DynamoDB的打通最為典型,其他云提供商也在逐步提供類似的服務,本節主要介紹這種連接及其開發模式。
DynamoDB是一個非關系型Key-Value鍵值存儲數據庫。它不會通過結構化、關系型的方式存儲數據,而是用簡單的Key-Value格式存儲JSON對象。此外,DynamoDB是分布式數據庫,因此提供了天然的冗余和備份能力。
在DynamoDB中,表(table)、數據(item)和屬性(attributes)是三個核心概念。其中,每個表由一個或多個數據組成,每個數據又由一個或多個屬性組成。每個表需要設置主鍵(primary key)作為索引,主鍵可以由單一的分區鍵(partition key)組成,也可以由分區鍵和排序鍵(sort key)組成,即復合主鍵。不管使用哪種方式,最后的組成的主鍵在一張表中必須是唯一的。DynamoDB中各個概念之間的關系如圖4-15所示。

圖4-15 DynamoDB概念介紹
AWS Lambda可以通過配置數據庫觸發器的方式,一鍵打通DynamoDB,也可以在函數代碼中實現數據庫的增刪改查。例如每次更新DynamoDB表時,該操作都可以作為事件觸發Lambda函數,執行自定義邏輯。對應的觸發事件格式如代碼清單4-6所示。流事件可以同步觸發函數進行數據庫操作,也可以批量讀取,進行數據庫操作。AWS DynamoDB大大降低了開發人員對數據庫運維和管理的依賴,進一步拓展了開發者的邊界。
代碼清單4-6 DynamoDB事件結構
{ "Records": [ { "eventID": "1", "eventVersion": "1.0", "dynamodb": { "Keys": { "Id": { "N": "101" } }, "NewImage": { "Message": { "S": "New item!" }, "Id": { "N": "101" } }, "StreamViewType": "NEW_AND_OLD_IMAGES", "SequenceNumber": "111", "SizeBytes": 26 }, "awsRegion": "us-west-2", "eventName": "INSERT", "eventSourceARN": eventsourcearn, "eventSource": "aws:dynamodb" }, { "eventID": "2", "eventVersion": "1.0", "dynamodb": { "OldImage": { "Message": { "S": "New item!" }, "Id": { "N": "101" } }, "SequenceNumber": "222", "Keys": { "Id": { "N": "101" } }, "SizeBytes": 59, "NewImage": { "Message": { "S": "This item has changed" }, "Id": { "N": "101" } }, "StreamViewType": "NEW_AND_OLD_IMAGES" }, "awsRegion": "us-west-2", "eventName": "MODIFY", "eventSourceARN": sourcearn, "eventSource": "aws:dynamodb" }
- PHP動態網站程序設計
- Node.js Design Patterns
- Building Modern Web Applications Using Angular
- The Modern C++ Challenge
- Learning ArcGIS Pro 2
- Apache Spark 2.x Machine Learning Cookbook
- OpenStack Cloud Computing Cookbook(Fourth Edition)
- Mastering macOS Programming
- 算法訓練營:提高篇(全彩版)
- Serverless computing in Azure with .NET
- ASP.NET開發與應用教程
- Spring技術內幕:深入解析Spring架構與設計原理(第2版)
- Java程序設計基礎(第6版)
- Python面試通關寶典
- Effective C++:改善程序與設計的55個具體做法(第三版)中文版(雙色)