---
author: Cyberbolt
category: 软件开发
comments_data: []
count:
  commentnum: 0
  favtimes: 0
  likes: 0
  sharetimes: 0
  viewnum: 2659
date: '2022-04-04 12:55:00'
editorchoice: false
excerpt: CyberDB，一个基于 Python 字典和列表的内存数据库。
fromurl: https://github.com/LCTT/Articles/pull/14
id: 14430
islctt: false
largepic: /images/p/202204/04/125600vvprv1d98vffbfrv.jpg
permalink: /article-14430-1.html
pic: /images/p/202204/04/125600vvprv1d98vffbfrv.jpg.thumb.jpg
related: []
reviewer: wxy
selector: ''
summary: CyberDB，一个基于 Python 字典和列表的内存数据库。
tags:
- Python
- 内存数据库
- CyberDB
thumb: false
title: Python 内存数据库 CyberDB 使用实例
titlepic: true
translator: ''
updated: '2022-04-04 12:55:00'
---


> 
> CyberDB，一个基于 Python 字典和列表的内存数据库。
> 
> 
> 


![](/images/p/202204/04/125600vvprv1d98vffbfrv.jpg)


### 概括


CyberDB 是一个轻量级的 Python 内存数据库。它旨在利用 Python 内置数据结构字典、列表作数据存储，通过 TCP 套接字高效通信，并提供了数据持久化。该数据库的亮点在于它使用了 Pythonic 的方式编程，你可以像使用字典和列表一样使用 CyberDB。


现在我们把 CyberDB 带到能发挥其作用的地方，在生产环境中将 CyberDB 作为 Flask 的内存数据库，使用 Gunicorn 运行，并实现多进程间的通信。


这篇文章通过一个尽可能精简的 Flask 实例讲解，不会涉及复杂的 Web 知识。核心思路为 CyberDB + Gunicorn + Gevent + Flask（多进程 + 协程），启动一个 CyberDB 服务器，使用 Gunicorn 多进程运行 Flask 实例，每个进程的实例通过 Gevent 运行，进程中使用 CyberDB 客户端连接至内存数据库，由此实现对 CyberDB 数据库的高并发访问。


### 源码解析


文章使用 PyPy 运行，同样适用 CPython。


运行环境: Debian 10, Python 3.8.12, PyPy 7.3.7


此项目的目录结构



```
.
├── app.py
├── cyberdb_init.py
├── cyberdb_serve.py
├── requirements.txt
└── venv

```

我们通过列举每个文件的内容顺序讲解 CyberDB 的核心操作。


#### 文件 requirements.txt



```
CyberDB>=0.7.1
Flask==2.1.1
gevent==21.12.0
gunicorn==20.1.0

```

这是此项目的依赖。这篇文章不是 Python 基础教程，如果你不清楚，请查询相关文档创建虚拟环境 `venv` 目录并安装 `requirements.txt` 中的依赖。


生成 `venv` 目录并安装好依赖后，下面所有操作都在激活的虚拟环境中运行。


#### 文件 cyberdb\_init.py


功能：初始化 CyberDB 的表结构，只在第一次运行时使用，后续不再使用。



```
import time

import cyberdb

db = cyberdb.Server()
# 配置 CyberDB 服务端的 地址、端口、密码。
db.start(host='127.0.0.1', port=9980, password='123456')

# 待服务端启动后，连接 CyberDB 服务端。
time.sleep(3)
client = cyberdb.connect(host='127.0.0.1', port=9980, password='123456')
# 生成 proxy 对象。
with client.get_proxy() as proxy:
    # 创建类型为 CyberDict 的表 centre，并初始化内容。
    proxy.create_cyberdict('centre')
    centre = proxy.get_cyberdict('centre')
    centre['content'] = 'Hello CyberDB!'

# 将 CyberDB 保存至 data.cdb 。
db.save_db('data.cdb')

```

在项目根目录执行



```
python cyberdb_init.py

```

以完成 CyberDB 数据库表的初始化。


它会在 CyberDB 中创建了一个名为 `centre`、类型为 `CyberDict` 的表；初始化 `content` 键的值为 `Hello CyberDB!`；最后将 CyberDB 数据库保存至硬盘（在项目根目录生成了名为 `data.cdb` 的文件）。


#### 文件 cyberdb\_serve.py


功能：运行 CyberDB 服务端。



```
import cyberdb

def main():
    # 后台运行 CyberDB 服务端，设置相关信息。
    db = cyberdb.Server()
    # 从硬盘读取 data.cdb 至 CyberDB。
    db.load_db('data.cdb')
    # 每 300 秒备份一次数据库。
    db.set_backup('data.cdb', cycle=300)
    db.run(
        host='127.0.0.1', # TCP 运行地址
        port=9980, # TCP 监听端口
        password='hWjYvVdqRC', # 数据库连接密码
        max_con=10000, # 最大并发数
        encrypt=True, # 加密通信
        print_log=False # 不打印日志
    )


if __name__ == '__main__':
    main()

```

在项目根目录执行



```
python cyberdb_serve.py

```

以运行 CyberDB 服务端。


此处设置了 `encrypt=True` ，CyberDB 会将 TCP 通信内容使用 AES-256 算法加密。开启 `encrypt=True` 后，CyberDB 仅允许白名单中的 IP 通信，默认白名单为 `['127.0.0.1']`（查看白名单 [设置方法](https://www.cyberlight.xyz/static/cyberdb-chn/API/#cyberdbserver)）。一般，若只需在本地进程间通信，无需开启 `encrypt=True` 和设置白名单，只有远程通信时需要此操作。


#### 文件 [app.py](http://app.py)


功能：运行 Flask 实例和 CyberDB 客户端。



```
import cyberdb
from flask import Flask, g

# 连接 CyberDB 并生成客户端实例。
client = cyberdb.connect(
    host='127.0.0.1', 
    port=9980, 
    password='hWjYvVdqRC',
    # 服务端若加密，客户端必须加密，反之亦然。
    encrypt=True,
    # 每个连接若超过900秒无操作，将舍弃该连接。
    # 连接由连接池智能管理，无需关注细节。
    time_out=900
)

# 创建 Flask 实例，此部分请参考 
# Flask 文档 https://flask.palletsprojects.com/
app = Flask(__name__)

@app.before_request
def before_request():
    # 每次请求执行前生成 proxy 对象。
    g.proxy = client.get_proxy()
    # 从连接池获取连接。
    g.proxy.connect()

@app.get("/")
def hello_world():
    # 从数据库获取 centre 表。
    centre = g.proxy.get_cyberdict('centre')
    
    return {
        'code': 1,
        'content': centre['content']
    }

@app.teardown_request
def teardown_request(error):
    # 每次请求执行后归还连接至连接池。
    g.proxy.close()

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8000)

```

该模块会在每次请求执行前（`before_request()`）使用 `client.get_proxy()` 获取 `proxy` 对象，每个获取的 `proxy` 对象可以绑定一个 TCP 连接，此处使用 `proxy.connect()` 从连接池获取连接。视图函数 `hello_world()` 中，由 `proxy` 获取的对象 `centre`，与 `proxy` 共用同一个连接，`proxy` 的连接释放后，`centre` 也会失去连接。在每次请求后（`teardown_request()`）使用 `proxy.close()` 方法释放 `proxy` 绑定的连接，归还至连接池。


`cyberdb.connect` 的 `time_out` 参数表示连接池中每个连接的超时时间，此处每个连接超过 900 秒无操作将被舍弃。若不设置该参数，连接池的每个连接会维持到失效为止。


#### 使用 Gunicorn 运行 Flask 实例


Gunicorn 是一个用于 UNIX 的 Python WSGI HTTP 服务器，通常在生产环境使用，可以利用多核 CPU 。


Gevent 是一个基于协程的 Python 网络库。Gevent 会更改 CyberDB 客户端的底层套接字通信，使之支持协程。


在项目根目录运行



```
gunicorn -w 4 -b 127.0.0.1:8000 -k gevent app:app

```

使用 4 进程、Gevent 启动 Flask 实例。


浏览器访问 `127.0.0.1:8000` ，得到如下响应：



```
{"code":1,"content":"Hello CyberDB!"}

```

### 参考信息


CyberDB 源码: <https://github.com/Cyberbolt/CyberDB>


### 总结


通过此例，你可以把 CyberDB 部署到更复杂的 Web 环境中，充分享受内存的低延迟特性。CyberDB 的核心是以 Pythonic 的方式编程，你可以在任何 Python 代码中将 CyberDB 作为内存数据库。




---


作者简介：


Cyberbolt：一个自由的 Python 开发者。




---


via: <https://www.cyberlight.xyz/static/cyberdb-chn/tutorial/flask/>


作者：[Cyberbolt](https://www.zhihu.com/people/cyberbolt) 编辑：[wxy](https://github.com/wxy)


本文由贡献者投稿至 [Linux 中国公开投稿计划](https://github.com/LCTT/Articles/)，采用 [CC-BY-SA 协议](https://creativecommons.org/licenses/by-sa/4.0/deed.zh) 发布，[Linux中国](https://linux.cn/) 荣誉推出