在多数金融机构中,在线事务处理(OLTP)通常依赖于静态或不频繁更新的数据,这类数据也被称为参考数据。参考数据源并不总是需要ACID事务能力,而是需要支持基于简单数据访问模式的快速读取查询,以及事件驱动架构以确保目标系统保持最新状态。NoSQL数据库因其特性成为满足这些需求的理想选择,而AWS等云平台则提供了托管且高度可靠的数据生态系统。
本文中,我并不打算评断哪种AWS的NoSQL数据库更优,因为“更好的数据库”这一概念仅存在于特定目的的上下文中。我将分享一个编码实验室,用于评估AWS托管的NoSQL数据库,如DynamoDB、Cassandra、Redis和MongoDB的性能。
性能测试
I will start by defining the performance test case, which will concurrently insert a JSON payload 200 times and then read it 200 times.
JSON负载
在base_db.py中的base
/parent
类实现了测试案例逻辑,即执行10个并发线程来创建和读取200条记录。
#imports
.....
class BaseDB:
def __init__(self, file_name='instrument.json', threads=10, records=20):
...................................
def execute(self):
create_threads = []
for i in range(self.num_threads):
thread = threading.Thread(
target=self.create_records, args=(i,))
create_threads.append(thread)
thread.start()
for thread in create_threads:
thread.join()
read_threads = []
for i in range(self.num_threads):
thread = threading.Thread(target=self.read_records, args=(i,))
read_threads.append(thread)
thread.start()
for thread in read_threads:
thread.join()
self.print_stats()
每个线程分别在create_records
和read_records
中执行写入/读取操作。注意,这些函数并不包含任何特定于数据库的逻辑,而是用于衡量每次读写执行的性能。
def create_records(self, thread_id):
for i in range(1, self.num_records + 1):
key = int(thread_id * 100 + i)
start_time = time.time()
self.create_record(key)
end_time = time.time()
execution_time = end_time - start_time
self.performance_data[key] = {'Create Time': execution_time}
def read_records(self, thread_id):
for key in self.performance_data.keys():
start_time = time.time()
self.read_record(key)
end_time = time.time()
execution_time = end_time - start_time
self.performance_data[key]['Read Time'] = execution_time
一旦测试用例被执行,print_stats
函数将打印执行指标,如读写均值和标准差(stdev
)值,这些指标反映了数据库读写性能和一致性(较小的stdev
意味着执行性能更稳定)。
def print_stats(self):
if len(self.performance_data) > 0:
# 从性能数据创建Pandas DataFrame
df = pd.DataFrame.from_dict(self.performance_data, orient='index')
if not df.empty:
df.sort_index(inplace=True)
# 计算每列的均值和标准差
create_mean = statistics.mean(df['Create Time'])
read_mean = statistics.mean(df['Read Time'])
create_stdev = statistics.stdev(df['Create Time'])
read_stdev = statistics.stdev(df['Read Time'])
print("Performance Data:")
print(df)
print(f"Create Time mean: {create_mean}, stdev: {create_stdev}")
print(f"Read Time mean: {read_mean}, stdev: {read_stdev}")
NoSQL代码
与支持标准SQL的关系型数据库不同,每个NoSQL数据库都有自己的SDK。针对每个NoSQL数据库的子测试用例类仅需实现一个构造函数和create_record/read_record
函数,这些函数包含专有数据库SDK,用于在几行代码内建立数据库连接并进行记录的创建/读取。
DynamoDB测试用例
import boto3
from base_db import BaseDB
class DynamoDB (BaseDB):
def __init__(self, file_name='instrument.json', threads=10, records=20):
super().__init__(file_name, threads, records)
dynamodb = boto3.resource('dynamodb', region_name='us-east-1')
table_name = 'Instruments'
self.table = dynamodb.Table(table_name)
def create_record(self, key):
item = {
'key': key,
'data': self.json_data
}
self.table.put_item(Item=item)
def read_record(self, key):
self.table.get_item(Key={'key': key})
if __name__ == "__main__":
DynamoDB().execute()
AWS设置
要在AWS账户中执行这些性能测试用例,应遵循以下步骤:
- 创建一个具有访问所需AWS数据服务权限的EC2 IAM角色。
- 启动一个EC2实例并分配新创建的IAM角色。
- 创建每个NoSQL数据库实例。
IAM角色
DynamoDB表
Cassandra键空间/表
请注意,数据库主机和凭证在mongo_db.py和redis_db.py模块中被硬编码并移除,需要更新为您的AWS账户对应的数据库连接设置。为了连接DynamoDB和Cassandra,我选择暂时使用分配给db_performnace_iam_role
IAM角色的Boto3会话凭证。此代码将在任何AWS东1区域账户中运行,无需任何修改。
class CassandraDB(BaseDB):
def __init__(self, file_name='instrument.json', threads=10, records=20):
super().__init__(file_name=file_name, threads=threads, records=records)
self.json_data = json.dumps(
self.json_data, cls=DecimalEncoder).encode()
# Cassandra键空间配置
contact_points = ['cassandra.us-east-1.amazonaws.com']
keyspace_name = 'db_performance'
ssl_context = SSLContext(PROTOCOL_TLSv1_2)
ssl_context.load_verify_locations('sf-class2-root.crt')
ssl_context.verify_mode = CERT_REQUIRED
boto_session = boto3.Session(region_name="us-east-1")
auth_provider = SigV4AuthProvider(session=boto_session)
cluster = Cluster(contact_points, ssl_context=ssl_context, auth_provider=auth_provider,
port=9142)
self.session = cluster.connect(keyspace=keyspace_name)
连接到EC2实例(我使用了会话管理器),并运行以下Shell脚本来执行这些任务:
- 安装Git。
- 安装Python3。
- 克隆GitHub上的performance_db仓库。
- 安装并激活Python3虚拟环境。
- 安装第三方库/依赖项。
- 执行每个测试案例。
sudo yum install git
sudo yum install python3
git clone https://github.com/dshilman/db_performance.git
sudo git pull
cd db_performance
python3 -m venv venv
source ./venv/bin/activate
sudo python3 -m pip install -r requirements.txt
cd code
sudo python3 -m dynamo_db
sudo python3 -m cassandra_db
sudo python3 -m redis_db
sudo python3 -m mongo_db
您应该会看到前两个测试案例的以下输出:
(venv) sh-5.2$ sudo python3 -m dynamo_db 性能数据: 创建时间 阅读时间 1 0.336909 0.031491 2 0.056884 0.053334 3 0.085881 0.031385 4 0.084940 0.050059 5 0.169012 0.050044 .. … … 916 0.047431 0.041877 917 0.043795 0.024649 918 0.075325 0.035251 919 0.101007 0.068767 920 0.103432 0.037742
[200行 x 2列] 创建时间平均值: 0.0858926808834076, 标准差: 0.07714510154026173 阅读时间平均值: 0.04880355834960937, 标准差: 0.028805479258627295 执行时间: 11.499964714050293 |
(venv) sh-5.2$ sudo python3 -m cassandra_db 性能数据: 创建时间 阅读时间 1 0.024815 0.005986 2 0.008256 0.006927 3 0.008996 0.009810 4 0.005362 0.005892 5 0.010117 0.010308 .. … … 916 0.006234 0.008147 917 0.011564 0.004347 918 0.007857 0.008329 919 0.007260 0.007370 920 0.004654 0.006049
[200行 x 2列] 创建时间平均值: 0.009145524501800537, 标准差: 0.005201661271831082 读取时间平均值: 0.007248317003250122, 标准差: 0.003557610695674452 执行时间: 1.6279327869415283 |
测试结果
DynamoDB | Cassandra | MongoDB | Redis | |
---|---|---|---|---|
Create | mean: 0.0859 stdev: 0.0771 |
mean: 0.0091 stdev: 0.0052 |
mean: 0.0292 std: 0.0764 |
mean: 0.0028 stdev: 0.0049 |
Read | mean: 0.0488 stdev: 0.0288 |
mean: 0.0072 stdev: 0.0036 |
mean: 0.0509 std: 0.0027 |
mean: 0.0012 stdev: 0.0016 |
Exec Time | 11.45 sec | 1.6279 sec | 10.2608 sec | 0.3465 sec |
我的观察
- I was blown away by Cassandra’s fast performance. Cassandra support for SQL allows rich access pattern queries and AWS Keyspaces offer cross-region replication.
- I find DynamoDB’s performance disappointing despite the AWS hype about it. You should try to avoid the cross-partition table scan and thus must use an index for each data access pattern. DynamoDB global tables enable cross-region data replication.
- MongoDB拥有非常简单的SDK,使用起来很有趣,并且对JSON数据类型提供了最佳支持。您可以在嵌套的JSON属性上创建索引并运行复杂查询。随着新的二进制数据格式的出现,MongoDB可能会失去其吸引力。
- Redis的性能惊人地快,然而,归根结底,它即使支持复杂数据类型,也仍然是一个键/值缓存。Redis提供了强大的功能,如流水线和脚本,通过将代码传递给Redis在服务器端执行,进一步提高查询性能。
结论
总之,为企业参考数据平台选择AWS管理的NoSQL数据库取决于您的具体优先级。如果性能和跨区域复制是您的首要关注点,AWS Cassandra无疑是明显的赢家。DynamoDB与Lambda和Kinesis等其他AWS服务集成良好,因此是AWS原生或无服务器架构的绝佳选择。对于需要对JSON数据类型提供强大支持的应用程序,MongoDB领先。然而,如果您的重点是快速查找或高可用性的会话管理,Redis证明是一个极好的选项。最终,决策应符合您组织的独特需求。
一如既往,您可以在本文前面提到的GitHub仓库中找到代码(参见上文的Shell脚本任务#3)。如果您在运行此代码或配置AWS方面需要帮助,请随时联系我。
Source:
https://dzone.com/articles/aws-nosql-performance-lab-using-python