Golang 서버에서 athena 쿼리하기

HY·2023년 4월 22일
0

왜?

현재 내가 서버 엔지니어로 근무하고 있는 회사에선 golang을 사용해 서버를 구축했다. 왜 golang을 사용했냐면, Java 같은 언어들에 비해 저연차의 엔지니어도 기여하기 좋다... 그거 말고도 이유가 더 있었던 거 같은데 기억이 나지 않는다. 아무튼 golang을 사용하고 있고, 대외비적 사유로 인해 주로 사용하던 mysql 이 아닌 S3에 데이터를 적재하고 조회해오게 됐다.
프로젝트 초기에 리서치를 해보니 S3, Athena를 쓰는 사람들이 영 없는 건 아니었는데, 막상 Golang을 사용해서 쓰려고 하니 한국어 웹에선 거의 찾아볼 수가 없었다. 선임님의 도움을 많이 받았지만 나름 쌔빠지게 조사하면서 공부한 걸 이렇게 정리해서 공유해둔다면 언젠가 나같은 S3와 Athena에 대해 전혀 모르는 golang 서버 개발자에게 도움이 되지 않을까 싶어 간략하게 정리한다.
절대 전문적인 내용이 아니고, 서버에 적용하면서 얻은 팁 몇가지이니 참고만 하시길 -_-;;

AWS S3

S3는 주로 로그를 저장하는 저렴한 스토리지이다. 실제로 aws s3 console에서 조회해보면 디렉토리로 나누어져 있고, 파인더에서 조회하는 것처럼 파일을 조회할 수 있다. 그냥 로그 뿐만 아니라 이미지 같은 포맷의 파일도 저장할 수 있다.

AWS Athena

그런데 S3는 싸고 속도도 빠르고 보안도 좋다. 그러나 S3에 적재된 데이터를 직접 가져다 쓰려면 파일을 로드하고 압축 해제하는 등의 과정이 필요하여 사용하기가 어렵다. 이때 사용하는 것이 AWS Athena다. SQL을 사용해 데이터를 조회할 수 있고, 서버리스 서비스라 인프라를 따로 관리할 수고를 덜 수 있다.

uber/athenadrvier

아무튼 athena를 사용하기 위해 선택한 driver는 uber에서 만든 athenadriver이다. Link
golang에서 athena를 사용할 수 있게 해주는 드라이버가 몇 종류 있었는데, aws에서 만든 것과 uber에서 만든 athenadriver 사이에서 uber를 사용하게 됐다. athenadriver 쪽이 코드를 이해하기 더 쉽고, 비교적 최근에 업데이트가 됐기 때문이다.

package main

import (
	"database/sql"
	drv "github.com/uber/athenadriver/go"
)

func main() {
	// Step 1. Set AWS Credential in Driver Config.
	conf, _ := drv.NewDefaultConfig("s3://myqueryresults/",
		"us-east-2", "DummyAccessID", "DummySecretAccessKey")
	// Step 2. Open Connection.
	db, _ := sql.Open(drv.DriverName, conf.Stringify())
	// Step 3. Query and print results
	var url string
	_ = db.QueryRow("SELECT url from sampledb.elb_logs limit 1").Scan(&url)
	println(url)
}

어떻게 사용할지는 README에서 아주 잘 설명해놨다. 다만 open connection을 할 때 쿼리할 데이터의 source를 set 하는 부분이 빠져있다!
어떻게 어느 bucket에서 가져올지 지정도 하지 않고 쿼리를 해올 수가 있어; 하는 마음으로 나는 NewDefaultConfig에서 조회해올 s3 url을 넣고, conf.SetOutputBucket 을 다시 호출해 쿼리 result를 저장할 s3 bucket url을 넣는 잘못을 저질렀다. 그렇게 하니까 돌아가긴 하길래...
선임님이 지적해주셔서 이 부분을 다시 리서치 해보고 이유를 알게 됐다. Athena에서 쿼리할 때 FROM 절에 들어가는 테이블명을 통해 해당 데이터가 저장된 S3 버킷을 추측할 수 있다. 그래서 athenadriver에서도 result 로그를 저장할 bucket url만 받아 config에 저장하는 것이었다.

유의해야 할 점

Athena 특징

Athena에서는 쿼리할 때 스캔한 데이터 용량에 따라 비용이 책정되기 때문에, mysql에서 하듯 아무 생각 없이 쿼리를 실행하면 전체 데이터를 스캔하게 되어 속도가 느리고 비용이 많이 들게 된다.
그래서 s3에 적재할때 dt, hour 등으로 파티셔닝을 하는데, Athena에서 쿼리할 때 이런 조건으로 쿼리하는 것이 중요하다.
이 비용과 속도를 개선하기 위해 우리 팀에서는 Athena로 쿼리를 날릴 때 where clause로 최소한의 파티션만 조건으로 걸고, 조회한 데이터를 서버에서 필터링하여 사용하는 방법을 선택했다. 파티션을 생각하지 않고 작성한 쿼리에서 30초가 걸렸던 걸 이 방법을 통해 약 5초로 단축했다.

단점?

하지만 직접 사용해본 결과 AWS Athena는 속도가 좀 느리다. mysql 같은 성능을 기대하기는 어렵고, 특히 사용자가 접근하는 DB로는 부적절하지 않나 싶다. (우리 회사에서는 어쩔 수 없는 이유가 있었음;)
S3를 설계할 때 이 데이터를 어떻게 사용할 것인지 생각하며 설계를 해야 하지 않나 싶다. 일단 쌓아두자 하고 쌓아둔 데이터를 가져다 사용하려고 하니 이런 저런 제약이 많아 어려웠다.

moneywise 모드

athenadriver의 athenareader에선 moneywise 모드를 지원한다. 쿼리를 실행하면 쿼리 결과에 대한 메타데이터가 bucket에 쌓이는데, 그 데이터를 조회해 스캔한 데이터량을 구하고, 현재 aws의 가격책정을 반영해 이 쿼리를 실행하는데 비용이 얼마나 지불됐는지 확인할 수 있는 기능이다.
하지만 이 기능은 서버에서 사용자들에게 제공하는 것을 염두에 둔 것이 아니라 개발자들이 콘솔에서 명령어로 조회하는 것을 기반으로 한 기능이므로, 서버에서 직접 사용하기에는 복잡할 수 있다. 또한 금액이 하드코딩되어 있어 AWS에서 가격을 조정하더라도 개발자가 코드를 수정하지 않으면 업데이트되지 않는다.

마치며...

막상 프로젝트 진행을 할 땐 끝나기만 하면 내가 s3와 athena에 대해 길고 자세하고 전문적인 기록을 남기겠다 결심했는데 끝나고 여차저차 미루다 보니 거의 한 달이 지났다. 그래도 기억이 조금이라도 남아있을 때 써서 다행이지...

혹시라도 틀린 부분이 있다면 지적바랍니다.

profile
사실은 공부를 비밀스럽게 하고 싶었다

0개의 댓글