2022-04-18 13:57:14 Cyberbolt
作为基于 Python 的内存数据库,CyberDB 的表现如何呢?本文主要测试 CyberDB 和 Redis 在 Python Web 中的性能表现。
由于 CyberDB 中 proxy 的 connect 方法会检测连接是否有效,为了确保测试的公平性,我们将使用 redis 的 ping 方法与之对应。
文章将采用 Gunicorn 3进程 + Gevent 协程的方法测试。环境: Python 3.8.12, PyPy 7.3.7
本项目的目录结构为
. ├── app.py ├── app_redis.py ├── cyberdb_init.py ├── cyberdb_serve.py ├── redis_init.py └── requirements.txt
每个文件的内容如下
app.py
import cyberdb from flask import Flask, g client = cyberdb.connect( host='127.0.0.1', port=9980, password='hWjYvVdqRC' ) app = Flask(__name__) @app.before_request def before_request(): g.proxy = client.get_proxy() g.proxy.connect() @app.get("/") def hello_world(): 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)
app_redis.py
import redis from flask import Flask, g rdp = redis.ConnectionPool(host='127.0.0.1', port=6379, decode_responses=True) r = redis.StrictRedis(connection_pool=rdp) app = Flask(__name__) @app.before_request def before_request(): r.ping() g.r = r @app.get("/") def hello_world(): return { 'code': 1, 'content': g.r['content'] } if __name__ == '__main__': app.run(host='127.0.0.1', port=8000, debug=True)
cyberdb_init.py
import time import cyberdb db = cyberdb.Server() db.start(host='127.0.0.1', port=9980, password='123456') time.sleep(3) client = cyberdb.connect(host='127.0.0.1', port=9980, password='123456') with client.get_proxy() as proxy: proxy.create_cyberdict('centre') centre = proxy.get_cyberdict('centre') centre['content'] = 'Hello CyberDB!' db.save_db('data.cdb')
cyberdb_serve.py
import cyberdb def main(): db = cyberdb.Server() db.load_db('data.cdb') db.set_backup('data.cdb', cycle=300) db.run( host='127.0.0.1', port=9980, password='hWjYvVdqRC', max_con=10000, print_log=False ) if __name__ == '__main__': main()
redis_init.py
import redis r = redis.Redis(host='127.0.0.1', port=6379, decode_responses=True) r.set('content', 'Hello CyberDB!')
requirements.txt
APScheduler==3.9.1
async-timeout==4.0.2
backports.zoneinfo==0.2.1
cffi==1.14.6
click==8.1.2
CyberDB==0.9.1
Deprecated==1.2.13
Flask==2.1.1
gevent==21.12.0
greenlet==0.4.13
gunicorn==20.1.0
hpy==0.0.3
importlib-metadata==4.11.3
itsdangerous==2.1.2
Jinja2==3.1.1
MarkupSafe==2.1.1
obj-encrypt==0.7.0
packaging==21.3
pycryptodome==3.14.1
pyparsing==3.0.8
pytz==2022.1
pytz-deprecation-shim==0.1.0.post0
readline==6.2.4.1
redis==4.2.2
six==1.16.0
tzdata==2022.1
tzlocal==4.2
Werkzeug==2.1.1
wrapt==1.14.0
zipp==3.8.0
zope.event==4.5.0
zope.interface==5.4.0
测试条件: 自己的环境中拥有 Redis 和 wrk 。
测试步骤:
(注:本文不是 Python 的基础教程,如果你不了解虚拟环境,请查询相关文档的操作)
1.创建并激活虚拟环境,安装 requirements.txt 中的依赖后,新建终端,运行 python cyberdb_init.py
初始化 CyberDB 的表结构,并运行 python cyberdb_serve.py
以开启 CyberDB 服务器。
2.并在另一个终端运行 redis-server
开启 Redis 服务器。在激活的虚拟环境中运行 python redis_init.py
初始化 Redis 的表结构。
3.运行 gunicorn -w 3 -b 127.0.0.1:8000 -k gevent app:app
(Flask 运行 CyberDB),之后使用 wrk -t8 -c100 -d120s --latency http://127.0.0.1:8000
测试。结果如下:
Running 2m test @ http://127.0.0.1:8000 8 threads and 100 connections Thread Stats Avg Stdev Max +/- Stdev Latency 24.49ms 12.17ms 310.04ms 86.68% Req/Sec 505.40 124.64 1.28k 77.15% Latency Distribution 50% 19.95ms 75% 29.53ms 90% 38.15ms 99% 66.11ms 482884 requests in 2.00m, 86.58MB read Requests/sec: 4020.84 Transfer/sec: 738.20KB
4.运行 gunicorn -w 3 -b 127.0.0.1:8000 -k gevent app_redis:app
(Flask 运行 Redis),之后使用 wrk -t8 -c100 -d120s --latency http://127.0.0.1:8000
测试。结果如下:
Running 2m test @ http://127.0.0.1:8000
8 threads and 100 connections
Thread Stats Avg Stdev Max +/- Stdev
Latency 22.59ms 14.58ms 697.21ms 95.14%
Req/Sec 549.22 85.09 1.08k 78.60%
Latency Distribution
50% 21.22ms
75% 25.28ms
90% 29.66ms
99% 54.46ms
524279 requests in 2.00m, 94.00MB read
Requests/sec: 4365.66
Transfer/sec: 801.51KB
本测试中,CyberDB 的结果为 4020.84 HPS,Redis 的结果为 4365.66 HPS,两者在同一水平。
该结果并不令人惊讶,CyberDB 和 redis-py 都是基于 socket 开发的接口,两者服务端也均为单线程。CyberDB 所依赖的 Python 字典和列表,与 Redis 相同,都是由 C 开发。
两者最大的区别是,CyberDB 原生基于 Python,你可以像使用字典和列表一样使用 CyberDB;Redis-py 只是 Python 中操作 Redis 的接口。