본문 바로가기

문돌이 존버/ELK 스터디

Django MySQL 멀티 테이블 데이터 처리를 위한 Logstash conf 파일 설정

반응형

이번 글에서는 지난 Mac 버전 장고, MySQL, 로그스태시 연동 튜토리얼을 디벨롭하여 저의 상황에 맞는 커스터마이징을 진행해보겠습니다. 저는 MySQL에 테이블이 2개 생성되어 있고, 외래키(Foreignkey) 설정 및 1:N 관계를 가지고 있습니다. 테이블 2개에 적재된 모든 데이터를 한 번에 로그스태시에 전달해야 하고, 키바나 시각화에 하나하나 이용해야 합니다. 

이와 관련된 해결 방법으로 여러 가지를 살펴봤는데요. 먼저, 처음에 시도한 것은 아래와 같고 참고한 사이트는 한 외국인의 블로그입니다. jdbc input을 원하는 테이블만큼 여러 개 생성하고 각 쿼리문과 타입을 다르게 설정한 것인데요. 이후에 filter를 통해 타입에 따라 구분하고 output에서도 index로 어떤 타입인지 표시를 했습니다. 

input {
  jdbc {
    jdbc_driver_library => "/connector 다운로드 경로/mysql-connector-java-8.0.21.jar"
    jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
    jdbc_connection_string => "jdbc:mysql://localhost:3306/monitor?useTimezone=true&useLegacyDatetimeCode=false&serverTimezone=UTC"
    jdbc_user => "DB username"
    jdbc_password => "DB userpassword"
    statement => "SELECT * FROM device_info;"
    schedule => " * * * * * *"
    type => "object_type1"
  }
  jdbc {
    jdbc_driver_library => "/connector 다운로드 경로/mysql-connector-java-8.0.21.jar"
    jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
    jdbc_connection_string => "jdbc:mysql://localhost:3306/monitor?useTimezone=true&useLegacyDatetimeCode=false&serverTimezone=UTC"
    jdbc_user => "DB username"
    jdbc_password => "DB userpassword"
    statement => "SELECT * FROM person_info;"
    schedule => " * * * * * *"
    type => "object_type2"
  }
}

filter {
    mutate { add_field => { "[@metadata][type]" => "%{type}" } }
    mutate { remove_field => ["type"] }
}

output {
    elasticsearch {
        hosts => ["localhost:9200"]
        index => "django_%{[@metadata][type]}_idx"
        document_id => "%{unique_id}"
    }
    stdout{
        codec => rubydebug
    }
}

하지만 여기서 발생하는 문제점은 많은 데이터가 있음에도 불구하고 각 테이블에서 단 1개의 데이터만 전달된다는 것입니다. 그 이유가 뭘까 고민하다가 찾은 방법은 바로 아래 2라인을 jdbc 내부에 추가하는 것이었죠. 또 하나, 여러 개의 jdbc input 대신 쿼리문으로 두 테이블의 데이터를 모두 가져오는 것이었습니다. 

tracking_column => "regdate"
use_column_value => true

제가 참고한 사이트는 역시 외국 블로그(?) 글이고, 우리가 추가 입력할 수 있는 옵션에 대해서 자세하게 설명하고 있습니다. 영어가 불편하신 분들을 위해 아주 간단하게 tracking_column과 use_column_value에 대해 설명하자면...

1. tracking_column은 DB에 데이터가 새로 추가되는 순간을 구분하기 위해 트래킹할 컬럼을 지정하는 것입니다. 즉 DB에 언제 데이터가 들어왔는지를 알려면 regdate 라는 컬럼을 참조하라는 의미입니다.

2. use_column_value를 true라고 지정하면 tracking_column 값을 :sql_last_value로 정의합니다. 새로운 데이터를 발견할 때마다 앨라스틱서치에 계속 전달을 해주는 것이죠. false로 지정하면 마지막 쿼리문이 던져진 순간을 반영하여 모든 데이터를 전달할 수 없는 것입니다.(위에서 발생한 문제점도 이와 연관된 것으로 보입니다) 

* 추가 사항: tracking_columnuse_column_value 관련해서 ELK 공식 문서를 발견해서 추가로 소개해드립니다.(일찍 발견하지 못한 것에 대해 반성...) Jdbc input plugin을 사용하여 logstash conf 파일을 설정하는 방법을 전체적으로 잘 설명하고 있더군요. 

tracking_column
에는 꼭 시간적인 데이터를 사용하지 않아도 됩니다. id가 될 수도 있고, 다른 컬럼도 될 수 있으며 어쨌든 순차적으로 데이터 정보를 읽는 것입니다. 이는 다르게 보면 순차적으로 정보를 읽어올 필요가 없는 파일에 대해선 tracking_columnuse_column_value를 작성하지 않아도 된다는 뜻입니다. 즉 파일 전체를 logstash에 보내야 할 상황이라면 이 둘은 필요없게 되는 것이죠. 저 역시 이미 갖추어져 있는 데이터를 logstash에 보내야 했는데, 추가로 schedule 관련 라인도 삭제했습니다. schedule => " " 부분을 계속 남기게 되면 새로운 데이터가 아니면 데이터 정보를 읽지 못합니다!  

이외에도 sql_last_value 등 각종 세팅에 대해서 설명하고 있으니 자세한 사항은 공식 문서를 참고해주세요. 

결과적으로 앨라스틱서치에 제가 원하는 정보를 모두 보낸 로그스태시 conf 파일은 아래와 같습니다. 

input {
  jdbc {
    jdbc_driver_library => "/connector 다운로드 경로/mysql-connector-java-8.0.21/mysql-connector-java-8.0.21.jar"
    jdbc_driver_class => "com.mysql.cj.jdbc.Driver"
    jdbc_connection_string => "jdbc:mysql://localhost:3306/monitor?useTimezone=true&useLegacyDatetimeCode=false&serverTimezone=UTC"
    jdbc_user => "DB username"
    jdbc_password => "DB userpassword"
    tracking_column => "regdate"
    use_column_value => true
    statement => "SELECT d.id as deviceid_id, d.status, d.station, d.region, d.installdate, 
    p.id, p.degree, p.hasMask FROM monitorapp__device_info as d 
    left join monitorapp_person_info as p on d.id = p.deviceid_id 
    WHERE p.regdate>:sql_last_value;"
    schedule => " * * * * * *"
  }
}

output {
    elasticsearch {
        hosts => ["localhost:9200"]
        index => "django_test"
        document_id => "%{id}"
    }
    stdout{
        codec => rubydebug
    }
}

logstash conf 파일을 실행하면 콘솔에 아래와 같이 잘 나타내는 것을 확인할 수 있습니다. 각자만의 모델 및 테이블에 따라 조금씩 변형을 주면 쉽게 구현할 수 있을 것입니다. 

 

728x90
반응형