베이스캠프 Sprint8
21.03.08부터 21.03.12까지 베이스캠프 Sprint8을 진행했다. 전 Sprint에서 웹 서버 Scale out을 진행했다면, 이번 Sprint에서는 스케일 아웃된 웹 서버에 DB 샤딩까지 진행해보는 것이 목표였다. DB가 하나여서 병목이 되어버리면 웹 서버를 스케일 아웃한 의미가 없어지게 된다.
쿼리 검수
DB 샤딩에 앞서 SQL이론 교육 및 쿼리 검수를 받았다. 전반적으로 ‘좋은 쿼리’에 대한 교육이었던 것 같다.
SQL이론 교육은 정말 흥미로운 부분이 많았다. 단순히 SQL문법에 관한 내용은 아니었고, 각 SQL문이 실제로 어떤 식으로 작동하고, 그렇기 때문에 지양해야하는 SQL문 등에 대해서 배울 수 있었다. 책으로만 배우던 SQL과 전혀 다른 부분이었고 현업에서도 성능을 위해 꼭 알아야할만큼 유용한 내용들이 많았다. 특히 DB 상에서 성능 상의 이슈로 물리적인 Foreign key를 사용하지 않고, 이로 인한 참조 무결성 관리는 애플리케이션, 즉 개발자가 주로 한다는 사실은 전혀 몰랐던 것이기에 놀라웠다. 그리고 물리 FK를 모두 제거할 생각에 Entity 클래스나 메소드를 다 뜯어고쳐야 하는 건가 싶었지만 팀원이 물리 FK만 생성하지 않는 옵션을 추가할 수 있는 방법을 찾아내서 다행히 로직 코드를 고칠 일은 없었다.
쿼리 검수 결과는 대부분의 TF에서 비슷한 검수 결과를 받았다. 이전에 검수를 원하는 쿼리 두개를 선정해서 검수 요청을 드렸고, 그 중에 하나는 내가 작성한 항공편 검색 조건 조회 쿼리였다. 지적해주신 문제점 중에 내가 고쳐야할 부분은 크게 두가지였다.
- select문에서 중복되는 칼럼 제외
- group by 사용시 select문에서 가져오는 칼럼 모두 명시
1번은 사실 ORM을 쓰다보니 불가피한 부분이었는데(Entity를 통째로 가져오기 때문에) 해당 검수 결과를 바탕으로 쿼리를 고치다 보니 Entity의 칼럼을 하나하나 지정해주면서 ORM을 쓰는 의의가 무색해지는(?) 기존에 비해 지저분한 코드가 되어버렸다. ORM의 여러 장점 중 타입 안정성 정도만 지켜지는 코드라고 느껴졌는데 성능을 위해 이부분은 포기해야하는 건가 싶었다.
2번은 결론부터 말하자면 내가 문법을 잘못 알고 있었던 것이다. 이전까지 group by에는 해당 tuple을 구분짓는 칼럼들만 작성해도 되는 것으로 알고 있었고(예를 들어 select * ... group by PK
와 같은..), 검수 결과를 알려주셨을 때도 어떤 차이가 있는지 잘 이해가 가지 않았다. 그래서 교육을 진행해주신 남준희 선임님께 다시 질문을 드렸고, 명쾌한 답을 들을 수 있었다.
수행이 가능하다곤 하지만 문법상 select절에는 group by절에 명시된 컬럼을 다 작성해주셔야 됩니다. MySQL의 경우 위와 같이 실행하면 문제 없이 수행되지만 타 DBMS의 경우 오류 발생합니다.
애초에 잘못된 문법으로 알고 있었고, MySQL에서만 오류없이 수행되는 쿼리였다.
이 교육의 내용은 정리해서 이 블로그에 남겨놓는 게 좋을 것 같다.
샤딩
계정서버 디비 샤딩을 진행했다. 테이블이 회원 테이블 하나인 계정서버 DB에 대해 진행했다. 태스크 분배 시에 이 부분은 내가 맡아서 개발하고 싶다고 어필하여 주도적으로 개발하게 되었다. 샤딩에 대한 부분은 이전부터 확실히 알고 넘어가고 싶었기 때문이다.
처음에 참고할만한 블로그들을 찾아봤는데 Spring AOP, Spring Expression부터 시작해서 java annotation 만들기, AbstractDataSourceRouter 등 모르는 개념 투성이었고, 추상화 레벨이 높아서 코드를 이해하는 것 조차 쉽지 않았다. 그래서 코드의 구조와 내용을 이해하는데만 하루를 투자했다. 결국 위의 개념들을 모두 활용하여 샤딩 구현을 해냈다. 베이스캠프 기간에 작성한 코드 중에서 가장 고심을 많이하면서 코드를 작성했고, 여러가지 트러블 슈팅을 거쳐서 코드가 탄생했는데, 트러블 슈팅 과정들도 정리해서 이 블로그에 남겨놓는게 좋을 것 같다.
로그인 인터페이스 통합
모든 TF의 로그인 인터페이스를 통합하는 과제였다. 이 부분도 나에게 굉장히 흥미로웠다. 계정 서비스를 통합하기 위해서는 각 TF별로 외부에서 로그인이 가능하도록 API를 제공해야함을 의미하고, 다른 TF와 스펙에 대한 합의가 필요한 부분이었다. 그동안은 우리 TF에서 작성한 API는 우리 TF 서비스에서만 사용했기 때문에 API 내부 로직에 오류가 있어도 우리끼리 해결하면 되는 문제였지만, 이제는 다른 서비스에도 영향을 줄 수 있는 부분이 생긴 것이다.
어쨋든 API 스펙 정의를 위해 모든 TF에서 대표 인원이 참가하여 회의를 진행했다. 나도 회의에 참석해서 적극적으로 의견을 개진하는 경험을 할 수 있었고, 결과적으로 깔끔한 API 스펙이 정해져서 다른 팀원이 해당 API 구현을 맡아서 개발했다. 일반적으로 현업에서 서비스를 개발할 때 API 설계 시 부서간 또는 외부와 협업하는 방식을 배울 수 있는 기회였다.
그 외
이 외에도 내가 주도적으로 개발하지 않았지만 아래와 같은 태스크를 진행했다.
-
Security Key Manager
기존에 프로젝트 파일 내에 무방비하게 기록되어 있던 민감 정보(db 계정 및 비밀번호 등)를 없애기 위한 작업이었다. SKM을 활용하면 발급받은 일종의 토큰을 이용하여 API 요청하면 해당 정보를 받아오는 구조로 구현할 수 있고, 프로젝트 파일 내에 정보가 노출되는 걸 막을 수 있었다.
-
스케일 아웃 코드리뷰 반영
사실 다른 팀원들은 이 부분 때문에 고생을 많이했다. Sprint7의 스케일 아웃 시 구현한 Redis 세션과 DB Session에 대해서 우리 TF 전체가 세션 구조에 대해 아예 잘못 이해하고 있었던지라 전면 수정이 필요했기 때문이다.
Leave a comment