2021년 12월 31일 금요일

2021년 회고

2021년은 이직을 하면서 조금 바쁜 해를 살았다. 새 회사와 도메인에 적응하기 위해 나름 바쁘게 살았고 기존에 알던 지식을 어떻게 사용할 수 있을지 많이 고민을 했었다. 결과적으로는 기술부채를 많이 쌓았지만 경험적인 측면에서는 많이 도움이 되었던 것 같다.


올해 포스팅은 대단한 것을 쓸 기회가 없었을 것 같았기 때문에 개인적으로 그 동안 알고 있던 내용을 정리하는 시간을 갖고자 했다. 데이터 엔지니어가 알아야할 기본적인 내용을 시리즈별로 작성했다.


1) 빅데이터 플랫폼 아키텍처에 대하여.. 데이터 스토리지 관점에서의 흐름
https://parksuseong.blogspot.com/2021/06/1.html
2) 빅데이터 플랫폼 아키텍처에 대하여.. 하둡을 알아보자
https://parksuseong.blogspot.com/2021/08/2.html
3) 빅데이터 플랫폼 아키텍처에 대하여.. 데이터를 처리를 위한 Spark
https://parksuseong.blogspot.com/2021/08/3-spark.html
4) 빅데이터 플랫폼 아키텍처에 대하여.. 배치 스케쥴러(airflow, azkaban, oozie)
https://parksuseong.blogspot.com/2021/08/4-airflow-azkaban-oozie.html
5) 빅데이터 플랫폼 아키텍처에 대하여.. 데이터 시각화를 위한 프레임워크(DashBoard 구현에 필요한 Grafana, Prometheus, influxDB 등)
https://parksuseong.blogspot.com/2021/08/5-dashboard-grafana-prometheus-influxdb.html
6) 빅데이터 플랫폼 아키텍처에 대하여.. 다른 팀과 협업 시 구성하면 좋은 프레임워크(hive, hue)
https://parksuseong.blogspot.com/2021/10/6-hive-hue.html


원래 기술블로그를 보면서 의견이 있어도 댓글을 안달고 그냥 머리속으로 끝냈는데 포스팅을 하다보니 댓글 하나하나가 큰 힘이되고 다시 생각을 정리하는 시간도 갖게되어서 댓글을 달아주신 분들이 너무 감사하다는 생각이 들었다.

특히 전 직장에서 기술적으로 많이 도움을 주셨던 장원주 담당님이 의견을 남겨주셔서 큰 힘이 되었고 댓글이 큰 힘이 되는 것을 알았기 때문에 나도 다른 블로그글들을 보면 댓글을 남겨야겠다고 생각을 했다.(SSG.COM 장원주 담당님 감사합니다.)


2021년은 코로나때문에 스스로도 많이 나태해졌고 무언가 열심히 찾아보고 새로운 방법을 찾아보려고 한 것이 없다는 것이 너무 아쉬운 한해가 되었다. 그나마 가장 열심히(?) 방법을 찾아보려고 했던 것이 있다면 airflow dynamic task at runtime인데 이 부분도 포스팅을 했는데 같은 어려움을 겪으면서 고민을 해 주신분이 계셨고 댓글을 남겨주셔서 감사했다.

해당 포스팅은 airflow dynamic task at runtime에 대한 고찰이며 같은 결론에 도달한 것이 다행이기도 하지만 아쉽기도 하였다.

( https://www.blogger.com/blog/post/edit/7933278769949015036/5051160839575531588 )


생각해보면 100% dynamic batch flow를 들어본 적도 본 적도 없기는 하다.


블로그 조회수



내년에는 쓸 것을 찾아서 더 열심히 써야겠다. 개인적으로 데이터 쪽이나 사이드 프로젝트를 진행하며 꾸준히 포스팅할 소스를 찾아볼까 한다.

아무튼 2022년에는 더 재밌는 일이 찾아오기를 바란다!

2021년 11월 12일 금요일

airflow dynamic task at runtime에 대한 고찰

airflow에서 runtime에 동적으로 태스크를 생성하는 것이 옳은 일인가? (task들의 정보는 외부에 존재한다고 가정한다. 그 정보를 가져오려면 수 분이 소요될 수 있다.)

지금까지 스케쥴러에서 dag(flow)를 고정시켜놓고만 사용했었다.
일반적으로 스케쥴러에서 가장 가까운 곳에서 meta 정보를 불러와서 그 정보로 dag를 그린다. 그리고 그 meta 정보는 아마 대부분 스케줄러 DB일 것이다.

airflow를 사용하다가 dag안에 task를 런타임에 동적으로 생성해야하는 경우가 있다면 어떻게 해야할까 고민을 했다. 동적으로 그릴 정보는 airflow DB가 아닌 멀리 떨어져 있는 곳에 존재한다고 가정하자. 참고로 airflow variable은 airflow meta DB에 저장된다. 따라서 dag 정보를 variable에 저장한다면 그 것은 동적이 아닌 정적이라고 봐야한다. 어쨌든 task가 수정되기 위해서는 variable도 수동으로 수정되어야하니까..

조금 더 상세하게 시나리오를 짠다면 어떤 DB에 쿼리를 수행하여 해당 결과 행 만큼 task1, task2, task3.. taskN 을 생성하고 이 task1~taskN을 병렬수행할 수 있겠다.

즉 task_list.append(task1~taskN)로 task_list를 만들고 task_start > task_list > task_end 형태로 그려지는 형태일 것이다.

결론먼저 이야기한다면 개인적으로는 권장하지 않는다. task는 정적으로 생성되어야 한다고 생각한다. (아닐 수도 있지만..)

예를 들어 task들의 정보가 hive에서 select로 가져올 경우 일단 느리다. 1분정도밖에 안걸린다고 하더라도 서비스에서 1분이면 못 기다릴 시간이다. 어떻게든 결과를 가져와서 그린다고 할 지라도 dag가 엄청 느리게 그려지겠지.. 혹시 몰라서 subdag에 넣고 하면 그나마 괜찮을까 했었는데 여러 비슷한 레퍼런스에서도 그런식으로 작성을 했었고.. 시도해봤지만 실패다.

게다가 airflow process 중에 dag manager가 주기적으로 수행하면서 dag를 최신화(refresh) 작업을 하는데 (마치 heartbeat처럼) 그럼 그 때마다 쿼리 결과를 날려야한다면? 그리고 그 쿼리가 3~5분이 걸린다면 재앙이다.

runtime에 수행되도록 이리 저리 머리를 굴려봐도 결과적으로는 realtime으로 task 형상이 보여야하기 때문에 안된다고 생각을 하고 정적으로 flow를 구성하는 것을 권장한다.

하지만 우리에겐 언제나 해결책이 있기 때문에 혹시 비슷한 고민을 했던 분들 중 airflow dynamic task(dag, subdag) at runtime best practice가 존재한다면 댓글 부탁드립니다.

2021년 10월 27일 수요일

Hive partition table로 DW를 구축할 때 고려할 점(upsert)

과거에 팀장님께서도 한번 주문했던 내용인데 하둡에 저장된 과거 데이터의 update 시나리오를 고민했던 적이 있다. 당시 결국 만족할만한 방법이 없어서 drop했던 내용인데 그 기억을 살려 hive를 기준으로 다시 포스팅을 해본다.


대부분 HDFS에 적재된 데이터는 Hive로 접근한다. HDFS 데이터를 가지고 DW를 구축할 때 Hive가 가장 편하긴 하지만 HDFS 특징으로 인해 Hive에서의 약간의 제약이 있다. 파일시스템이기 때문에 일반적인 DB처럼 row 1개를 delete, update를 하기 어렵기 때문이다.


대부분의 경우 하이브 테이블은 파티셔닝을 한다. 데이터의 양이 많고 매일 적재되기 때문에 파티셔닝은 필수다. 하지만 이런 경우 소급이 문제가 된다.

가령 과거 데이터를 새로 만들어서 insert overwrite table target_tbl partition(col='yyyymmdd') select * from source_tbl 형태로 데이터를 적재해보자. 이런 경우 upsert로 동작하지 않는다. 해당 파티션의 데이터를 delete 후 새로 엎어치는 작업을 한다. 즉 delete&copy 형태로 동작한다. 

이런 경우 그럼 지워지면 안되는 데이터도 날아가기 때문에 결과적으로는 통으로 데이터를 만들어줘야한다. 이런 경우 old 데이터와 new 데이터를 full outer join을 해서 통으로 새로 다시 만들거나 new_tbl left join old_tbl+ union all old_tbl not exists new_tbl 형태로 통으로 다시 만들어줘야한다.


insert는 해당 파티션에 단순 append이기 때문에 단순 데이터를 적재하는데 쓸수는 있지만 insert overwrite로 밀어넣는 형태라면 해당 파티션이 새로 적재된다는 사실이다.

파일시스템이라서 당연한 결과이기는 하지만 hive를 어떠한 형태로 사용하더라도 hdfs를 사용하기 때문에 방법이 없다. 또한 인덱스의 효과도 일반 DB와 비교해서 크지 않다.


그럼 결과적으로 통으로 새로 만들어야하는가? "그렇다."

그럼 어느 부분에서 효율을 낼 수 있나? 현재로서는 spark를 사용해서 연산 속도를 높이는 것 외에는 없어보인다.


다른 방법이기는 하지만 파티션을 일자 외에도 다른 컬럼을 추가해서 아주 잘(?) 사용한다면 방법이 있을 수도 있다. 하지만 권장하지는 않는다!

2021년 10월 2일 토요일

6) 빅데이터 플랫폼 아키텍처에 대하여.. 다른 팀과 협업 시 구성하면 좋은 프레임워크(hive, hue)

무슨 내용을 쓸까하다가 보안적인 부분에 대해서 포스팅을 안했기 때문에 이번에는 이 부분에 대해서 다뤄보려고 한다. 최근 깃랩에 사이드프로젝트를 만들어보니 토큰 발급이 필수로 바뀌어서 문득 다음 포스팅 주제도 보안적인 부분을 다루면 좋겠다고 생각했다.


선택사항이고 개인적으로 보안적인 부분은 최전방에서 최대한 막고 내부 동료들끼리는 개발 효율을 위해 최대한 풀어줘야한다는 생각이지만 이는 업에 따라 법적인 문제(생각보다 고려할 부분이 많다)도 있기 때문에 잘 고려해서 해야한다. 단지 이 포스팅은 한가지 시나리오일 뿐이다.

상황은 하둡 데이터를 접근해야한다. 당연히 관리자는 모두 접근이 가능하겠지만 만약 다른 부서 사람들이 접근을 해야하는 경우는 어떻게 해야할까? 데이터를 직접 뽑아줄 수도 있지만 분석가는 데이터를 불러와서 모델링을 해야하기 때문에 결국 open을 해야하는 이슈가 있다.

하둡 자체에 kerberos 인증이 있기는 하지만 우리가 로그인할 때의 수준이지 데이터 접근에 대한 개념이 아니다.


그럼 어떻게 할까.
1차적으로 하둡 페이지들에 대한 개인의 접근은 모두 막는다. 즉 모든 방화벽을 열어주지 않는다. 굳이 열어준다면 리소스 매니저만 열어준다.

그럼 사람들이 데이터는 어떻게 접근하는가?
hue만 열어준다. (hue는 절대 스케쥴러 용도가 아닌 단순 파티션이나 데이터 확인용!!) 
그럼 단지 쿼리만 날릴 수 있겠지만 불필요한 접근이 없게 될 것이다.

그리고 개발이나 배치는 hive를 통해서만 접근하도록 한다. 즉 개발서버에서 hive만 접근가능하게 열어주고 hive 쿼리만 날릴 수 있게 한다. 어차피 데이터는 쿼리로 접근할테니.. 중요한 것은 hdfs에 direct로 접근하지 못하게 하는 것이다.

체감되는 트랜드 순서가 MR -> Tez -> Spark인 것 같은데 hive on spark를 구성하면 좋겠지만 MR이든 Tez든 Spark든 모두 Spark로 처리할 필요는 없고 데이터의 사이즈에 따라서 MR이나 Tez를 써야하는 경우도 있다.

갑자기 다른데로 샌것같은데 아무튼 이번 포스팅은 보안(?)이라기보다는 어쨌든 아무나 접근 못하게 하는 방법(?)을 제안해보았다.

결론은 개인 컴퓨터에선 hue만 열어줘도 된다.

2021년 8월 28일 토요일

5) 빅데이터 플랫폼 아키텍처에 대하여.. 데이터 시각화를 위한 프레임워크(DashBoard 구현에 필요한 Grafana, Prometheus, influxDB 등)

1편 Bigdata Architecture, 2편 Hadoop, 3편 Spark, 4편 Scheduler에 이어서 5편은 무슨 주제로 포스팅을 할까 하다가.. Hive나 Hue같은 부가적인 프레임워크보다는 시각화를 먼저 쓰는게 좋다고 문득 생각이 들었다.

데이터를 저장(Hadoop)하고 Spark로 처리하고 Scheduler로 정기적인 작업을 할 수 있다면 꾸준히 output data가 어딘가에 쌓일 것이다. 그 것을 HDFS로 저장하거나 또는 다른 DB에 저장해서 필요할 때 가져다 쓰면 된다.


대시보드를 만들 때 Tableau, Power BI 등 유료 대시보드를 쓰면 여러 기능들을 사용할 수 있고 잘만들면 drill down을 하면서 Olap처럼 사용할 수도 있다. 하지만 서버 상태 모니터링이나 실적 등 처럼 정형화된 그래프만 봐도 충분한 경우가 있다. 이럴 땐 굳이 유료 대시보드를 구매할 필요 없이 범용적으로 사용하는 Grafana를 권장한다.


Grafana는 Graph뿐만 아니라 alert 등을 걸고 이메일 알림을 받을 수 있다. 또한 공통적으로 사용하는 화면들은 다른 사람들이 잘 만들어놓고 grafana 공식 홈페이지에 dash board를 검색하여 json을 가져다가 쓰기만 하면 된다.


Grafana labs


Grafana는 대시보드다. 그럼 데이터는 어디에 있는 것을 사용하면 될까? mysql, postgresql, influxDB 등 다양한 connector(plugins)가 존재하며 데이터가 있는 DB와 연결하면 일정 주기마다 데이터가 불러와지면서 화면에 그려준다. 보통은 쿼리를 작성하고 그 쿼리가 일정 주기마다 DB에 날린다.


불러온 데이터는 각종 Graph로 표현할 수 있다. 클릭 몇번으로도 구현이 될 정도로 아주 간단하다. 버전마다 사용가능한 차트가 다르고 다른 사람들이 작성해놓은 dash board를 다운받아서 사용할 경우 데이터 형식만 맞춰주면 그대로 가져다 쓸 수 있다.


보통 시계열 데이터는 InfluxDB에 넣고 사용을 한다. time series DB이기 때문에 Timestamp로 구분을 하고 PK를 사용하지 않기 때문에 메트릭정보, 실시간 로그 분석 등에 사용하기 알맞다. Opensource olap 중에 하나인 druid와 철학을 같이하는 것처럼 보인다.


이렇게 grafana에 direct로 DB를 연결해서 보여주는 방식도 있지만 별도 수집기를 둘 수도 있다. 이는 Prometheus라는 프레임워크가 해줄 수 있다. Prometheus 역시 time series로 데이터를 수집하며 각종 metric을 수집할 수 있다.

중요한 것은 데이터를 필요한 곳에 넣어주느냐, 데이터가 필요한 곳에서 가져가느냐의 차이이다. 둘다 가능하지만 후자가 조금 더 안전하다. Destination의 문제로 인해 데이터를 더 이상 받으면 안될 때에도 데이터를 억지로 밀어넣고 있는다면 당연히 장애가 심각해질 것이다. 따라서 push 방식보다는 pull 방식을 더 선호하고 이 외에도 데이터를 받는 곳에서 장애가 나게된다면 pull 방식은 단지 데이터를 가져가지 않을 뿐이니 문제가 없다. 단지 수집기로 쓰기에 알맞다.


과거에 포스팅을 했지만 프로메테우스는 확장하기가 어렵다. 확장을 하려면 프로메테우스들끼리 묶고 다시 상단에서 그 데이터를 pull해오는 방식으로 구현을 해야한다. 즉 프로메테우스를 층층이 쌓아서 피라미드(?)처럼 설계를 해야한다. 다른 방식이 있는지는 모르겠지만 그 정도로 프로메테우스를 heavy하게 사용할 일이 있을까?



프로메테우스 아키텍처이다. 위에서 언급했던 데로 Grafana에서 direct로 DB를 붙게된다면 15초, 30초 마다 한번씩 쿼리를 수행하기 때문에 DB입장에서는 부담이 될 수 있다. 하지만 프로메테우스를 사용한다면 프로메테우스가 그 DB역할을 대신해주고, 프로메테우스는 pull 방식으로 데이터를 수집하므로 조금 더 안전한 구조가 될 수 있다.

아키텍처처럼 Pushgateway를 두고 Prometheus server가 데이터를 수집할 수도 있고 수집대상에 exporter를 띄워서 Prometheus server가 수집할 수도 있다. 즉 Prometheus server가 몸통이다. 또한 여기에서도 Alertmanager를 별도로 두어 email 등의 알람을 줄 수 있다. 또한 Prometheus 자체가 데이터를 들고있으니 그래프를 그리는 것 또한 가능하다. 하지만 이쁘지 않기 때문에 그라파나를 통해서 그리는 것이 훨씬 더 이쁘게 그릴 수 있다.


Prometheus는 필수는 아니고 Dashboard를 위해서는 Grafana만 있으면 된다. 
Grafana를 잘 활용하자.


Hive Error) Cannot insert into target table because column number/types are different

Hive에 Insert를 할 때 이런 에러를 볼 수 있다. 
target table은 partition table이고 source 테이블보다 컬럼이 한개(div_col)가 더 많다. 
대충 Insert 구문은 이런식으로 작성을 했다. 
INSERT OVERWRITE TABLE TARGET_TBL_NMPARTITION(partition_col='yyyymm') SELECT '0' as div_col, * FROM SOURCE_TBL_NM

"Cannot insert into target table because column number/types are different : Table insclause-0 has N columns, and the N+1 columns are partitioned and we not required any filters we have to dump/store from non partitioned table to partitioned table."

넣고자 하는 데이터에 SELECT * FROM 구문이 문제가 되는 것으로 partition 컬럼이 return 되면서 컬럼이 한개가 더 +1 되는 상황이다.
그래서 이런 경우에는 타겟 테이블 컬럼 이름을 Select 절에 다 써줘서 갯수를 맞춰줘야한다.

즉 INSERT OVERWRITE TABLE TARGET_TBL_NMPARTITION(partition_col='yyyymm') SELECT '0' as div_col, Col1, Col2, Col3... FROM SOURCE_TBL_NM

컬럼명이 천개가 넘어가면 설계를 바꾸는것을 권장하고싶다. 굳이 통으로 한개를 들고다닐 필요가 없다면 말이다. 

교훈 : 테이블의 컬럼 갯수는 적당히 쓰자.. 테이블당 컬럼이 1000개가 넘어가면 골때린다.. hdfs를 사용하는 Hive가 Column store가 된다는 일은 앞으로도 없을테니까...



2021년 8월 22일 일요일

4) 빅데이터 플랫폼 아키텍처에 대하여.. 배치 스케쥴러(airflow, azkaban, oozie)

2, 3포스팅을 통해 데이터를 관리하는 하둡과 처리하는 스파크가 세팅되있다면 이제 정기적으로 작업를 수행할 수 있는 배치 스케쥴러가 필요하다.

스케쥴러란 정기적으로 원하는 시간에 특정 작업(스크립트 등)을 수행하기 위해 필요한 시스템이다. 자동화를 잘만 해놓는다면 상당히 많은 리소스를 절약할 수 있다.

빅데이터 진영에는 다양한 스케쥴러가 존재하는데 airflow, azkaban, oozie 등 많은데 아마 요즘은 airflow가 대세가 된 것 같다. 사실 스케쥴러는 단순히 스케쥴러 역할(마치 crontab처럼)이 있다면 배치를 수행하는데 큰 문제가 없기 때문에 어떤 것이든 상관이 없다고 생각한다.

먼저 oozie의 경우 xml로 작성해야하기 때문에 흐름과 맞지 않고 매끄러운 flow를 그리기 어렵다.

사실 분석 클러스터(spark cluster)로 연산을 하게 될 경우 코드(스크립트)를 짜서 분석 서버에 작업을 던지기만 하면되서 단순히 실행 shell script(bash operator)를 원하는 시간대에 설정만 할 수 있으면 된다. 만약 각 스크립트가 수행되는 worker에서 data를 share하고자 할 때에는 조금 불편할 수도 있는데 이 때에는 xcom같은 기능을 활용해서 local로 data를 떨구고 다른 worker에서 읽을 수 있도록 해야하며 이는 작업 후에 data를 지워주거나 잘 못 되었을 경우 다시 받아야할 때 생각보다 비효율적이고 껄끄러운 작업이 된다. 그래서 개인적으로는 share가 필요한 data는 hadoop에 쓰는 식으로해야 추후 스케쥴러 서버의 disk full 등의 장애를 피할 수 있다.(개인적인 의견)

물론 분석 클러스터에서 작업을 하지 않고 로컬 머신에서 돌아가는 경우도 있다. ML/DL job들은 대부분이 단일머신에서 돌아가고 있을테니까.. 


airflow의 경우 파이썬으로 작성하기 때문에 자유로운 커스터마이징이 가능하고 flow를 그리는 것이 쉽다. dag안에 subdag 등을 생성하는 것도 쉽다. 파이썬 기반이다보니 누구나 접근하기 쉽다. 장점은 파이썬 기반이기 때문에 쉽고 자유도가 높다는 점이다. 그렇다면 단점은 무엇일까? 단순히 스케쥴러 역할로만 사용한다면 큰 불편함은 못 느낄 것이다. 단지 DAG의 CICD를 신경쓴다면 크게 어려움은 없을 것이다.


그렇다면 azkaban은 어떨까? azkaban 역시 단순 스케쥴러 역할만 하게 되면 airflow와 똑같다. 오히려 airflow보다 ui에서는 더 간편해보인다. airflow와 마찬가지로 Scheduler 자체의 variable를 가질 수 있으며 최소화로 사용하도록 한다. 소급에 필요하거나 adhoc하게 돌릴용으로만 variable을 사용해야하는데 남발하고 핵심 재료(?)로 사용하게 될 경우 dependency가 많이 걸리게 된다. 극단적으로 아예 안써도 된다고 충분히 다른 곳을 이용해서 해결하는 것을 권장하고싶다.


아무튼 결론은 어떤 스케쥴러를 사용해도 비슷하고 스케쥴러 선정에 고려해야할 부분은 여러가지가 있겠지만 나열해본다면 다음과 같다.

1. UI가 사용하기 편하고 깔끔하다.
2. 재수행이 편하다.
3. flow(dag)를 그리는 것이 간편하다.
4. log보는 것이 편하다.
5. 다른 시스템과 호환이 잘 된다. (굳이 bash로 짤거면 필요는 없긴하다.)

이 정도만 고려하면 충분하지 않을까..

2022년 회고

 올해는 블로그 포스팅을 열심히 못했다. 개인적으로 지금까지 경험했던 내용들을 리마인드하자는 마인드로 한해를 보낸 것 같다.  대부분의 시간을 MLOps pipeline 구축하고 대부분을 최적화 하는데 시간을 많이 할애했다. 결국에는 MLops도 데이...