[데브인턴십 4기] Configuration Distribution Admin Page 만들기

최정재

업데이트:

문제 상황


1.현재는 운영팀에서 비트윈 서버의 설정을 바꿀 수 없어서 항상 개발팀에 요청을 해야합니다.

Between api 서버는 minimum 3개의 instance가 운영되고 있습니다. 이 서버들의 setting값을 설정해주는 config 파일을 동기화 시키기 위해 주키퍼를 사용하여 configuration distribution 시스템을 운영하고 있습니다. 현재는 cli 창을 통해 Bastion 서버에 접속하여 linux 명령어를 통해 cli창에서 distribution을 진행하고 있습니다. 이 때문에 운영팀에서는 setting값을 변경할 수 없고 필요시에 개발팀에 요청을 하게되어 업무효율이 떨어지는 상황입니다. Admin server를 구축하여 운영팀에서도 setting값을 변경할 수 있게 하는 것이 프로젝트의 가장 큰 목적입니다.

2.configuration distribution이 비효율적인 구조로 이루어져 있습니다.

추가로 현재는 Bastion 서버에서 api 서버를 거쳐 distribution을 수행하는데 이를 개선하여 Admin server에서 한번에 zookeeper에 update 요청을 거는 식으로 infra 구조를 변경하려 합니다.


사용 기술


이번 프로젝트에 사용된 기술입니다.

  1. zookeeper

  2. docker

  3. aws

  • ec2

  • java aws sdk


기대 효과


Feature Flag

특정 기능을 특정 인원에게만 접근할 수 있게 하여 운영환경에서 테스트 할 수 있게 하는 방법. 운영팀에서 원할 때 개발팀의 도움없이 해당 기능에 접근 할 수 있게하여 업무 효율성 증가.

Infra 구조 개선 및 기능 분리

config distribution 관련 기능을 Bastion 서버와 api 서버에서 분리하여 admin server에서 모두 처리하게 하여 각 서버는 core logic에 집중할 수 있게됨. 또한 config distribution 과정도 간단해짐.


Infra 구조


기존의 Infra 구조

먼저, 기존 Between 서버에서 config distribution을 위한 infra 구조입니다. 개발자가 Bastion에 접속하여 python 코드를 실행시키면 주키퍼에서 global path의 data를 가져와서 Bastion local에 json파일로 저장합니다. 그리고 vi 명령어를 통해 json파일을 수정하고 수정된 파일을 api 서버 에 복사합니다. 그리고 api 서버에서 globalConfigurationUpdater.java를 실행시켜서 api 서버에 저장된 json파일로 주키퍼에 update 요청을 보내고 주키퍼에 등록된 watcher에 의해 distribution이 진행됩니다.

globalConfigurationUpdater.java 코드만 Bastion환경에서 실행시킬 수 있으면 api 서버를 중간에 거쳐서 distribution을 수행할 필요가 없어집니다. 다음은 프로젝트 수행 후 바뀐 infra 구조입니다.

바뀐 Infra 구조

api 서버를 거칠 필요가 없어져서 기존의 Bastion역할을 하는 Admin server에서 바로 주키퍼에 update요청을 보내는 것을 볼 수 있습니다.


결과물 (Demo)


admin page에 접속하면 /between path 하위에 있는 path들을 주키퍼로 부터 받아옵니다. 각 path에서 수정할 수 있는 기능은 하위 경로를 선택하거나 ‘현재 경로 선택’을 하여 해당 경로의 data를 수정하거나 현재 경로에 새로운 경로를 추가하여 주키퍼의 해당 path에 새로운 znode를 생성하는 것입니다. 이번 프로젝트에서 수정할 /global을 선택하겠습니다.

/between/global path에 있는 znode를 수정해보겠습니다.

위의 사진은 json 데이터를 웹 페이지에서 수정하고 ‘비교’버튼을 누른 사진입니다. 왼쪽이 수정전이고 오른쪽이 수정 후의 json data입니다. +, - 로 이전과 달라진 data를 한번 사용자가 한번 check 할 수 있게 하고 여기서 ‘수정’버튼을 누르면 주키퍼에 update 요청이 보내지고 distribution이 일어납니다. 그러면 결과적으로 admin page에서 api 서버의 모든 config data를 수정할 수 있게 되는 것입니다.


zookeeper update 요청 코드 리뷰


띵스플로우 노션의 “핵심테이블 / 문서/ Pigeon Globalconfiguration zookeeper 동작”으로 가시면 코드 리뷰가 자세히 되어있습니다. 여기에는 코드를 올릴 수 없는 관계로 간단히만 적겠습니다.

코드의 목적은 안전하게 zookeeper update를 수행하는 것입니다.

우선 configuration class가 중요한데 json파일의 class형태라고 보시면 됩니다. 이 class를 수정한 json파일과 매핑시켜 validation을 진행합니다. 따라서 json파일을 수정하기 위해서는 configuration.java 파일도 수정해 주어야 합니다. 번거롭지만 configuration을 잘못수정하면 치명적이므로 개발자의 실수를 최대한 줄이기위한 안전 장치입니다.

이외에는 발생할 수 있는 상황에 대한 예외처리입니다. zookeeper를 update 한 후에 zookeeper의 data를 다시 한번 읽어와 json파일과 비교함으로써 update가 제대로 수행되었는지 check하고 안되었으면 예외를 발생시킵니다. 또한 update를 수행할 때 해당 path에 node가 없으면 node를 생성합니다.

이 모든 zookeeper와 관련된 처리는 curator라는 주키퍼에서 제공하는 라이브러리를 통해 수행됩니다. curator객체를 생성해서 zookeeper와 연결하면 zookeeper와 관련된 다양한 메소드를 사용할 수 있습니다. 대표적으로 create / delete / checkExist / getData / setData / getChilderen 등이 있습니다. getChildren은 해당 path의 하위 path들을 불러오는 메소드 입니다.

이외에도 watcher를 등록하는 메소드도 제공합니다. watcher를 등록하면서 node가 추가/제거/수정 되거나 reconnection이 발생하면 수행될 callback 함수를 정의해줘야 합니다. 그런데 사실 zookeeper에 update요청을 하는 로직에 watcher는 필요가 없습니다. update 요청은 메소드로 처리되기 때문에 watcher가 작동하려면 돌아가는 api서버에서 curator 객체를 생성하여 watcher를 등록해야 합니다.

api 서버의 메인함수 injector호출 class에 global path에 watcher를 등록하는 코드가 있었습니다. 여기서 의문점이 하나 생겼는데 zookeeper에 update 요청을 날릴 때는 curator객체에 굳이 watcher를 등록할 필요가 없는데 왜 그랬는지 입니다. “어차피 메소드가 완료되면 객체들도 다 삭제되기 때문에 watcher를 다는 코드가 큰 오버헤드를 발생시키지 않아 불필요하게 메소드를 추가 생성하지 않은 것 같다”가 제 결론입니다.


정리


http://channy.creation.net/blog/1620 참조

먼저 못한점으로 zookeeper watcher에 대한 부족한 이해를 뽑았습니다. zookeeper curator의 watcher 등록부분에 대한 자료가 부족하여 코드를 뜯어보았지만 충분한 이해가 되지 않았습니다. 이후에 기존 between코드를 크게 수정하려면 해당 logic을 이해해야 하므로 아쉬운 점이었습니다.

잘한점은 api 서버 환경에서 돌아가던 코드를 admin server로 옮긴 것입니다. 그 과정에서 코드의 이해가 필요했고 라이브러리 버젼을 맞추는데 많은 시간을 소요했습니다. 결과적으로 api server를 거치지않고 distribution이 가능해졌습니다.

댓글남기기