건조 제품 丨 시계열 데이터베이스 DolphinDB와 Druid 비교 테스트

DolphinDB와 Druid는 모두 분산 분석 시계열 데이터베이스입니다. 전자는 C ++를 사용하여 개발되고 후자는 Java를 사용하여 개발되지만 아키텍처, 기능 및 응용 프로그램 시나리오 측면에서 공통점이 많습니다. 이 보고서는 SQL 쿼리, 데이터 가져 오기 및 디스크 공간 측면에서 둘의 성능을 비교합니다.

테스트 데이터 세트는 약 300GB의 미국 주식 시장 거래 및 견적 데이터를 사용합니다. 테스트를 통해 다음을 발견했습니다.

  • DolphinDB의 데이터 쓰기 속도는 Druid의 약 30입니다 .
  • DolphinDB의 쿼리 속도는 Druid의 10입니다 .
  • DolphinDB 데이터베이스의 정적 공간 사용량은 Druid보다 80 % 높고 런타임에 사용되는 총 디스크 공간은 Druid보다 약간 적습니다.

1. 시스템 소개

DolphinDB는 C ++로 작성된 분석 분산 시계열 데이터베이스로 스트리밍 데이터 처리 엔진, 병렬 컴퓨팅 엔진 및 분산 컴퓨팅 기능이 내장되어 있습니다. DolphinDB 데이터베이스에는 수평 및 수직 클러스터 확장을 지원하는 내장 분산 파일 시스템이 있습니다. SQL 및 Python과 유사한 스크립팅 언어를 제공하고 SQL을 사용하여 데이터를 처리 할 수있을뿐만 아니라 더 복잡한 메모리 계산을 완료 할 수도 있습니다. 기존 애플리케이션과의 통합을 용이하게하기 위해 일반적으로 사용되는 다른 프로그래밍 언어로 API를 제공합니다. DolphinDB는 수조 개의 데이터를 신속하게 처리 할 수 ​​있으며, 금융 분야의 과거 데이터 분석 모델링 및 실시간 스트리밍 데이터 처리는 물론, 사물 인터넷 분야의 대규모 센서 데이터 처리 및 실시간 분석에서 탁월한 성능을 발휘합니다.

Druid는 Java 언어로 구현 된 OLAP 데이터웨어 하우스로 지연 시간이 짧은 쿼리 및 1 조 수준의 데이터 삽입 및 실시간 스트리밍 데이터 분석에 적합합니다. Druid는 고가용 성과 높은 확장 성을 특징으로하는 분산, SN 아키텍처 및 컬럼 스토리지, 역 인덱스, 비트 맵 인덱스와 같은 핵심 기술을 채택합니다. 동시에 Druid는 여러 언어 인터페이스를 제공하고 일부 SQL을 지원합니다.

2. 시스템 구성

2.1 하드웨어 구성

이 테스트의 하드웨어 구성은 다음과 같습니다.

장비 : DELL OptiPlex 7060

CPU : Inter (R) Core ™ i7-8700 CPU @ 3.20GHz, 6 코어 및 12 스레드

메모리 : 32GB

하드 디스크 : 256GB SSD, 1.8TB Seagate ST2000DM008-2FR102 기계식 하드 디스크

운영 체제 : Ubuntu 16.04 x64

2.2 환경 구성

이번 테스트 환경은 단일 서버 아래의 다중 노드 클러스터입니다. DolphinDB의 데이터 노드 수를 4 개로 설정하고 단일 데이터 노드의 최대 가용 메모리를 4GB로 설정합니다. Druid 노드 수를 오버로드, 브로커, 내역, 코디네이터 및 middleManager 인 5 개로 설정합니다. Druid는 기본적으로 쿼리 결과를 캐시하므로 테스트 중 여러 쿼리를 통한 평균화 방법의 정확성에 영향을 미치므로 쿼리 캐시 기능이 꺼져 있습니다. Druid의 쓰기 성능 테스트에 영향을주지 않기 위해 Druid의 롤업 기능이 비활성화되었습니다. 다른 모든 구성은 기본 구성을 따릅니다.

원본 csv 파일은 HDD에 저장됩니다. 데이터베이스는 SSD에 저장됩니다.

3. 테스트 데이터 세트

이 테스트는 2007 년 8 월 미국 주식 시장 레벨 1의 TAQ 데이터 세트를 사용합니다. TAQ 데이터 세트는 매일 23 개의 csv 파일로 나뉩니다. 단일 파일의 크기는 7.8G에서 19.1G입니다. 전체 데이터 세트의 크기는 약 290G이며 총 데이터는 6,561,693,704 개입니다.

DolphinDB 및 Druid의 테스트 데이터 세트 TAQ에있는 각 필드의 데이터 유형은 다음과 같습니다.

3d62ba9f8bfcd07d604821c8b9ae116b.png

Druid에서 DATE 필드는 타임 스탬프 열로 지정됩니다. 다른 필드는 차원 필드로 사용됩니다.

4. 데이터 파티션 체계

DolphinDB에서는 주식 코드 + 날짜 조합 파티션을 채택하여 주식 코드 범위에 따라 128 개의 파티션과 날짜에 따라 23 개의 파티션으로 나뉩니다.

Druid는 시간 범위 파티션 만 지원하므로 DATE 열을 타임 스탬프 유형으로 지정하고 날짜를 단위로 지정하고 23 개의 파티션으로 나뉩니다.

5. 비교 테스트

데이터베이스 쿼리 성능, I / O 성능 및 디스크 공간 측면에서 DolphinDB와 Druid를 비교했습니다.

5.1 데이터베이스 쿼리 성능

DolphinDB 스크립팅 언어는 SQL 구문을 지원하고 시계열 데이터에 대한 확장 된 기능을 제공합니다. Druid는 쿼리를위한 Json 데이터 형식 기반의 언어를 제공하고 SQL 쿼리를위한 dsql도 제공합니다. 이 테스트는 Druid 자체 dsql을 사용합니다.

TAQ 데이터 세트에 대해 몇 가지 일반적인 SQL 쿼리를 수행했습니다. 우발적 요인이 결과에 미치는 영향을 줄이기 위해이 쿼리 성능 테스트는 각 쿼리 작업에 대해 10 회 수행되었으며 총 시간은 평균화되었으며 시간은 밀리 초 단위였습니다. DolphinDB를 테스트 할 때 서버에서 SQL 문의 실행 시간을 평가하기 위해 timer 문을 사용했습니다. Druid는 쿼리 시간을 출력하는 도구 나 기능을 제공하지 않기 때문에 클라이언트 명령 줄 도구 dsql에서 출력 한 실행 시간을 사용합니다. DolphinDB에 비해 Druid가 반환하는 실행 시간은 쿼리 결과에 대한 전송 및 표시 시간이 더 많습니다. 쿼리에서 반환되는 데이터의 양이 매우 적기 때문에 dsql과 Druid 서버는 동일한 노드에 있으며 영향 시간은 약 1ms입니다. 약 1ms의 시간은 테스트 결론에 영향을 미치지 않으므로 특별한 처리가 수행되지 않습니다.

7 개의 쿼리에 대한 SQL 표현이 다음 표에 나와 있습니다.

335ec03747bcb0a29ef29b3ba22f9372.png

테스트 결과는 아래 표에 나와 있습니다.

e6cc39a3384839a6d9bfcae7df9afd35.png

그 결과 거의 모든 쿼리에서 DolphinDB의 성능이 Druid보다 우수하고, Druid의 속도보다 약 3 ~ 30 배 빠른 것을 알 수 있습니다.

Druid는 타임 스탬프를 기반으로 한 세분화 만 허용하고 DolphinDB는 데이터를 여러 차원에서 분할 할 수 있으므로 TAQ 분할에는 두 차원의 시간 및 주식 코드가 사용되므로 쿼리는 주식 코드에 따라 필터링하거나 그룹화해야합니다. DolphinDB의 장점은 테스트에서 더 분명합니다 (예 : 테스트 1, 3, 6 및 7).

5.2 I / O 성능 테스트

단일 파일 (7.8G)과 여러 파일 (290.8G)을 가져올 때 DolphinDB 및 Druid의 성능을 테스트했습니다. 공정하게 말하면 Druid의 롤업 기능을 사용 중지했습니다. 테스트 결과는 아래 표에 나와 있으며 시간은 초 단위입니다.

69edbf1e57afcf86f9c07079dc34f024.png

같은 상황에서 하나의 파일을 가져올 때 Druid의 가져 오기 시간은 DolphinDB의 16 배 이상입니다. 여러 파일을 가져올 때 DolphinDB는 병렬 가져 오기를 지원하므로 Druid보다 속도가 빠릅니다. 데이터 가져 오기 스크립트는 부록 2를 참조하십시오.

5.3 디스크 공간 테스트

DolphinDB와 Druid로 데이터를 가져온 후 두 데이터 압축률을 비교했습니다. 테스트 결과는 아래 표에 나와 있습니다.

ed803bb15f18c4e6c14f379c5f1c1ac4.png

DolphinDB는 LZ4 압축 알고리즘을 사용하여 열에 저장된 데이터를 빠르게 압축합니다. 압축하기 전에 DolphinDB의 SYMBOL 유형은 사전 인코딩을 사용하여 문자열을 정수로 변환합니다. 데이터 저장 과정에서 Druid는 LZ4 알고리즘을 사용하여 타임 스탬프와 메트릭을 직접 압축하고 사전 인코딩, 비트 맵 인덱스 및 포효하는 비트 맵을 사용하여 차원 필드를 압축합니다. 사전 인코딩을 사용하면 문자열의 저장 공간을 줄일 수 있고 비트 맵 인덱스는 비트 논리 연산을 빠르게 수행 할 수 있으며 비트 맵 인덱스 압축은 저장 공간을 더욱 절약 할 수 있습니다.

이 테스트에서 DolphinDB 데이터베이스가 차지하는 디스크 공간은 Druid보다 약 80 % 더 큽니다. 이 차이를 일으키는 주요 요인은 BID 및 OFR의 두 부동 소수점 필드의 압축 비율이 DolphinDB와 Druid에서 상당히 다르다는 것입니다. DolphinDB에서이 두 필드의 압축률은 20 %이고 Druid에서는 5 %까지 높습니다. 그 이유는 테스트 데이터 세트가 과거 데이터 세트이고 데이터가 날짜와 주식의 두 필드에 따라 정렬 되었기 때문입니다. 단기간에 주식의 가격 변동은 매우 적고 고유 한 견적의 수는 매우 제한적이며 Druid는 비트 맵 압축을 사용하여 매우 좋은 결과를 얻습니다.

Druid 데이터베이스의 압축률이 높고 정적 디스크 공간이 더 작지만 Druid가 실행 중일 때 세그먼트 캐시 디렉토리가 생성되고 총 디스크 공간 점유가 65GB에 도달합니다. DolphinDB는 실행할 때 추가 공간이 필요하지 않지만 총 디스크 공간은 Druid보다 약간 적습니다.

6. 요약

Druid 용 DolphinDB의 성능 이점은 (1) 저장 메커니즘과 파티셔닝 메커니즘의 차이, (2) 개발 언어의 차이 (c ++ 대 자바), (3) 메모리 관리의 차이, ( 4) 알고리즘 구현의 차이 (예 : 정렬 및 해싱).

파티셔닝 측면에서 Druid는 값 파티셔닝, 범위 파티셔닝, 해시 파티셔닝, 목록 파티셔닝을 지원하는 DolphinDB에 비해 유연성이 부족한 시간 유형 범위 파티셔닝 만 지원하며, 각 테이블은 여러 필드를 기반으로 파티셔닝 할 수 있습니다. DolphinDB의 파티션 세분성은 더 세밀하고 데이터 나 쿼리가 특정 노드에 집중되기가 쉽지 않습니다. DolphinDB는 쿼리 중에 더 적은 데이터 블록을 스캔해야하고 응답 시간이 짧고 성능이 더 좋습니다.

성능을 제외하고 DolphinDB는 Druid보다 더 기능적입니다. SQL 지원 측면에서 DolphinDB는 매우 강력한 창 기능 메커니즘을 지원하며 SQL 조인을보다 포괄적으로 지원합니다. 슬라이딩 기능, asof join, window join 및 시계열 데이터에 특화된 DolphinDB를 잘 지원합니다. DolphinDB는 데이터베이스, 프로그래밍 언어 및 분산 컴퓨팅을 통합하며 일반적인 데이터베이스 쿼리 기능 외에도 더 복잡한 메모리 컴퓨팅, 분산 컴퓨팅 및 스트림 컴퓨팅을 지원합니다.

DolphinDB와 Druid도 운영 모드에서 약간 다릅니다. Druid가 세그먼트 캐시를 지운 후 충돌하거나 다시 시작한 후 데이터를 다시로드하고 각 세그먼트를 세그먼트 캐시로 압축 해제 한 다음 쿼리하는 데 많은 시간이 걸리며 효율성이 낮고 캐시가 더 큰 공간을 차지합니다. , 따라서 Druid는 다시 시작할 때 오래 기다려야하며 더 많은 공간이 필요합니다.

부록

부록 1. 환경 구성

(1) DolphinDB 구성

controller.cfg

localSite = localhost : 9919 : ctl9919 
localExecutors = 3 
maxConnections = 128 
maxMemSize = 4 
webWorkerNum = 4 
workerNum = 4 
dfsReplicationFactor = 1 
dfsReplicaReliabilityLevel = 0 
enableDFS = 1 
enableHTTPS = 0

cluster.nodes

localSite, mode 
localhost : 9910 : agent, agent 
localhost : 9921 : DFS_NODE1, datanode 
localhost : 9922 : DFS_NODE2, datanode 
localhost : 9923 : DFS_NODE3, datanode 
localhost : 9924 : DFS_NODE4, datanode

cluster.cfg

maxConnection = 128 
workerNum = 8 
localExecutors = 7 
webWorkerNum = 2 
maxMemSize = 4

agent.cfg

workerNum = 3 
localExecutors = 2 
maxMemSize = 4 
localSite = localhost : 9910 : agent 
controllerSite = localhost : 9919 : ctl9919

(2) 드루이드 구성

_흔한

# Zookeeper 
druid.zk.service.host = zk.host.ip 
druid.zk.paths.base = / druid 
# 메타 데이터 저장소 
druid.metadata.storage.type = mysql 
druid.metadata.storage.connector.connectURI = jdbc : mysql : //db.example.com : 3306 / druid 
# 딥 스토리지 
druid.storage.type = local 
druid.storage.storageDirectory = var / druid / segments 
# 인덱싱 서비스 로그 
druid.indexer.logs.type = file 
druid.indexer. logs.directory = var / druid / indexing-logs

브로커:

Xms24g 
Xmx24g 
XX : MaxDirectMemorySize = 4096m 

# HTTP 서버 스레드 
druid.broker.http.numConnections = 5 
druid.server.http.numThreads = 25 

# 스레드 및 버퍼 처리 
druid.processing.buffer.sizeBytes = 2147483648 
druid.processing.numThreads = 7 

# 쿼리 캐시 
druid.broker.cache.useCache = false 
druid.broker.cache.populateCache = false 

코디네이터 : 
Xms3g 
Xmx3g 내역 

: 
Xms8g 
Xmx8g 

# HTTP 서버 스레드 
druid.server.http.numThreads = 25 

# 스레드 및 버퍼 처리 
druid.processing .buffer.sizeBytes = 2147483648 
druid.processing.numThreads = 7

# 세그먼트 스토리지 
druid.segmentCache.locations = [{ "path": "var / druid / segment-cache", "maxSize": 0}] 
druid.server.maxSize = 130000000000 

druid.historical.cache.useCache = false 
druid. 

history.cache.populateCache = false middleManager : 
Xms64m 
Xmx64m 

# middleManager 당 작업 수 
druid.worker.capacity = 3 

# HTTP 서버 스레드 
druid.server.http.numThreads = 25 

# Peons 
druid.indexer.fork 에서 스레드 및 버퍼 처리 . property.druid.processing.buffer.sizeBytes = 4147483648 
druid.indexer.fork.property.druid.processing.numThreads = 2

초과 적재:

Xms3g 
Xmx3g

부록 2. 데이터 가져 오기 스크립트

DolphinDB 데이터베이스 脚本 :

if (existsDatabase ( "dfs : // TAQ")) 
dropDatabase ( "dfs : // TAQ") 

db = database ( "/ Druid / table", SEQ, 4) 
t = loadTextEx (db, 'table',, " /data/data/TAQ/TAQ20070801.csv ") 
t = select count (*) as ct from t group by symbol 
buckets = cutPoints (exec symbol from t, 128) 
buckets [size (buckets) -1] =`ZZZZZ 
t1 = table (buckets as bucket) 
t1.saveText ( "/ data / data / TAQ / buckets.txt") 

db1 = database ( "", VALUE, 2007.08.01..2007.09.01) 
partition = loadText ( "/ data / data / buckets.txt ") 
파티션 = exec * 파티션 
db2 = database (" ", RANGE, partitions) 
db = database ("dfs : // TAQ ", HIER, [db1, db2])
db.createPartitionedTable (table (100 : 0,`symbol`date`time`bid`ofr`bidsiz`ofrsiz`mode`ex`mmid, [SYMBOL, DATE, SECOND, DOUBLE, DOUBLE, INT, INT, INT, CHAR, SYMBOL]),`quotes,`date`symbol) 

def loadJob () { 
filenames = exec filename from files ( '/ data / data / TAQ') 
db = database ( "dfs : // TAQ") 
filedir = '/ data / data / TAQ ' 
for (fname in filenames) { 
jobId = fname.strReplace ( ". csv", "") 
jobName = jobId  
submitJob (jobId, jobName, loadTextEx {db, "quotes",`date`symbol, filedir +' / '+ fname}) 
} 
} 
loadJob () 
select * from getRecentJobs () 
TAQ = loadTable ( "dfs : // TAQ", "quotes");

드루이드 스크립트 :

{ 
"type": "index", 
"spec": { 
"dataSchema": { 
"dataSource": "TAQ", 
"parser": { 
"type": "string", 
"parseSpec": { 
"format": " csv ", 
"dimensionsSpec ": { 
"dimensions ": [ 
"TIME ", 
"SYMBOL ", 
{"name ":"BID ","type ":"double "}, 
{"name ":"OFR ","type ":"double "}, 
{"name ":"BIDSIZ ","type ":"int "}, 
{"name ":"OFRSIZ ","type ":"int "}, 
"MODE ", 
"EX ", 
"MMID " 
] 
}, 
"timestampSpec ": { 
"column ":"DATE ​​", 
"format ":"yyyyMMdd " 
}, 
"columns ": ["SYMBOL ", 
"DATE ​​", 
"TIME ",  
"BID ",
"OFR ",
"BIDSIZ", 
"OFRSIZ", 
"MODE", 
"EX", 
"MMID"] 
} 
}, 
"metricsSpec": [], 
"granularitySpec": { 
"type": "uniform", 
"segmentGranularity": "day" , 
"queryGranularity": "none", 
"intervals": [ "2007-08-01 / 2007-09-01"], 
"rollup": false 
} 
}, 
"ioConfig": { 
"type": "index", 
"firehose": { 
"type": "local", 
"baseDir": "/ data / data /", 
"filter": "TAQ.csv"
}, 
"appendToExisting": false 
}, 
"tuningConfig": { 
"type": "index", 
"forceExtendableShardSpecs": true 
"targetPartitionSize ": 5000000,
"maxRowsInMemory": 25000, 
} 
} 
}


추천

출처blog.51cto.com/15022783/2577739