21년도 정신 없이 시간이 지났다.
올 해 기억에 남는 것들을 세 가지로 추려서 정리해보았다.

배치 작업

서버 개발자에게 batch 작업이란 필수적인 것 같다.
올해는 우리 서비스 운영의 변경 사항들도 많았고, 효율적인 관리를 위해 정말 많은 batch를 설계하고 개발했다.
어떤 특별한 기술을 사용한 것보다 설계를 개선해 나가는 점이 올해 많이 배운게 아닌가 싶다.

batch를 계속하면서 내가 배운점들은 이렇다.

1. 배포는 가능하면 쪼개서 나가자

우리 회사는 배포가 살짝 불편한 편이다. 모듈마다 다르지만 검증/결재를 기다리는 일들로 배포에는 항상 피로감이 쌓이고 재미가 없다.
이런 이유로 여러 작업의 배포가 필요할 때 한 번에 나갔다가 어디서 이슈가 생겼는지 확인하기가 어려웠다. (근데 이건 배포 방식을 바꿔야 해결이 될 것 같다.)

2. migration batch는 rollback이 가능한 구조인지 파악하자

많은 batch와 migration을 수행하면서 간단한 migration에는 자신감이 충만해질 때가 있다.
그래서 rollback에 대한 생각을 접어둘 때가 있는데, 배포 이후에 rollback이 불가능한 경우를 생각하면 아찔하다.
migration은 사용자의 data를 손대는 batch니까 작업 수행 전후로 확인해야할 내용들을 명확히 정리하고 수행해야 한다.

3. 확장성을 보장하자

우리가 관리하는 배치들은 대부분 정해진 기간이 있다.
기간을 맞추기 위해, 혹은 낭비되는 cpu를 채우거나 인스턴스 숫자를 조절하기 위해서 보통 batch의 worker(instance 혹은 thread)가 확장 가능한 구조가 굉장히 중요하다.
instance를 더 붙이고 싶은데 불가능하거나 그 때마다 재시작해야해서는 안되니까.

  • 기간을 맞추기 위해 TPS(Transaction Per Second)나 batch 예상 시간을 조회할 수 있는 지표를 남기면 유용하다.

4. 위와 유사하게 중단/재시작과 멱등성을 고려하자

배치는 여러 이유로 중단/재시작이 필요한 경우가 많다.
인스턴스가 내려갔다거나, memory 부족 등의 이슈로 instance type을 변경한다거나, db throttling 이슈로 input data를 shuffling 해서 재수행하기도 하고 등등..
이럴 때마다 수행된 user(혹은 특정 item 등의 batch 단위)가 batch에 다시 들어가더라도 문제가 없도록 멱등성이 고려되어야 한다. 이걸 고려하지 않으면 배치 돌릴 때마다 피곤하다.

  • 여기서 말하는 멱등성은 다시 돌아도 문제가 없는 것도 있지만, 돌아간 user에 대해서 다시 돌리지 않을 수 있는 일종의 flag가 있어야 batch에도 문제가 없고 재수행했을 때 수행 시간에도 문제가 없다.

5. data flow를 확인하자

우리는 지금 global 5개 region에서 서비스를 하고 있다.
file이 오가는 batch의 경우 binary data가 region을 넘어가는 경우가 발생하기도 하는데, 최대한 효율적으로 binary flow를 잡아갈 수 있도록 설계가 필요하다.
한 번은 설계를 잘 해놓고, binary flow를 놓쳐서 성능이 현저하게 떨어져서 다시 개발한 적이 있었다.

6. life cycle을 같이 도는 batch에서 소스 코드를 분리하지 말자

중복을 최소화하는 것은 개발자의 숙명이기도 하다.
one time job으로 설계된 batch가 아니라 life cycle을 같이하는 batch들에서 소스 코드를 따로 쓰는 경우 문제가 생기기 정말 쉽다.
올 해 우리는 WAS에서 새로운 기능을 내보내고, batch에서는 해당 코드가 추가되지 않아 사용자 데이터를 날려먹을 뻔한 적이 있었다.


설계

위에서도 말했듯 올해는 설계를 하며 배운점이 많다.
설계에서는 어떤 어떤 점들을 배웠다보다는 DDD 스터디와 적용을 함께 하면서 설계하는 능력이 성장하는 것을 느꼈다.

1. DDD는 배우면 배울수록 쉽지 않다.

이전에 DDD에 따라 설계했다고 생각한 모듈들이 조금 더 공부하고 보니 불편한 것들이 많았다.
하면서 느는 것 같긴한데, 아직도 명확하지 않는게 느껴진다.

2. 통계도 설계에 함께 포함되어야 한다.

요구사항을 뽑아서 설계를 진행할 때, 통계가 요구사항에 들어가지 않았다.
서비스가 진행되고 통계를 뽑으려면 이미 늦고, 불편한 작업들(우리는 로그를 까보거나 batch를 통해) 필요할 때마다 통계를 요청하게되어 굉장히 불편했다.

  • 서비스하는 입장이라면 통계를 빠르고 쉽게 전달해줄 수 있는 구조가 되야하는 것 같다.

3. first class object를 쓰자.

우리가 가진 모듈 중에 개발된지 오래되고 우리팀 멤버들이 개발에 참여하지 않은 모듈이 있다.
이게 굉장히 가독성이 떨어지는데 hashmap<stirng, object> 이렇게 hashmap을 굉장히 많이 사용한다.
끔찍한건 저기 object에 hashmap이 다시 들어가기도 한다는 것. 정말 최악이다.
그리고 id를 string이 아닌 ID라는 wrapper class를 만들어서 써봤는데 명확하고 실수가 줄어들어 좋았다.


db

올해는 유독 database 관련 작업들이 많았다.

1. db 통합

한 모듈은 특정 entity를 두 db에 저장하고 있었다.
여러 database를 사용할 수 있고 db를 옮기거나 추가하기 좋은 확장성을 갖는 interface 구조를 설계하는게 굉장히 중요하다는 것에는 동의하나, 의미 없이 db를 두 벌 사용하는 경우는 피하는게 좋다.
예를 들면, blog에 page db는 cassandra를 쓰고 comment는 dynamodb를 쓴다면 뭐 그러려니 하겠지만, 우리는 page의 db를 cassandra와 dynamodb를 같이 쓰고 있었다. (히스토리가 있는 윗분들의 예전 결정)
두 db를 쓰는건 interface가 잘 나뉘어 있어도 개발(특히 db와 연관된 batch)에 굉장한 부담이 되었다.
db 통합은 간단하진 않지만 이걸로 오는 개발/코드리뷰/테스트작성의 효율은 굉장히 컸다.

2. dynamo db table 통합

nosql인 dynamodb를 mysql처럼 테이블을 종류별로 나눠 사용하던 것을 통합했다.
예를들면 page main table과 page meta table이 있던걸 합치는 작업인데, 이 또한 개발/코드리뷰/테스트작성에 굉장한 효율을 가져왔다.
특히 table 통합 이후에 elpased time이 절반으로 줄었다. 서비스 응답 시간에서 가장 중요한건 DB라는 말이 생각난다.

3. dynamodb의 blob limit 문제

dynamodb에 대해 좀 더 이해하는 시간이 되었다.
LSI를 만들 때는 조심해야 한다.
이 내용은 지난번에 정리한 DynamoSizeLimitException를 참고하면 좋겠다.

4. dynamo db query

우리 팀에 db query에 탁월한 능력을 가진 분이 있다.
nosql을 major로 써서 query에 약했는데, 통계 작업을 하면서 query의 힘을 다시 깨닫는다.
공부가 필요할 것 같다.


2021년에는 2020년보다는 재미있는 작업들을 많이 해보지 못한 것 같아서 아쉽다.
일을 많이 한 것 같은데, 아직도 짐처럼 남아있는 작업들이 있기도 하다.

22년에도 설계를 더 잘하고, 기술적으로는 새로운 기술들도 더 배우고 익숙해지는 한 해가 되었으면 좋겠다.