본문 바로가기
SingleStoreDB/사례연구

[사례 연구, Dzone] 시계열, 실시간 및 그 이상을 위한 SingleStore

by 에이플랫폼 [Team SingleStore Korea] 2019. 12. 6.

먼저, 이 게시물은 Eric Hanson이 개발자 웹 사이트인 DZone에 게시한 시계열 데이터에 대한 Webinar 내용이 정리되었습니다. SingleStore의 Eric Hanson은 수십 년의 경험이 있는 수석 데이터 전문가입니다. Eric은 과거 기존 데이터베이스의 한계를 확장 가능한 SQL로 어떻게 해결할 수 있는지에 대한 설계 관점을 제공합니다. 또한, SingleStore에서 ANSI SQL 트랜잭션에 영향을 주지 않으면서 시계열 및 빅데이터 분석 워크로드를 처리하는 방법을 보여줍니다.

링크를 통해 DZone에 게시된 Webinar를 보실 수 있습니다.


​시계열 데이터는 기업이 보유한 데이터와 향후 얻을 수 있는 데이터에서 더 많은 가치를 얻고자 함에 따라 점점 더 많은 관심을 끌고 있습니다. SingleStore는 세계에서 가장 빠른 데이터베이스로, 경쟁 데이터베이스보다 일반적으로 10배 빠르고 비용 효율이 3배 더 높습니다. SingleStore는 스키마와 ANSI SQL 호환성을 갖춘 정형 데이터와 반정형 데이터를 지원하는 확장 가능한 관계형 데이터베이스입니다.

 

SingleStore에는 시계열 데이터를 지원하는 기능이 있습니다. 시계열 데이터를 위한 주요 강점으로는 요구되는 데이터량에 대한 수집 처리와 이 데이터에 대한 빠른 수집 속도 그리고 매우 빠른 쿼리 속도와 쿼리에 대한 높은 동시성이 있습니다.

오늘날, 시계열과 관련한 요구 사항이 많은 주요 산업으로는 에너지 및 유틸리티, 금융 서비스, 미디어 및 통신, 그리고 첨단 기술 분야가 있습니다. 모든 산업이 SingleStore를 사용하는 것은 아니지만 이 4가지 산업분야에서 많은 고객을 보유하고 있습니다.

SingleStore 블로그 게시물을 참조하여 시계열 데이터 , 시계열 데이터베이스 선택SingleStore를 사용하여 시계열 함수 구현에 대한 자세한 내용을 확인하실 수 있습니다. 또한 SingleStore에서 제공되는 추가 웨비나 및 이러한 주제를 다루는 O'Reilly 전자 책 다운로드도 있습니다.


SingleStore 소개

SingleStore에는 시계열 워크로드 처리를 위한 광범위하고 강력한 속성이 있습니다. 아래의 차트에서 SingleStore가 수많은 데이터 기술과 연결되어 있음을 알 수 있습니다. 응용 프로그램, BI(비즈니스 인텔리전스)도구 및 임시 쿼리(Ad hoc Qeury)를 지원하며 베어 메탈, 클라우드, 가상 머신, 컨테이너 등 모든 곳에서 실행이 가능합니다. 어디서 실행하든 스케일 아웃, 비공유 아키텍처의 특징을 가지는 SingleStore는 뛰어난 확장성을 보여줍니다.

데이터 수집(Ingest)

SingleStore 데이터베이스는 위의 그림과 같이 다양한 도구들과 에코시스템을 이루고 있습니다. 그림 왼쪽에는 SingleStore가 지원 가능한 주요 데이터 소스가 있습니다. 빅 데이터 로딩과 스트리밍 데이터를 포함하는 데이터 소스로부터 데이터를 매우 빠르게 수집할 수 있는 파이프라인 기능을 제공합니다.

SingleStore는 외부 관계형 데이터베이스에 커넥터를 구축하기 위해 관련 기업들과 파트너 관계를 맺고 있으며 자체 CDC 기능이 있습니다. 또한 Hadoop, HDFS 및 Amazon S3를 포함한 데이터 레이크 연결을 위한 ETL 기능이 포함된 파이프라인을 제공합니다.

매우 편리한 방법으로 데이터를 로드할 수 있습니다. 예를 들어, SingleStore에서 파이프라인으로 Kafka 스트리밍을 사용하여 데이터를 실시간으로 스트리밍할 수 있습니다. 데이터를 Kafka 큐에 덤프 하기만 하면 SingleStore는 이 큐에 접근하며 따로 코드를 작성하지 않고도 실시간으로 데이터를 변환하여 테이블에 로드할 수 있습니다. 또한, Spark와 Informatica와 같은 도구를 사용해 데이터를 변환하여 로드가 가능합니다.

행 저장소 및 열 저장소(Rowstore and Columnstore)

SingleStore는 두 가지 유형의 테이블에 데이터를 저장합니다. 인 메모리기반 행 저장소 테이블과 디스크 스토리지 기반의 열 저장소 테이블입니다.

메모리에 최적화된 행 저장소 테이블은 대기 시간이 매우 짧은 트랜잭션과 소량의 데이터에 대해 빠르게 분석할 때에 사용이 됩니다.

디스크에 최적화된 열 저장소 테이블은 페타 바이트 규모를 지원합니다. 열 저장소는 내장된 압축 기능으로 압축된 데이터에 대한 쓰기, 분석 및 쿼리를 고성능으로 처리합니다.

쿼리 및 리포팅

ANSI SQL을 지원하고 ODBC와 같은 표준 관계형 데이터베이스 연결 기능을 사용하기 때문에 수 많은 응용 프로그램 소프트웨어를 SingleStore에 연결할 수 있습니다. 또한 MySQL 시스템에 연결된 거의 모든 것은 SingleStore에 연결할 수 있습니다.

BI 도구와 대쉬 보드 시스템(Tableau, Looker, Microstrategy)을 SingleStore에 연결할 수 있습니다. 또한, 이미 익숙한 API로 쉽게 SingleStore를 연결하기 위한 사용자 지정 앱을 작성할 수 있습니다.

 


시계열 데이터베이스 SingleStore

이러한 광범위한 기능과 여기서 설명할 특정 기능을 갖춘 SingleStore는 환상적인 시계열 데이터베이스입니다.

SingleStore는 아래 시계열 관련 요구 사항 3가지을 갖추며 시계열 데이터에 환상적인 작업을 수행합니다.

●높은 수집 속도. 초 당 많은 이벤트가 발생하거나 주기적으로 데이터를 매우 빠르게 로드

●짧은 쿼리 지연 시간. 앱, BI 도구, 임시 쿼리 또는 조합에서 필요한 쿼리에 대해 매우 빠른 대화식의 응답 시간을 제공

●동시성 요구. SingleStore 인스턴스 수를 확장하여 필요한 만큼의 동시 사용자를 지원

이러한 요구 사항을 충족하여 시계열 데이터를 처리해야 할 때에 SingleStore가 매우 적합합니다.

ANSI SQL

SingleStore가 지원하는 스키마 및 ANSI SQL은 시계열 데이터를 위해 가장 우선적으로 갖추어야 할 기능입니다. SQL은 필터링, 조인, 집계를 위한 강력한 기능을 많이 지원하며 시계열 데이터를 처리할 때에 이러한 기능이 필요합니다. SQL 지원은 일반적인 용도의 기능과 함께 이를 필요로 하는 시계열에도 적용이 가능합니다.

 

시계열 데이터를 다루는 수많은 데이터베이스와 달리 SingleStore는 트랜잭션을 지원합니다. 트랜잭션 지원을 통해 시계열 데이터가 영구적이고 안전하며 일관되게 처리가 가능하게 합니다.

데이터 수집

사람들은 SingleStore로 시계열 데이터를 처리할 때에 빠르고 쉬운 데이터 수집을 가장 좋은 점이라 말합니다. 데이터 수집은 여러 가지 방법으로 할 수 있습니다. 일반 Insert 문으로 데이터를 삽입하거나 데이터 로드를 위해 벌크 로더 수행과 SingleStore 파이프라인(Pipeline)을 수행할 수 있습니다. 이 중 가장 편리한 방법을 사용하여 빠른 성능을 확인할 수 있습니다.

 

SingleStore 파이프라인에 대해 좀 더 자세한 설명을 드리겠습니다. 파이프라인은 Kafka 큐 또는 Linux 파일 시스템의 파일 폴더, AWS S3 또는 Azure Blob 저장소를 참조하여 생성할 수 있습니다. 그런 다음 파이프라인을 시작하면 Kafka 큐에서 메시지를 직접 로드하거나 사용자가 지정한 파일 폴더에 있는 파일을 직접 로드합니다. 애플리케이션에 페치-실행의 루프는 필요치 않습니다. 파이프라인이 직접 접근하여 이를 처리하기 때문입니다.

표준 인터페이스를 사용하여 Python으로 작성된 외부 스크립트나 원하는 언어를 사용하여 파이프라인으로 데이터를 변환할 수도 있습니다. 필요한 경우 데이터를 변환하여 편리하게 파이프라인을 통해 로드할 수 있습니다.

SingleStore 로더에서는 트랜잭션 일관성을 지원합니다. 파일을 로드할 때에 파일은 모두 로드되거나 모두 로드되지 않을 수 있습니다. 또한, 데이터가 로드되는 대상 테이블에 쿼리를 수행하면 모든 파일을 보거나 전혀 보지 않을 수 있습니다. 이는 Kafka 파이프라인이 정확히 한 번만 로드하는 데이터 스트림 시맨틱을(exactly-once semantics) 지원하기 때문입니다.

SingleStore는 데이터를 매우 빠르게 수집할 수 있습니다. 이것을 충분히 강조하기 위해 아래의 사례를 소개하겠습니다.

우리는 파트너 Intel과 협력하여 Xeon Platinum 단일 서버를 사용할 수 있었습니다. 단일 서버의 사양은 Xeon Platinum 칩 2개, 각각 28코어, 고성능 SSD로 구성되었습니다.

'cluster in a box'로 불리는 클러스터로 두 개의 리프 노드와 하나의 애그리 게이터로 구성하였고 이는 모두 동일한 단일 서버에 설치되었습니다.

그런 다음, 드라이버로 동시에 데이터를 로드하였습니다. insert, update 나 upsert를 동시에 실행하는 많은 병렬 연결을 사용하여 단일 서버에서 초당 285만 행의 insert와 update를 수행할 수 있었습니다.

이 사례에서 놀라운 속도를 보여주었습니다. 또한, 보다 빠르게 데이터를 수집하기 위해 확장해야 하는 경우에는 더 많은 노드를 추가하여 확장할 수 있습니다.

쿼리

SingleStore는 벡터화 및 컴파일을 통한 빠른 쿼리 처리를 지원합니다. 머신 코드로 쿼리를 컴파일합니다. SingleStore가 일반적으로 기존의 행 저장소(Rowstore) 기반 데이터베이스보다 훨씬 빠른 이유에 대해서는 위에서 설명하였습니다. 그 주요 이유 중 하나는 쿼리를 머신 코드로 컴파일하기 때문입니다. 쿼리가 행 저장소 테이블에 액세스하면 기존 데이터베이스처럼 해석되지 않고 코드가 직접 실행됩니다. 또한 시계열 데이터에 매우 유용한 윈도우 기능을 지원하는데 나중에 그것에 대해 자세히 설명하겠습니다.

스토어드프로시저, 사용자 정의 함수와 사용자 정의 집계 함수 등은 확장성을 지원합니다. 이 세 가지 모두 시계열 관리에 유용합니다.

SingleStore는 또한 뛰어난 데이터 압축 기능을 갖추고 있습니다. 시계열 이벤트 데이터는 매우 방대할 수 있으므로 저장 공간을 절약하기 위해 데이터를 압축할 수 있어야 합니다. SingleStore의 열 데이터 압축은 시계열 이벤트를 압축하는데 탁월합니다.

시계열 데이터를 효과적으로 쿼리 하는 방법에 대해 이야기하겠습니다. 윈도우 함수를 사용하면 행 윈도우을 통해 데이터를 집계할 수 있습니다. 파티션 키로 입력 행 세트를 지정해야 합니다. 그런 다음 각 파티션 내에서 순서 또는 정렬 순서를 갖게 됩니다.

윈도우 함수는 파티션 내의 각 행에 대한 결과를 계산하므로 윈도우 함수 결과는 해당 파티션 내의 행의 순서에 따라 다릅니다. 예를 들어, 위의 오른쪽 그림과 같이 전체 블록과 같은 입력 행 집합이 있을 수 있습니다. 시작과 끝 사이의 자주색이 윈도우라는 것을 알 수 있으며 윈도우 시작, 윈도우 끝 그리고 윈도우 내 현재 행에 대한 개념이 있습니다. 이런 윈도우 기능들을 SQL내에서 새로운 확장을 사용하여 SQL로 지정할 수 있습니다.

SingleStore는 다양한 Window 함수를 지원합니다. 순위 함수와 LAG 및 LEAD 와 같은 가치 함수뿐만 아니라 SUM, MEAN, MAX, AVERAGE, COUNT 등과 같은 집계 함수를 지원합니다. 그리고 백분위 수 값을 제공하는 특수 백분위 수 함수가 있습니다.


SingleStore의 시계열 예제

Tick ​​스트림을 기반으로 시계열 응용 프로그램의 간단한 예를 보여 드리겠습니다. 매우 간단한 재무관련 Tick 스트림이 있다고 가정합니다. 여기에는 Tick 이라는 테이블이 있으며 높은 정밀도를 가지는 daytime, daytime(6) 값이 있습니다.

SingleStore는 소수점 이하 6 자리의 daytime 또는 timestamp 유형을 지원합니다. 따라서 마이크로 초까지의 정밀도를 지원합니다. 이는 일부 시계열 응용 프로그램에 필요할 수 있는 고정밀도의 timestamp입니다.

아래의 예제에는 테이블 값에 고정밀도의 timestamp, 주식 기호 및 거래 가격이 있습니다. 이것은 지나치게 단순화되었지만, 이 간단한 예제를 사용하여 앞으로 보여드릴 몇 가지 향후 쿼리에 사용하려 합니다.

시계열 데이터와 관련하여 한 가지 중요한 것은 데이터 평탄화(Data Smoothing)* 입니다. Ticks 스트림이 들어오거나 시계열 이벤트가 나타날 때에 많은 잡음으로 인하여 들쭉 날쭉 한 곡선이 나타나게 됩니다. 이를 데이터 평탄화하여 사용자가 표시하기 쉽고 이해하기 쉽도록 처리하고자 합니다.

이를 SingleStore의 Window 함수로 해결할 수 있습니다. 아래의 예제에 있는 쿼리는 시계열의 마지막 4개 항목에 대한 윈도우 평균을 계산합니다. 이 예제에서는 주식 기호(symbol) 값을 ABC를 조건으로 하여 주식 기호, timestamp, 원래 가격 및 평탄화한 가격을 계산 합니다. 출력 결과를 확인하면 '가격(price)' 필드는 값이 들쑥날쑥 되어 고르게 평탄화되지 않음을 확인할 수 있습니다. '평탄화한 가격(smoothed_price)' 필드는 앞쪽의 세번 째 행(윈도우의 시작)과 현재 행(윈도우의 끝) 사이의 윈도우 평균값입니다.

* 데이터 스무딩(Data Smoothig) : 데이터 세트에서 노이즈를 제거하여 패턴을 식별하기 위한 작업

이렇게 하여 시계열의 마지막 4개 항목에 대한 윈도우 평균을 계산한 평탄화된 데이터를 출력할 수 있습니다. 원하는 방식으로 해당 윈도우를 정의할 수 있습니다. 전체를 윈도우로 설정하거나 앞쪽의 몇 번 째 행(윈도우의 시작)과 현재 행(윈도우의 끝) 또는 현재 행의 앞쪽에서(윈도우의 시작) 현재 행의 뒤쪽(윈도우의 끝)으로 하여 윈도우의 평균을 계산할 수 있습니다.

사람들이 시계열 데이터에 대해 수행하고자 하는 또 다른 중요한 작업은 잘 정의된 시간 버킷에 대해 집계하는 것입니다. 이것을 타임 버킷팅(time bucketing)이라고 합니다. 불규칙한 시계열을 규칙적인 시계열로 변환하고자 합니다. 불규칙한 시계열에는 불규칙적인 간격을 가지는 항목이 있습니다. 그것들은 임의의 간격으로 도착할 수 있으므로, 매 초마다 하나의 항목이 도착하지 않을 수 있습니다. 평균적으로 0.5초마다 하나의 항목이 도착할 수 있지만 이는 포아송 프로세스*(Poisson process)의 도착 시간과 같은 통계 프로세스와 비슷할 수 있습니다.

*포아송 프로세스 : 확률론에서 단위 시간 안에 어떤 사건이 몇 번 발생할 것인지를 표현하는 이산 확률 분포

Ticks 스트림이 도착하는 사이에 몇 초가 걸릴 수 있으며 이를 전환하여 매초마다 한 항목 씩 가져오기로 합니다. 이것은 타임 버킷팅으로 할 수 있습니다. 타임 버킷팅의 또 다른 적용은 고정밀도의 시계열을 낮은 정밀도로 변환하려는 경우입니다. 예를 들어, 초당 하나의 항목이 있고 분당 하나의 항목을 갖도록 변환할 수 있습니다. 시계열의 정밀도를 낮추는 방법을 아래에서 설명하겠습니다.

SingleStore에서 타임 버킷팅을 수행할 수 있는 몇 가지 방법이 있습니다. 첫째는 시간 표현으로 그룹화하는 것입니다. 예를 들어 select ts :> daytime 등의 쿼리입니다. 첫 번째 표현인 ts :> daytime 은 SingleStore의 형 변환입니다. 해당 timestamp를 daytime(6)이 아닌 daytime( )으로 변환합니다. 그것은 1초의 정밀도를 가지게 되며 소수 자리의 초를 갖지 않게 됩니다.

daytime( )으로 변환하고 집계를 취한 다음에 첫 번째 표현식으로 그룹화하고 첫 번째 표현식으로 순서를 지정하는 쿼리를 작성합니다. 이 쿼리는 고정밀도의 시계열을 1초 단위의 시계열로 변환합니다.

두 번째는 사용자 정의 함수(UDF)를 사용하여 타임 버킷팅을 수행할 수도 있습니다. 위의 예제처럼 두 가지 인수를 취하는 타임 버킷 함수를 작성했습니다. 첫 번째 인수는 1초, 1분, 3초 등의 시간 패턴입니다. 정의한 타임 버킷은 별칭을 주어 다른 필드와 식별하고자 하였습니다. 두 번째 인수는 timestamp 입니다.

예제의 쿼리 표현식으로 작업을 수행할 수 있지만 이것은 설명을 위해 지나치게 단순화되었습니다. 타임 버킷팅을 수행하기 위한 사용자 정의 함수 작성법은 SingleStore 블로그에 곧 게시될 예정입니다.


시계열을 위한 SingleStore에 대한 추가 정보

SingleStore는 스케일 아웃, 쿼리 컴파일 및 벡터화를 통해 믿을 수 없을 정도로 높은 성능을 제공하므로 다양한 방법으로 시계열 관련 기술 문제를 해결할 수 있습니다. 시계열 쿼리는 빠르게 실행되며 대규모 워크로드와 대용량 데이터를 처리하도록 확장할 수 있습니다.

또한 일반적인 insert문, upsert문, 로드 또는 파이프라인을 통해 매우 빠른 시계열 이벤트 수집이 가능합니다. 또한 시계열에 적합한 강력한 SQL Window 함수 확장을 지원하며 기본 구현으로 SingleStore에 완전히 내장되어 있습니다. 원하는 경우 시계열 처리에 더 강력한 기능과 유연성을 추가하기 위해 사용자 정의 함수(UDF), 사용자 정의 집계 함수(UDAF) 및 스토어드프로시저(Stored Procedure)를 사용하여 시계열 처리를 조금 더 쉽게 처리할 수 있습니다.

마지막으로 SingleStore는 분산 SQL DBMS의 모든 기능을 제공합니다. 따라서 시계열 응용 프로그램을 구축하려는 경우 시계열에 특정 목적으로 제작된 시계열 데이터베이스를 사용하거나 SingleStore와 같은 범용 데이터베이스를 사용할 수 있습니다.

범용 데이터베이스를 선택하면 SQL 트랜잭션, 백업 및 복원, 전체 클러스터 관리, 행 저장소, 행 저장소의 인덱스, 열 저장소, 동시성, 고가용성과 같은 추가 이점이 많이 있습니다. 트랜잭션적인 범용 응용 프로그램을 처리할 수 ​​있습니다. 데이터 웨어하우스(DW), 데이터 마트(Mart), 운영 데이터 저장소(ODS) 또는 운영 앱에 대한 분석 확장과 같은 분석 애플리케이션을 처리할 수 ​​있습니다.

특정 시계열 데이터베이스에서 수행하기 어려운 외부 조인 및 기타 종류의 작업을 수행할 수 있는 완전한 SQL 기능이 있습니다. 따라서 SingleStore의 일반성은 다양한 애플리케이션 요구를 처리할 수 ​​있습니다. 또한 SingleStore는 강력한 Window 함수와 사용자 정의 확장을 사용하여 시계열 데이터를 실제로 효과적으로 처리할 수 ​​있습니다.


Q & A

Q : PostgreSQL에 시계열 함수를 구현하는 몇 가지 기술이 있습니다. SingleStore의 시계열 함수와 다른 점은 무엇입니까?

A : 가장 큰 차이점은 SingleStore에서 수집 및 대규모 쿼리 시, 보이는 뛰어난 성능입니다. PostgreSQL에 중점을 둔 시스템은 보고 있는 시스템에 따라 스케일 아웃을 제공하지 않을 수 있습니다. 또한 SingleStore에는 메모리 기반의 행 저장소(Rowstore)와 디스크 기반의 열 저장소(Columnstore)가 있습니다. 머신 코드로 쿼리를 컴파일하고 컬럼 쿼리는 벡터화를 사용합니다. PostgreSQL에서 표준 쿼리 처리 작업에서 얻을 수 있는 것보다 고성능의 쿼리 처리 엔진이 있습니다.

 

Q. NoSQL 기반 시계열 구현과 SingleStore가 제공하는 것의 차이점은 무엇입니까?

A : NoSQL 시스템은 시계열을 반드시 지원하는 것은 아니며 완전한 표준 SQL을 지원하지 않습니다. SingleStore에서는 시계열 스타일 쿼리를 처리하는데 유용한 모든 SQL 구문과 Window 함수를 지원합니다.

 

Q. SingleStore에서 수집되는 데이터를 처리하기 위해 처리량을 확장할 수 있는 기술은 무엇입니까?

A : 앞에서 설명드린 바와 같이, 초당 2.85백만 행을 단일 서버에서 처리하는 놀라운 성능을 보여주었습니다. 앞서 설명하였듯이, 스케일 아웃을 지원하기 때문에 그 이상으로 확장해야 할 경우에는 더 많은 서버를 추가하고 데이터를 로드할 수 있습니다.

애그리 게이터(Aggregator) 노드를 추가하여 데이터를 직접 Insert 하는 경우 처리할 수 있는 Insert 률을 높일 수 있습니다. 또한 파이프라인 기능은 리프(Leaf) 노드 레벨에서 완전하게 병렬처리를 합니다. 따라서 파이프라인을 통해 데이터를 수집하려는 경우 클러스터에 더 많은 리프 노드를 추가하여 데이터 처리량을 확장할 수 있습니다.

또한 SingleStore 로더는 뛰어난 성능을 보여줍니다. 6.7 버전 이후부터는 로더에 동적 데이터 압축이 도입되었습니다. 데이터를 로드할 때 해당 작업의 일부로 리프 노드 전체에서 데이터를 섞어야(Reshuffle) 하기 때문입니다.

네트워크에 대역폭이 제한되어 있는 경우 내부 네트워크를 통해 리프 노드 사이를 흐르는 데이터를 압축하는 적응형 데이터 압축 전략이 있습니다. 따라서 노드를 확장하여 데이터를 로드할 때 SingleStore의 성능을 향상시키는데 사용할 수 있는 기술이 많이 있습니다.

SingleStore는 머신 코드로의 컴파일 및 동적 압축과 같은 기술을 통해 데이터 로드의 구현으로 상당히 높은 성능을 보여줍니다.

 

Q. 동시에 사용되는 파이프라인 또는 병렬 파이프라인 수와 관련하여 파이프라인 제한이나 물리적 제한이 있습니까?

A : 클러스터의 용량, 클러스터의 하드웨어 용량 이외의 다른 제한은 없습니다.

February 28, 2019

Eric Hanson


출처: ​https://www.singlestore.com/blog/dzone-webinar-time-series-real-time/

 

DZone Webinar – SingleStore for Time Series, Real Time, and Beyond

Interest in time series data is growing, and SingleStore is a great fit for many time series use cases. If you need to support a high ingest rate, low-latency queries, and/or a high rate of concurrent queries, SingleStore may be a great fit. This DZone web

www.singlestore.com

www.a-platform.biz | info@a-platform.biz