대부분의 금융 회사에서 온라인 거래 처리(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 Keyspace/Table
DB 호스트와 자격 증명이 mongo_db.py 및 redis_db.py 모듈에서 하드코딩되어 제거되었으며 AWS 계정에 해당하는 데이터베이스 연결 설정으로 업데이트해야 합니다. DynamoDB와 Cassandra에 연결하기 위해 db_performnace_iam_role
IAM 역할에 일시적으로 할당된 Boto3 세션 자격 증명을 사용하기로 선택했습니다. 이 코드는 동부 1 리전의 어떤 AWS 계정에서든 수정 없이 실행됩니다.
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 Keyspaces 구성
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 인스턴스에 연결하고(세션 관리자를 사용했음), 다음 쉘 스크립트를 실행하여 이러한 작업을 수행합니다:
- 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 성능 데이터: Create Time Read Time 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 rows x 2 columns] Create Time 평균: 0.009145524501800537, 표준편차: 0.005201661271831082 Read Time 평균: 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 저장소에서 코드를 찾을 수 있습니다(위의 쉘 스크립트 작업 #3 참조). 이 코드를 실행하거나 AWS 설정에 대한 도움이 필요하시면 언제든지 연락주세요.
Source:
https://dzone.com/articles/aws-nosql-performance-lab-using-python