Python 內(nèi)存數(shù)據(jù)庫 CyberDB 使用實例
CyberDB,一個基于 Python 字典和列表的內(nèi)存數(shù)據(jù)庫。
概括
CyberDB 是一個輕量級的 Python 內(nèi)存數(shù)據(jù)庫。它旨在利用 Python 內(nèi)置數(shù)據(jù)結(jié)構(gòu)字典、列表作數(shù)據(jù)存儲,通過 TCP 套接字高效通信,并提供了數(shù)據(jù)持久化。該數(shù)據(jù)庫的亮點在于它使用了 Pythonic 的方式編程,你可以像使用字典和列表一樣使用 CyberDB。
現(xiàn)在我們把 CyberDB 帶到能發(fā)揮其作用的地方,在生產(chǎn)環(huán)境中將 CyberDB 作為 Flask 的內(nèi)存數(shù)據(jù)庫,使用 Gunicorn 運行,并實現(xiàn)多進程間的通信。
這篇文章通過一個盡可能精簡的 Flask 實例講解,不會涉及復(fù)雜的 Web 知識。核心思路為 CyberDB + Gunicorn + Gevent + Flask(多進程 + 協(xié)程),啟動一個 CyberDB 服務(wù)器,使用 Gunicorn 多進程運行 Flask 實例,每個進程的實例通過 Gevent 運行,進程中使用 CyberDB 客戶端連接至內(nèi)存數(shù)據(jù)庫,由此實現(xiàn)對 CyberDB 數(shù)據(jù)庫的高并發(fā)訪問。
源碼解析
文章使用 PyPy 運行,同樣適用 CPython。
運行環(huán)境: Debian 10, Python 3.8.12, PyPy 7.3.7
此項目的目錄結(jié)構(gòu)
.
├── app.py
├── cyberdb_init.py
├── cyberdb_serve.py
├── requirements.txt
└── venv
我們通過列舉每個文件的內(nèi)容順序講解 CyberDB 的核心操作。
文件 requirements.txt
CyberDB>=0.7.1
Flask==2.1.1
gevent==21.12.0
gunicorn==20.1.0
這是此項目的依賴。這篇文章不是 Python 基礎(chǔ)教程,如果你不清楚,請查詢相關(guān)文檔創(chuàng)建虛擬環(huán)境 venv 目錄并安裝 requirements.txt 中的依賴。
生成 venv 目錄并安裝好依賴后,下面所有操作都在激活的虛擬環(huán)境中運行。
文件 cyberdb_init.py
功能:初始化 CyberDB 的表結(jié)構(gòu),只在第一次運行時使用,后續(xù)不再使用。
import time
import cyberdb
db = cyberdb.Server()
# 配置 CyberDB 服務(wù)端的 地址、端口、密碼。
db.start(host='127.0.0.1', port=9980, password='123456')
# 待服務(wù)端啟動后,連接 CyberDB 服務(wù)端。
time.sleep(3)
client = cyberdb.connect(host='127.0.0.1', port=9980, password='123456')
# 生成 proxy 對象。
with client.get_proxy() as proxy:
# 創(chuàng)建類型為 CyberDict 的表 centre,并初始化內(nèi)容。
proxy.create_cyberdict('centre')
centre = proxy.get_cyberdict('centre')
centre['content'] = 'Hello CyberDB!'
# 將 CyberDB 保存至 data.cdb 。
db.save_db('data.cdb')
在項目根目錄執(zhí)行
python cyberdb_init.py
以完成 CyberDB 數(shù)據(jù)庫表的初始化。
它會在 CyberDB 中創(chuàng)建了一個名為 centre、類型為 CyberDict 的表;初始化 content 鍵的值為 Hello CyberDB!;最后將 CyberDB 數(shù)據(jù)庫保存至硬盤(在項目根目錄生成了名為 data.cdb 的文件)。
文件 cyberdb_serve.py
功能:運行 CyberDB 服務(wù)端。
import cyberdb
def main():
# 后臺運行 CyberDB 服務(wù)端,設(shè)置相關(guān)信息。
db = cyberdb.Server()
# 從硬盤讀取 data.cdb 至 CyberDB。
db.load_db('data.cdb')
# 每 300 秒備份一次數(shù)據(jù)庫。
db.set_backup('data.cdb', cycle=300)
db.run(
host='127.0.0.1', # TCP 運行地址
port=9980, # TCP 監(jiān)聽端口
password='hWjYvVdqRC', # 數(shù)據(jù)庫連接密碼
max_con=10000, # 最大并發(fā)數(shù)
encrypt=True, # 加密通信
print_log=False # 不打印日志
)
if __name__ == '__main__':
main()
在項目根目錄執(zhí)行
python cyberdb_serve.py
以運行 CyberDB 服務(wù)端。
此處設(shè)置了 encrypt=True ,CyberDB 會將 TCP 通信內(nèi)容使用 AES-256 算法加密。開啟 encrypt=True 后,CyberDB 僅允許白名單中的 IP 通信,默認(rèn)白名單為 ['127.0.0.1'](查看白名單 設(shè)置方法)。一般,若只需在本地進程間通信,無需開啟 encrypt=True 和設(shè)置白名單,只有遠(yuǎn)程通信時需要此操作。
文件 app.py
功能:運行 Flask 實例和 CyberDB 客戶端。
import cyberdb
from flask import Flask, g
# 連接 CyberDB 并生成客戶端實例。
client = cyberdb.connect(
host='127.0.0.1',
port=9980,
password='hWjYvVdqRC',
# 服務(wù)端若加密,客戶端必須加密,反之亦然。
encrypt=True,
# 每個連接若超過900秒無操作,將舍棄該連接。
# 連接由連接池智能管理,無需關(guān)注細(xì)節(jié)。
time_out=900
)
# 創(chuàng)建 Flask 實例,此部分請參考
# Flask 文檔 https://flask.palletsprojects.com/
app = Flask(__name__)
@app.before_request
def before_request():
# 每次請求執(zhí)行前生成 proxy 對象。
g.proxy = client.get_proxy()
# 從連接池獲取連接。
g.proxy.connect()
@app.get("/")
def hello_world():
# 從數(shù)據(jù)庫獲取 centre 表。
centre = g.proxy.get_cyberdict('centre')
return {
'code': 1,
'content': centre['content']
}
@app.teardown_request
def teardown_request(error):
# 每次請求執(zhí)行后歸還連接至連接池。
g.proxy.close()
if __name__ == '__main__':
app.run(host='127.0.0.1', port=8000)
該模塊會在每次請求執(zhí)行前(before_request())使用 client.get_proxy() 獲取 proxy 對象,每個獲取的 proxy 對象可以綁定一個 TCP 連接,此處使用 proxy.connect() 從連接池獲取連接。視圖函數(shù) hello_world() 中,由 proxy 獲取的對象 centre,與 proxy 共用同一個連接,proxy 的連接釋放后,centre 也會失去連接。在每次請求后(teardown_request())使用 proxy.close() 方法釋放 proxy 綁定的連接,歸還至連接池。
cyberdb.connect 的 time_out 參數(shù)表示連接池中每個連接的超時時間,此處每個連接超過 900 秒無操作將被舍棄。若不設(shè)置該參數(shù),連接池的每個連接會維持到失效為止。
使用 Gunicorn 運行 Flask 實例
Gunicorn 是一個用于 UNIX 的 Python WSGI HTTP 服務(wù)器,通常在生產(chǎn)環(huán)境使用,可以利用多核 CPU 。
Gevent 是一個基于協(xié)程的 Python 網(wǎng)絡(luò)庫。Gevent 會更改 CyberDB 客戶端的底層套接字通信,使之支持協(xié)程。
在項目根目錄運行
gunicorn -w 4 -b 127.0.0.1:8000 -k gevent app:app
使用 4 進程、Gevent 啟動 Flask 實例。
瀏覽器訪問 127.0.0.1:8000 ,得到如下響應(yīng):
{"code":1,"content":"Hello CyberDB!"}
參考信息
CyberDB 源碼: https://github.com/Cyberbolt/CyberDB
總結(jié)
通過此例,你可以把 CyberDB 部署到更復(fù)雜的 Web 環(huán)境中,充分享受內(nèi)存的低延遲特性。CyberDB 的核心是以 Pythonic 的方式編程,你可以在任何 Python 代碼中將 CyberDB 作為內(nèi)存數(shù)據(jù)庫。
作者簡介:
Cyberbolt:一個自由的 Python 開發(fā)者。