본문 바로가기
DBMS

py-ptcc driver를 이용해서 mongodb tpc-c 테스트 하기

by developer's warehouse 2023. 12. 18.

이 글에서는 py-tpcc에 대해서 알아보고, 이를 사용하여 자체 호스팅된 MongoDB에서 TPC-C 테스트를 실행하는 방법에 대해서 알아보도록 하겠습니다.

py-tpcc 몽고디비 tpc-c 테스트 하기 썸네일

1. py-tpcc에 대해서

py-tpcc 프로젝트는 NoSQL 시스템을 위한 TPC-C OLTP 벤치마크의 Python 기반 프레임워크입니다. 이 코드는 원래 브라운 대학교 학생들이 NoSQL 시스템에 관한 대학원 세미나 과정을 위해 작성한 것입니다. 이 프레임워크는 다양한 시스템에 맞게 새로운 드라이버를 작성할 수 있도록 모듈식으로 설계되었습니다.

 

py-tpcc는 python을 이용해서 tpcc 테스트를 할 수 있는 오픈 소스입니다. 이 소스의 README 파일에는 다음과 같이 적혀 있습니다. 아래 README의 내용을 토대로 각 내용에 대해서 분석해 보도록 하겠습니다.

 

README
+ ----------------------------------------------- +
+ Python TPC-C                                    +
+ ----------------------------------------------- +


The basic idea is that you will need to create a new driver file that 
implements the functions defined in "abstractdriver.py". One function will 
load in the tuples into your database for a given table. Then there are five 
separate functions that execute the given transaction based on a set of input 
parameters. All the work for generating the tuples and the input parameters 
for the transactions has been done for you.

Here's what you need to do to get started:

(1) Download the source code from Github:

https://github.com/apavlo/py-tpcc/tree/master/pytpcc

(2) Create a new file in the 'drivers' directory for your system that follows 
the proper naming convention. For example, if your system is 'MongoDB', then 
your new file will be called 'mongodbdriver.py' and that file will contain a 
new class called 'MongodbDriver' (note the capitalization).

(3) Inside your class you will need to implement the required functions of 
defined in AbstractDriver. There is documentation on what these need to do 
also available on Github:

https://github.com/apavlo/py-tpcc/wiki

(3) Try running your system. I would start by defining the configuration file 
that gets returned with by the 'makeDefaultConfig' function in your driver and 
then implement the data loading part first, since that will guide how you 
actually execute the transactions. Using 'MongoDB' as an example again, you 
can print out the driver's configuration dict to a file:

$ python ./tpcc.py --print-config mongodb > mongodb.config

Make any changes you need to 'mongodb.config' (e.g., passwords, hostnames). 
Then test the loader:

$ python ./tpcc.py --no-execute --config=mongodb.config mongodb

You can use the CSV driver if you want to see what the data or transaction 
input parameters will look like. The following command will dump out just the 
input to the driver's functions to files in /tmp/tpcc-*

$ python ./tpcc.py csv

You can also look at my SqliteDriver implementation to get an idea of what 
your transaction implementation functions need to do:

https://github.com/apavlo/py-tpcc/blob/master/pytpcc/drivers/sqlitedriver.py

 

py-tpcc의 기본 아이디어

기본 아이디어는 "abstractdriver.py"에 정의된 함수를 구현하는 새 드라이버 파일을 만들어야 한다는 것입니다.
하나의 함수는 주어진 테이블에 대한 데이터베이스에 튜플을 로드합니다. 그런 다음 랜잭션의 튜플과 입력 매개변수를 생성하는 모든 작업은 완료되었으므로, 이 매개변수를 기반으로 주어진 트랜잭션을 실행하는 별도의 함수 5개를 작성하면 됩니다.

 

현재 pytpcc에 존재하는 drivers들은 다양하게 있는데, RDBMS 류는 sqlite만 존재합니다. sqlite 외에는 cassandra, couchdb, hbase, membase, mongodb, redis, 등이 있습니다.

 

사용 방법 요약

문서상에는 소스를 다운로드 하고, 테스트하길 원하는 db 제품에 맞는 abstractdriver.py에 존재하는 함수를 작성하면 된다고 합니다.

 

(1) 아래 소스를 다운로드 합니다.

https://github.com/mongodb-labs/py-tpcc/tree/master/pytpcc

 

(2) 테스트하려는 DB의 작업에 해당하는 추상 드라이버를 만듭니다.

해당 소스를 만드는 것은 다음과 같습니다.

시스템의 'dirvers' 디렉터리에 적절한 명명 규칙을 따르는 새 파일을 만듭니다.
예를 들어, 시스템이 'MongoDB'라면 새 파일 이름은 'mongodbdriver.py'이며 이 파일에는 'MongodbDriver'라는 새 클래스가 포함됩니다(대문자에 유의하세요).

 

(3) 클래스 내부에서 다음과 같은 필수 함수를 구현해야 합니다.
AbstractDriver의 필수 함수를 구현해야 합니다. 이러한 기능을 구현하는 데 필요한 문서는 다음에 있습니다.

https://github.com/apavlo/py-tpcc/wiki

py-tpcc fork

저의 경우 다른 DB들과의 성능을 비교하기 위해서 pyodbc를 이용해서 dbms들에 테스트를 할 수 있는 python class를 작성할 계획입니다.

먼저 py-tpcc를 내 github repository로 fork합니다. 아래 이미지처럼 Fork를 눌러서 "Create a new fork"를 누르면 쉽게 fork 할 수 있습니다.

 

fork 후에 다운로드 받아서 먼저 Quick Start를 실행해 보도록 하겠습니다.

다운로드는 repository를 clone 합니다.

$ git clone https://github.com/lswhh/py-tpcc
'py-tpcc'에 복제합니다...
remote: Enumerating objects: 985, done.
remote: Counting objects: 100% (37/37), done.
remote: Compressing objects: 100% (32/32), done.
remote: Total 985 (delta 15), reused 14 (delta 5), pack-reused 948
오브젝트를 받는 중: 100% (985/985), 4.79 MiB | 7.04 MiB/s, 완료.
델타를 알아내는 중: 100% (653/653), 완료.

Quick Start

mongodb에 대해서는 아래와 같이 예제와 구현이 완료되어 있습니다. 아래 방법으로 먼저 테스트를 진행해 봅니다.

 

로컬 머신에 이미 MongoDB가 설치되어 있다고 가정하면 다음 명령을 사용하여 이 벤치마크를 테스트할 수 있습니다.

시스템 구성을 파일로 덤프한 다음 해당 파일에 필요한 변경 사항(예: 비밀번호, 호스트 이름)을 적용합니다.

  1. MongoDB를 예로 들면, 드라이버의 구성 dict를 파일에 출력할 수 있습니다
$ python3 ./tpcc.py --print-config mongodb > mongodb.config

 

위의 명령을 수행하면 다음과 같이 pymongo 가 없어서 에러가 납니다.

:~/py-tpcc/pytpcc$ python3 tpcc.py --print-config mongodb > mongodb.config
Traceback (most recent call last):
  File "/home/mongo/py-tpcc/pytpcc/tpcc.py", line 225, in <module>
    driverClass = createDriverClass(args['system'])
  File "/home/mongo/py-tpcc/pytpcc/tpcc.py", line 62, in createDriverClass
    mod = __import__('drivers.%s' % full_name.lower(), globals(), locals(), [full_name])
  File "/home/mongo/py-tpcc/pytpcc/drivers/mongodbdriver.py", line 40, in <module>
    import pymongo
ModuleNotFoundError: No module named 'pymongo'

 

그러므로, pip를 이용해서 pymongo를 설치해 줍니다.

~/py-tpcc/pytpcc$ pip install pymongo
Defaulting to user installation because normal site-packages is not writeable
Collecting pymongo
  Downloading pymongo-4.6.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (677 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 677.1/677.1 KB 6.0 MB/s eta 0:00:00
Collecting dnspython<3.0.0,>=1.16.0
  Downloading dnspython-2.4.2-py3-none-any.whl (300 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 300.4/300.4 KB 9.5 MB/s eta 0:00:00
Installing collected packages: dnspython, pymongo
Successfully installed dnspython-2.4.2 pymongo-4.6.1

 

설치 후 처음 "python3 ./tpcc.py --print-config " 명령을 다시 수행하면 다음과 같이 정상 수행되면서 mongodb.config 파일이 생성됩니다.

 

~/py-tpcc/pytpcc$ python3 tpcc.py --print-config mongodb > mongodb.config
mongo@altibase-KVM:~/py-tpcc/pytpcc$ cat mongodb.config
# MongodbDriver Configuration File
# Created 2023-12-14 09:55:19.778244
[mongodb]

# The mongodb connection string or URI
uri                  = mongodb://localhost:27017

# Database name
name                 = tpcc

# If true, data will be denormalized using MongoDB schema design best practices
denormalize          = True

# If true, transactions will not be used (benchmarking only)
notransactions       =

# If true, all things to update will be fetched via findAndModify
findandmodify        = True

# If true, we will allow secondary reads
secondary_reads      = True

# If true, we will enable retryable writes
retry_writes         = True

# If true, we will perform causal reads
causal_consistency   = True

# If >1 then sharded
shards               = 1

 

  1. 'mongodb.config’에서 필요한 변경사항을 수정합니다 (예: 비밀번호, 호스트네임).
  2. 아래 명령을 수행해서 로더를 테스트합니다
$ python3 ./tpcc.py --no-execute --config=mongodb.config mongodb

 

로더를 테스트 중 아래와 같이 에러가 발생합니다. 아래 에러는 mongodbdriver.py에서 호출한 insert 메서드가 python의 mongodb 라이브러리에 없다는 에러입니다.

pymongo 라이브러리 버전차이로 발생하는 것 같습니다. mongodbcriver.py를 수정해 줘야 니다.

$ python3 ./tpcc.py --no-execute --config=mongodb.config mongodb
2023-12-14 09:58:45,182 [<module>:252] INFO : Initializing TPC-C benchmark using MongodbDriver
2023-12-14 09:58:45,183 [<module>:262] INFO : Loading TPC-C benchmark data using MongodbDriver
Traceback (most recent call last):
  File "/home/mongo/py-tpcc/pytpcc/./tpcc.py", line 272, in <module>
    l.execute()
  File "/home/mongo/py-tpcc/pytpcc/runtime/loader.py", line 65, in execute
    self.loadWarehouse(w_id)
  File "/home/mongo/py-tpcc/pytpcc/runtime/loader.py", line 158, in loadWarehouse
    self.handle.loadFinishDistrict(w_id, d_id)
  File "/home/mongo/py-tpcc/pytpcc/drivers/mongodbdriver.py", line 419, in loadFinishDistrict
    self.database[constants.TABLENAME_ORDERS].insert(self.w_orders.values())
  File "/home/mongo/.local/lib/python3.10/site-packages/pymongo/collection.py", line 3507, in __call__
    raise TypeError(
TypeError: 'Collection' object is not callable. If you meant to call the 'insert' method on a 'Collection' object it is failing because no such method exists.

 

다음과 같이 insert_many로 수정해 주었습니다.

$ git diff
diff --git a/pytpcc/drivers/mongodbdriver.py b/pytpcc/drivers/mongodbdriver.py
index 611483b..bc29d0d 100644
--- a/pytpcc/drivers/mongodbdriver.py
+++ b/pytpcc/drivers/mongodbdriver.py
@@ -416,7 +416,7 @@ class MongodbDriver(AbstractDriver):
     def loadFinishDistrict(self, w_id, d_id):
         if self.denormalize:
             logging.debug("Pushing %d denormalized ORDERS records for WAREHOUSE %d DISTRICT %d into MongoDB", len(self.w_orders), w_id, d_id)
-            self.database[constants.TABLENAME_ORDERS].insert(self.w_orders.values())
+            self.database[constants.TABLENAME_ORDERS].insert_many(self.w_orders.values())
             self.w_orders.clear()
         ## IF

 

수정 완료후 tpcc database를 삭제하고 load 명령을 재수행 합니다.

:~/py-tpcc/pytpcc$ python3 ./tpcc.py --no-execute --config=mongodb.config mongodb
2023-12-14 16:13:25,492 [<module>:252] INFO : Initializing TPC-C benchmark using MongodbDriver
2023-12-14 16:13:25,492 [<module>:262] INFO : Loading TPC-C benchmark data using MongodbDriver
Traceback (most recent call last):
  File "/home/mongo/py-tpcc/pytpcc/./tpcc.py", line 272, in <module>
    l.execute()
  File "/home/mongo/py-tpcc/pytpcc/runtime/loader.py", line 65, in execute
    self.loadWarehouse(w_id)
  File "/home/mongo/py-tpcc/pytpcc/runtime/loader.py", line 158, in loadWarehouse
    self.handle.loadFinishDistrict(w_id, d_id)
  File "/home/mongo/py-tpcc/pytpcc/drivers/mongodbdriver.py", line 419, in loadFinishDistrict
    self.database[constants.TABLENAME_ORDERS].insert_one(self.w_orders.values())
  File "/home/mongo/.local/lib/python3.10/site-packages/pymongo/collection.py", line 663, in insert_one
    common.validate_is_document_type("document", document)
  File "/home/mongo/.local/lib/python3.10/site-packages/pymongo/common.py", line 552, in validate_is_document_type
    raise TypeError(
TypeError: document must be an instance of dict, bson.son.SON, bson.raw_bson.RawBSONDocument, or a type that inherits from collections.MutableMapping

 

다음과 같이 데이터 로드테스트가 정상적으로 완료됩니다.

~/py-tpcc/pytpcc$ python3 ./tpcc.py --no-execute --config=mongodb.config mongodb
2023-12-14 16:18:53,914 [<module>:252] INFO : Initializing TPC-C benchmark using MongodbDriver
2023-12-14 16:18:53,914 [<module>:262] INFO : Loading TPC-C benchmark data using MongodbDriver
~/py-tpcc/pytpcc$

 

no-execute로 데이터 로드 테스트가 동작하는 것을 확인하면 실제 테스트를 하기 위해서 아래 명령을 수행합니다.

$ python3 tpcc.py --config=mongodb.config mongodb

 

그런데, 다시 아래와 같은 에러가 발생합니다. 에러 메시지를 확인해 보면 Transaction numbers가 mongos나 replica set member에게만 허용된다는 트랜잭션 관련 에러로 보입니다.

2023-12-14 16:54:06,902 [run_transaction:1099] ERROR: Failed with unknown OperationFailure: 20
Failed with unknown OperationFailure: 20
{'ok': 0.0, 'errmsg': 'Transaction numbers are only allowed on a replica set member or mongos', 'code': 20, 'codeName': 'IllegalOperation'}
2023-12-14 16:54:06,902 [execute:072] WARNING: Failed to execute Transaction 'NEW_ORDER': Transaction numbers are only allowed on a replica set member or mongos, full error: {'ok': 0.0, 'errmsg': 'Transaction numbers are only allowed on a replica set member or mongos', 'code': 20, 'codeName': 'IllegalOperation'}

 

standalone mongodb를 replica set으로 변경하기

아래 링크에 정리된 내용을로 어렵지 않게 standalone mongodb를 primary만 갖는 replica set으로 변경할 수 있습니다.

https://2story.org/entry/몽고DB-standalone-to-replica-sets

 

몽고DB standalone to replica sets

우분투 22.04에 몽고DB를 standalone으로 설치했습니다. 몇 가지 간단한 테스트를 하고, 트랜잭션을 테스트해보려 하는데 에러가 나와서 확인해 보니, 몽고DB에서 트랜잭션은 분산트랜잭션만 가능하

2story.org

이렇게 변경하고 나면 아래와 같이 tpcc 테스트가 완료됩니다. 결과 화면이 줄이 안 맞는 측면이 있는데, 이는 수정해서 봐야 할 듯합니다.

$  python3 ./tpcc.py --config=mongodb.config mongodb
2023-12-18 16:21:38,941 [<module>:252] INFO : Initializing TPC-C benchmark using MongodbDriver
2023-12-18 16:21:38,942 [<module>:262] INFO : Loading TPC-C benchmark data using MongodbDriver
2023-12-18 16:28:37,642 [<module>:289] INFO : Final Results
2023-12-18 16:28:37,642 [<module>:290] INFO : Threads: 1
{'PAYMENT': 2197, 'NEW_ORDER': 2395, 'ORDER_STATUS': 197, 'STOCK_LEVEL': 202, 'DELIVERY': 205}
{'DELIVERY': {'latency': {'min': 33.71286392211914, 'max': 46.92673683166504, 'p50': 36.481618881225586, 'p75': 37.46747970581055, 'p90': 38.625240325927734, 'p95': 39.57653045654297, 'p99': 43.908119201660156}, 'total': 205}, 'NEW_ORDER': {'latency': {'min': 10.593414306640625, 'max': 31.412601470947266, 'p50': 13.67044448852539, 'p75': 14.827966690063477, 'p90': 17.530202865600586, 'p95': 21.417856216430664, 'p99': 24.833202362060547}, 'total': 2395}, 'ORDER_STATUS': {'latency': {'min': 5.359411239624023, 'max': 19.825458526611328, 'p50': 6.104469299316406, 'p75': 6.32166862487793, 'p90': 8.294105529785156, 'p95': 10.260343551635742, 'p99': 14.682531356811523}, 'total': 197}, 'PAYMENT': {'latency': {'min': 5.795478820800781, 'max': 13.067007064819336, 'p50': 6.560087203979492, 'p75': 6.777286529541016, 'p90': 7.121562957763672, 'p95': 7.534027099609375, 'p99': 9.506464004516602}, 'total': 2197}, 'STOCK_LEVEL': {'latency': {'min': 5.147457122802734, 'max': 22.341489791870117, 'p50': 9.395599365234375, 'p75': 10.259866714477539, 'p90': 11.68370246887207, 'p95': 13.335227966308594, 'p99': 19.70982551574707}, 'total': 202}, 'tpmc': 2394.599891778432, 'denorm': True, 'duration': 60.01002526283264, 'warehouses': 4, 'date': '2023-12-18 16:28:37', 'threads': 1, 'txn': True, 'batch_writes': True, 'find_and_modify': True, 'read_preference': 'nearest', 'write_concern': 1, 'causal': True, 'all_in_one_txn': True, 'retry_writes': True, 'read_concern': 'majority', 'total_retries': 0, 'total': 5196, 'aborts': 22}
2023-12-18 16:28:37,670 [<module>:291] INFO : b'\n========================================================================================================================================================================================================\nData Loading Time: 358 seconds\n\nExecution Results after 60 seconds\n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n                  Complete        Time (s)       Percentage      Retries         minLatMs        p50             p75             p90             p95             p99             maxLatMs        Aborts          \n  DELIVERY        205                 7.525        3.95           0,0             33.71            36.48           37.47           38.63           39.58           43.91           46.93          0               \n  NEW_ORDER       2395               34.182       46.09           0,0             10.59            13.67           14.83           17.53           21.42           24.83           31.41          22              \n  ORDER_STATUS    197                 1.290        3.79           0,0              5.36             6.10            6.32            8.29           10.26           14.68           19.83          0               \n  PAYMENT         2197               14.650       42.28           0,0              5.80             6.56            6.78            7.12            7.53            9.51           13.07          0               \n  STOCK_LEVEL     202                 1.777        3.89           0,0              5.15             9.40           10.26           11.68           13.34           19.71           22.34          0               \n--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------\n  TOTAL           5196                  59.424                                                                                                                                                                    \n2023-12-18 16:28:37 TpmC for denorm 1 thr with txn 4 WH: 2395 2395 total 60 durSec, batch on 0 retries 0.0% with fnM nearest p50  13.67 p75  14.83 p90  17.53 p95  21.42 p99  24.83 max  31.41 WC WriteConcern(w=1) causal true 10in1 true retry true 5196 22'

 

그 외 tpcc 테스트 방법

위의 명령은 client1개로 테스트 하는 명령으로, 여러개의 client를 실행하기 위해서는 아래와 같은 명령으로 수행해야합니다. 

아래 명령을 통해서 데이터를 warehouses 1000사이즈로 100개의 클라이언트를 동작시킬 수 있습니다. 

python3 tpcc.py --config mconfig --warehouses 1000 --clients=100 mongodb

마지막으로 SQL을 사용하는 dbms에 py-tpcc를 테스트하기 위해서는 다음 링크를 통해서 수정할 수 있습니다.

  1. 트랜잭션 구현 함수가 어떻게 작동해야 하는지 알아보려면 SqliteDriver 구현을 참조할 수 있습니다.

몽고 DB에 py-tpcc가 동작하는 것을 확인했으니, 이제 unixodbc를 통해서 일반 sql을 지원하는 DBMS의 tpcc 테스트를 만들어보아야겠습니다.

facebook twitter kakaoTalk kakaostory naver band shareLink