[InfluxDB] MySQL과 성능 비교

0. 시작하며

지난 포스팅에서 이론적으로 InfluxDB에 대해 알아보았습니다. 이번 포스팅에선 InfluxDB를 사용해보고 다음 두가지의 조회 속도에 대해 측정을 진행해 보려고 합니다. 

  1. 쿼리레벨 연산과 코드레벨 연산의 조회 성능 비교
    • 프로젝트를 하며 개발했던 API중 시간적 리소스로인해 코드레벨 연산을 그대로 두고 마무리했던 로직을 재현
  2. InfluxDB와 MySQL 성능 비교

직접 Infra부터 설정해 진했지만 간단히 설명하고 넘어가겠습니다!

 

※ 비교 환경

  • infra: AWS EC2 (t2.micro) ubuntu, docker
  • DB: inflxuDB 2.7.4, MySQL8.2 ( data: InfluxDB에서 제공하는 bitcoin price sample data를 활용했습니다. 7788 row)
  • Server: Spring Boot 3.2.1

1. 환경 및 데이터 설정

가장 먼저 AWS EC2를 생성하고 docker를 활용하여 InfluxDB설치를 진행했습니다.

//influxdb 설치
sudo docker run -d --name my_influxdb -p 8086:8086 -v /var/lib/influxdb:/var/lib/influxdb -v /etc/influxdb:/etc/influxdb influxdb

 

또한 ufw 설정과 EC2 보안그룹설정도 진행해 주어야합니다. 이번에 사용될 포트는 22(ssh), 80(http), 8080(server), 3306(MySQL), 8086(InfluxDB) 포트입니다.

 

이제 http://<EC2 IP주소>:8086을 통해InfluxDB GUI환경으로 접속할 수 있습니다. 사용자 id, pw, bucket, org등의 설정을 완료하면 api token이 주어지며 해당 토큰을 꼭 저장해주세요! 이후 다음과 같은 화면을 만날 수 있습니다.

https://docs.influxdata.com/influxdb/cloud/reference/sample-data/#air-sensor-sample-data

 

Sample data | InfluxDB Cloud (TSM) Documentation

Thank you for your feedback! Let us know what we can do better:

docs.influxdata.com

위 페이지에서 InfluxDB가 제공하는 sample data의 이용방법을 보실 수 있습니다. 저는 그 중에서 bitcoin price를 import하여 사용해보겠습니다. 아래 처럼 코드를 붙여 넣고 "example-bucket" 부분을 각자 설정한 bucket 이름으로 설정하면 data가 들어오게됩니다.

 

2. InfluxDB와 Spring Boot 프로젝트의 통신

InfluxDB는 많은 기성 서비스들과의 연결이 장점인 만큼 Spring boot에서도 몇가지 설정으로 통신을 진행할 수 있었습니다. 이 과정에서 InfluxDB Client 라이브러리를 사용했습니다.

 

https://github.com/influxdata/influxdb-client-java/tree/master

 

GitHub - influxdata/influxdb-client-java: InfluxDB 2 JVM Based Clients

InfluxDB 2 JVM Based Clients. Contribute to influxdata/influxdb-client-java development by creating an account on GitHub.

github.com

의존성주입 <gradle>

	implementation "com.influxdb:influxdb-client-java:6.6.0"
	implementation "com.influxdb:flux-dsl:6.10.0"

 

 

 

Config file

@Configuration
public class InfluxDBConfig {
    @Value("${influxdb.url}")
    private String url;
    @Value("${influxdb.token}")
    private String token;
    @Value("${influxdb.org}")
    private String org;

    @Bean
    public InfluxDBClient influxDBClient() {
        return InfluxDBClientFactory.create(url, token.toCharArray(), org);
    }
}

 

application.yml 파일에 url, token, org를 설정하고 influxDB 빈을 생성할때 인자로서 주입해줍니다. 이로써 InfluxDBClient 설정이 끝났습니다. 이제 service 레이어에서 Flux 객체를 활용해 InfluxDB에 쿼리를 보낼 수 있습니다. 다음은 그 예시입니다.

 

    public double getAvgByQuery(AvgRequest avgRequest){
        QueryApi queryApi = influxDBClient.getQueryApi();

        Restrictions restrictions = Restrictions.and(
            Restrictions.measurement().equal("coindesk"),
            Restrictions.tag("code").equal("EUR")
        );

        Instant start = avgRequest.getStartTime().toInstant(ZoneOffset.UTC);
        Instant end = avgRequest.getEndTime().toInstant(ZoneOffset.UTC);

        Flux flux = Flux.from("bitcoin")
            .range(start, end)
            .filter(restrictions)
            .aggregateWindow(9999L, ChronoUnit.DAYS, "mean")
            .yield("mean");
        log.info("query ={}", flux);

        List<FluxTable> tables = queryApi.query(flux.toString());

        double avg = 0;
        for(FluxTable table : tables){
            List<FluxRecord> records = table.getRecords();
            for(FluxRecord record : records){
                avg = (double) record.getValue();
            }
        }
        return avg;
    }
  • Restrictions: Flux객체에서 filter에 해당하는 부분에 활용할 수 있습니다.
  • Flux: InfluxQL에 사용되도록 쿼리를 메소드 체이닝 방식으로 빌드할 수 있습니다. 위의 경우 다음과 같은 조건이 걸리게 됩니다.
    • bitcoin bucket에서
    • start ~ end 범위
    • messurement = coindesk , code = EUR
  • aggregateWindow: 일종의 그룹화로 이해할 수 있습니다. 저는 전체 데이터의 그룹화를위해 9999일 기간으로 묶고 이에대한 mean (평균) 값을 조회했습니다.

이후 queyApi().query()의 인자로 flux의 Stirng형을 인자로 실행하면 List<FluxTable>의 형태로 결과 데이터를 받을 수 있습니다. 위의 경우는 전체 데이터를 그룹화하여서 전체 인자는 1개인 List가 반환됩니다.

 

3.InfluxDB 와 MySQL 조회 성능비교

MySQL과 InfluxDB가 최대한 비슷한 환경을 세팅해보려고 해보겠습니다. 먼저 sample data를 csv형식으로 export하여 mysql로 옮겨보겠습니다.

 

InfluxDB는 여러 방법으로 export할 수 있지만 저는 http 통신 방법을 사용했습니다

curl -H "Accept: application/csv" -H "Authorization: Token [your_token]" --data-urlencode "q=SELECT * FROM [your_measurement]" > [file_name].cs

 

해당 통신이 정상적으로 진행되면 같은 위치에 csv파일이 생기는것을 보실 수 있습니다. 이를 MySQL Workbench를 통해 import해주었습니다.

 

Import 방법⬇

더보기

1. Tavle Data Import Wizard 실행

2. csv 파일 browse

3. 이후 테이블 이름 및 자료형을 설정하면 완료됩니다.

 

주의할점은 InfluxDB는 내부적으로 time을 날짜형식으로 가지고있지 않습니다.. 따라서 Unix time을 위의 날짜형으로 바꿔주어야하는데요 이때 MySQL의 FROM_UNIXTTIME을 사용할 수 있습니다.

 

InfluxDB의 시간 단위가 너무 작아서 10억으로 나누어주어야 시간을 적절한 날짜타입으로 변경할 수 있었습니다.

 

추가로 제가 프로젝트를할때 시간대별 평균을 계산해서 제공하는 API를 개발했었는데요. 이때 코드 레벨에서 많은 연산이 있었어서 아쉬움이 많았습니다. 이번에 InflxuDB를 다시 보며 해당 로직을 재현하여 InfluxDB에서 코드레벨, 쿼리레벨 그리고 MySQL에서 코드레벨, 쿼리레벨의 조회성능을 비교해보고자 했습니다.

 

※ MySQL의 경우 time을 PK, code를 Index로 지정하여 진행했습니다. 또한 단순히 20번의 요청시간에대한 평균값입니다.

 

InfluxDB

  • 일반적인 전체 평균 
    • 코드 레벨 연산: 약 82.45ms
    • 쿼리 레벨 연산: 약 23.7ms
  • 시간대별 평균
    • 코드 레벨 연산 : 약 85.45ms
    • 쿼리 레벨 연산 : 약 30.05ms

MySQL

  • 일반적인 전체 평균 
    • 코드 레벨 연산: 약 102.6ms
    • 쿼리 레벨 연산: 약 30.45ms
  • 시간대별 평균
    • 코드 레벨 연산: 약 103.5ms
    • 쿼리 레벨 연산: 약 35.2ms

전반적으로 쿼리와 코드연산간은 2 ~ 3배가량의 차이를 보여주었습니다. 또한 DB간에도 10 ~ 20%정도의 차이가 발생했습니다. 물론 시계열 데이터인만큼 InfluxDB가 유리할 수 밖에 없는 구조였습니다.

하지만 데이터의 구조에따라 어떤 DB를 쓰는지가 전체 성능에 많은 영향을 미치는것을 알게되었습니다.

무엇보다 DB통신시 쿼리 레벨에서 적절히 필터링하는것이 중요함을 다시한번 느끼게되었습니다.

 


https://nooroongzi.tistory.com/17

 

[K6]부하테스트 진행기

0. 시작하며 https://nooroongzi.tistory.com/16 [InfluxDB] MySQL과 성능 비교 0. 시작하며 지난 포스팅에서 이론적으로 InfluxDB에 대해 알아보았습니다. 이번 포스팅에선 InfluxDB를 사용해보고 다음 두가지의 조

nooroongzi.tistory.com

부하 테스트를 통해 더욱 많은 요청을 기반으로 비교를 진행해 보았습니다

 

 

'DB > InfluxDB' 카테고리의 다른 글

[InfluxDB] InfluxDB 정리  (0) 2023.12.31