Google spreadsheet 변경 여부를 텔레그램으로 받아보자

친구들과의 모임 하나는 매월 회비를 걷는다. 한 녀석이 총무를 하다가 내가 넘겨받게 되었는데 회비 입금과 사용내역을 Google spreadsheet으로 관리하고 있다. 가끔 수정하게 되는 문서이다보니 나도 링크를 별도로 보관하고 있지도 않고 친구들도 마찬가지. 따로 수정하고 링크 보내주는 것도 귀찮고 해서 문서 수정시에 그 친구들과 함께 사용하는 telegram 그룹으로 메세지를 날리는 봇을 만들어보기로 했다. 결국은 내가 총무를 하는 기간 동안 수행하게 될 ‘링크 복사 + 텔레그램 실행 + 그룹 선택 + 링크 붙여넣기’ 시간의 총합보다 더 많은 시간이 든 것 같지만…젠장…귀찮음이 줄었다는 데 만족하기로 했다. 이제 회비 문서를 수정하면 아래 이미지처럼 그룹 채팅에 초대한 bot이 수정된 문서 이름과 링크를 보내준다.

telegram-message

 

1. 어떻게 만들어볼까?

Telegram bot은 예전에 구현했던 걸 활용하기로 하고 python으로 가볍게 처리해보기로 했다. 처음엔 Flask 써서 REST API 구현한 후 내가 원하는 걸 컨트롤할까 했었는데 어차피 telegram bot으로 원하는 기능은 가능하니 패스. 문서 변경사항은 push notification이 가능하면 좋겠다고 생각했는데 없으면 없는대로 polling으로 가보자고 생각했다.

 

2. Google sheets API 검토

문서 변경사항을 감지하는게 중요하니 어떻게 알 수 있는지 조사를 해봤다. Spreadsheet이니 sheets API부터 검토. Python용 api client가 있어서 설치한 후 아래 링크에 나온 샘플을 약간 변경해서 실행했는데 변경사항을 알 수 있는 부분이 없었다. (API v4)

https://developers.google.com/sheets/quickstart/python

재밌는게 v3 버전에서 v4 버전으로의 migration은 어떻게 하는지에 대한 문서를 보니 아래 그림처럼 sheets API v3에는 updated 항목이 있어서 수정날짜를 알 수 있다.(v4에는 사라진건지)

google-sheets-api-v3

v3 API를 사용해 updated 시간만 비교해 어떻게 해볼까 생각했는데 언제 deprecated 될지 알 수가 없어서 다른 방법을 더 찾아보기로 했다.

 

3. Google drive API로 push notification 시도

Spreadsheet이나 docs 모두 Google drive에 올라가기 때문에 drive API에 쓸만한게 있는지 살펴보니 원하는게 떡하니 문서로 되어있다. (Receive Push Notifications) Google drive 내에 있는 모든 파일 혹은 지정한 파일의 변경사항을 push로 받는 방법이 기술되어 있는데 아래와 같은 과정을 거쳐야 한다.

(1) Domain 등록

Push notification이 날라오면 받을 곳이 필요한데 http로 날라오므로 web server 등의 위에 callback이 구현되어 있어야 한다. 이런건 익숙한 과정이지만 아무데나 막 보내지는 않겠다는 의지인지 사전에 google에 등록된 domain이어야 한단다. Google에서 인지하고 있는 domain인지 판단하는 기준은 몇가지가 있는 것 같은데 인증용 html 문서로 google에서 제공한 파일을 web server에 올려서 처리했다. 그냥 단순히 되는지 여부만 알려고 했을 뿐인데 상당히 귀찮았음. Domain 등록이 되면 Google API Console ‘사용자 인증 정보’ 메뉴에서 확인이 가능하다.

(2) SSL 설정

Domain 등록까지 완료되었으니 문제없을 줄 알고 push notification 받을 web application (python flask로 대충 만들어놓고)을 실행해보니 notification 대신 오류가 날라오는데 내용이 SSL이 아니라서 안된단다. 그래서 self sign한 key와 인증서 만들어서 적용한 후에 해보니 이번엔 무반응. 문서를 여러번 수정해도 push가 없었다. 내가 찾지 못한 것인지 제공되지 않는 건지 모르겠지만 Google API Console에서는 API 호출 횟수와 성공 실패 여부, 반응 속도 등은 표시되는데 실패한 경우 왜 실패했는지에 대한 로그나 내용을 확인할 수 없었다. 대신 stackoverflow에서 찾은게 self sign 인증서로는 받을 수 없다는 내용. (http://stackoverflow.com/questions/17831828/not-getting-google-drive-push-notifications) 내가 직접 파악한 내용이 아니기 때문에 저 내용이 맞는지는 검증을 해봐야 아는 문제이지만 이미 충분히 귀찮아진 상태여서 push는 포기.

 

Push notification 문서를 보면서 인증과 관련된 내용을 함께 살펴보게 되었는데 유용했다. Google api client 사용하면서 OAuth 2.0 인증시 사용자가 요청된 권한을 확인한 후 허가하는 부분이 거의 필수로 들어가 있었는데, (서버 측에서 활용할 경우를 위해) service account를 만들어서 전체 service에 대해 권한을 위임하는 방식을 사용하면 저 과정이 필요없었음.

https://developers.google.com/drive/v3/web/about-auth

https://developers.google.com/identity/protocols/OAuth2ServiceAccount

 

4. 다시 Polling

Push 받는 건 귀찮아서 포기했고 sheets API를 사용하면 변경 여부를 확인하기 어려우니 drive API를 더 살펴보기로 했다. 다행스럽게도 push는 아니지만 변경사항을 알 수 있는 API가 있어서 사용하기로 결정.(https://developers.google.com/drive/v3/web/manage-changes) 아래와 같은 방식으로 API를 사용해야 한다.

(1) 최초에 startPageToken 가져오기 (changes.getStartPageToken)

(2) (1)의 token을 pageToken으로 해서 변경사항 가져오기 (changes.list)

(3) (2)에서 변경사항이 생기면 response에 newStartPageToken이 있으므로 그 값을 새로운 pageToken으로 update

(4) (2)~(3) 과정 반복

아래처럼 넘어오는 response를 parsing해서 처리하면 된다.

google-drive-changes-list

 

5. telepot 변경사항

오랜만에 telegram bot python library인 telepot 사용해보니 그 사이 변경사항이 있어서 과거에 구현했던 telegram bot을 그대로 사용할 수 없었다. 내가 사용하던 기능과 관련된 변경사항은 아래 두 가지.

(1) notifyOnMessage 함수 변경 => message_loop

(2) glance2 제거됨 => 대신 glance 사용

상세 변경사항은 change log 참조.

 

6. 결론

모든 파일의 변경사항을 알 필요는 없었기 때문에 telegram bot에 문서 id 등록 기능을 추가해서 변경사항이 발생하면 등록 여부를 간단히 판단해서 등록된 문서일 경우에만 메세지를 보내도록 처리했다.

Google drive API의 변경사항 가져오는 API를 반복적으로 테스트 해봤는데 모든 변경사항을 잡는 것은 아닌 것 같다. 뭔가 규칙이 있는 것 같기도 했는데 몇 분 이내에 반복적으로 발생하는 모든 변경사항을 수정이라 인지하지는 않는다. Google drive에서 직접 파일 속성 같은 걸 확인해봐도 마찬가지여서 정책이 아닌가 싶다. (셀 하나하나 수정한다고 모두 각각의 변경사항이라고 판단해도 문제일 듯) 혹시 이런 것 때문에 push가 날라오지 않은건가 싶어서 나중에 다시 시도해볼 생각.

Juju로 Ceph을 deploy 해보자

Ceph의 manual deploy를 진행해봤으나 앞서 “Ceph을 설치해보자“에서 기술한 것처럼 ceph-deploy를 사용하는 방법만큼 공식 문서에 문제가 있어서 포기하고 juju로 해보기로 했다.

 

1. 준비

(1) Bootstrap

Juju로 deploy 하기 위해서는 사전에 bootstrap이 진행되어 있어야 한다. Juju version 1.25 기준 인프라로 AWS, Azure, VMWare, GCE, Joyent, Manual 등을 지원하는데 Azure에서 해보기로 했다. Bootstrap을 완료하고 status를 확인하면 아래 그림처럼 status server가 하나 보인다.

ceph-juju-status(2) yaml 준비

Ceph charm 문서를 보면 배포하기 전에 설정파일 안에 fsid와 monitor-secret 값을 필수로 넣으라고 명시되어 있다.

ceph-yaml

<출처 : https://jujucharms.com/ceph/xenial/3>

fsid는 uuid나 uuidgen을 실행하면(없으면 설치) 생성 가능하고 monitor-secret 값은 아래의 명령으로 생성할 수 있는데 cluster 공통으로 사용할 것이라 배포될 ceph node 안에서 생성되는게 맞을 것 같지만 배포 전이므로 임의의 장비에서 생성해봤다. (결론은 문제는 없는데 ceph-common가 설치되어 있어야 monitor-secret 값 생성이 가능해서 좀 이해가 안되는 부분)


# generate monitor-secret

ceph-authtool /dev/stdout --name=mon. --gen-key

Charm 문서에는 osd-devices 라는 항목에 대해서도 기술되어 있는데 굳이 설정파일에 넣을 필요는 없고 나중에 juju set 명령으로 설정하는게 가능하다. osd-devices는 실제 osd가 사용할 경로로 mount 된 disk 이거나 일반 directory를 지정하면 되는데 존재하지 않는 경로라면 생성 후 권한 설정까지 알아서 진행된다. 나중에 설정할거라면 배포 후에 아래의 명령을 사용한다.


juju set ceph osd-devices=path_for_osd

 

 

2. Ceph 배포

Ceph 배포는 간단하게 아래 명령으로 완료된다. 1-(2)에서 ceph.yaml 이란 이름으로 파일을 생성해서 그 파일을 설정파일로 지정했고 3개 instance에 배포하라고 해놨다. 배포를 시작하면 instance를 추가해서 ceph 설정까지 알아서 진행되고 완료되면 서비스가 active 상태로 변경된다.


juju deploy -n 3 --config ceph.yaml ceph

배포는 되었어도 아직은 ceph이 외부와 연결된게 없으므로 3개 중 하나의 instance에 접속해서 sudo ceph -w (ceph-deploy를 사용할 때와는 다르게 root 권한이 필요) 를 실행해보면 아래 그림처럼 상태를 확인할 수 있고 sudo ceph osd tree 명령으로 osd가 모두 정상인 것도 확인 가능하다.ceph-healthy

설정했던 osd-devices가 어떻게 되어있는지 확인해보니 위에서 언급했던 것처럼 경로 생성부터 권한 설정까지 모두 완전하게 처리되어 있었다.

ceph-ls

3. OSD 확장

실제 ceph을 활용할 때 확장할 가능성이 높기 때문에 확장이 잘 되는지 살펴보기로 했다. 역시 간편하게 아래의 두가지 명령만 실행하면 확장은 끝난다. 단, 사전에 ceph-osd charm이 사용할 설정 파일을 만들어줘야 하는데 이미 존재하는 ceph cluster에 붙일 것이기 때문에 fsid 등이 필요하지는 않고 osd가 사용할 osd-devices 만 지정해주면 된다. 2에서 cluster 구성을 할 때에는 osd-devices로 /ceph-disk 라는 경로를 설정했는데 확장시 어떻게 되는지 살펴보기 위해 이번에는 /added-disk라고 설정했다.

ceph-osd-yaml

<출처 : https://jujucharms.com/ceph-osd/xenial/3>


# deploy ceph-osd to two instances

juju deploy -n 2 --config osd.yaml ceph-osd

 

# add relation

juju add-relation ceph-osd ceph

ceph-osd deploy가 완료된 후에 최초 cluster가 구성된 node 중 하나에 접속해서 상태를 보면 아래의 그림처럼 모두 5개의 osd가 올라와있음을 확인할 수 있고 사용 가능한 storage 용량도 증가되었음을 알 수 있다. (약 76GB => 124GB)

ceph-healthy-after-expand마지막으로 확장된 osd에만 다르게 적용했던 osd-devices 경로는 어떻게 되어있는지 확인해보니 이전에 구성된 cluster에는 변화가 없고 추가된 osd만 지정한 경로(/added-disk)를 사용함을 알 수 있었다.ceph-ls-after-expand

4. 결론

ceph-deploy를 사용하면서 경험했던 문제들은 charm을 만든 사람이 개선했는지 전혀 나타나지 않았고 너무 간편하게 배포할 수 있었다. 아마 이미 존재하는 instance에 배포할 때를 위해 준비해둔 것이 아닌가 싶은데, 초기에 cluster 구성하면서 설정했던 fsid, monitor-secret은 별도 지정하지 않는 이상 charm 내부에서 생성해서 설정하도록 되어 있으면 더 좋았을 것 같다. 이제 deploy는 가볍게 해결할 수 있으니 실제 활용 측면에서 어떤지 살펴볼 생각이다.

 

5. 참고

(1) Ceph charm

(2) Ceph osd charm

(3) Juju commands

Ceph을 설치해보자

Ceph cluster 구성을 할 때 가장 중요한 요소는 ceph monitor와 osd 이다. “Ceph 가볍게 살펴보기“에서 기술한 것처럼 osd는 실제 object 저장을 담당하고 monitor는 node의 상태 확인이나 cluster map 정보를 담고 있기 때문. 공식 문서에 있는 설치 방법은 manual과 ceph-deploy라는 자동화 스크립트를 이용하는 방법으로 나뉘어 있는데 ceph-deploy를 사용해 보기로 했다. 공식 문서에 누락된 내용도 있고 ceph-deploy 스크립트 자체에 문제도 있는 것 같아서 함께 기술할 생각이다.

참고 : ceph-deploy를 사용한 Ceph 설치 공식문서

 

1. 준비

(1) VM

실제 꼭 필요한 것은 아니지만 ceph-deploy로 각 node를 관리하기 위한 ceph-admin과 cluster를 구성할 ceph-node01, ceph-node02 총 3대의 VM (Ubuntu 14.04)을 준비했다.

(2) SSH / hosts 설정

편의를 위해 ~/.ssh/config에 각 node의 Hostname, User 등록.

ceph-deploy가 일부 설정에서 각 node의 실제 hostname을 가지고 파일을 생성하거나 처리하는 경우가 있고 host 인식을 위해 /etc/hosts에 실제 cluster node의 hostname과 IP를 등록해둔다. 아래는 ceph-admin에서 지정한 hostname이 실제 node의 hostname과 달라서 생기는 오류 (admin node에서 하위 node의 hostname을 node1이라고 지정했을 때 ceph-deploy가 ceph-mon.node1.asok 파일을 찾으려고 하지만 실제 그 경로에 가보면 ceph-mon-ceph-node01.asok 파일이 생성되어 있었다)

ceph-install-host-error

2. ceph-deploy 설치

ceph-admin에서 아래의 command로 설치하면 되는데 hammer (ceph release name)라고 지정해도 이후 ceph 설치과정에서 ceph-deploy가 repository를 자동으로 최신인 jewel로 변경해버린다.


wget -q -O- 'https://download.ceph.com/keys/release.asc' | sudo apt-key add -

echo deb <a href="http://download.ceph.com/debian-hammer/">http://download.ceph.com/debian-hammer/</a> $(lsb_release -sc) main | sudo tee /etc/apt/sources.list.d/ceph.list

sudo apt-get update &amp;&amp; sudo apt-get install ceph-deploy

 

3. ntp / openssh-server 설치

Ubuntu 14.04 설치했을 때 이미 ntp와 openssh-server가 설치된 상태였지만 혹시 설치되지 않은 상태라면 설치해둔다. (NTP는 각 node간 시간 동기를 위해 필요하다고 가이드 하고있음)

 

4. Ceph user 추가

공식문서에는 ceph 설치와 관리를 위한 별도 user를 생성하라고 되어 있고 보안 및 기타 이유로 ceph이라는 이름은 사용하지 말라고 명시되어 있어서 cephuser라는 이름으로 사용자를 생성하고 sudoer로 등록했으나 실제 파일 생성 등의 작업은 ceph이라는 사용자로 진행이 되는 것으로 보인다.  아래의 command를 이용하거나 별도의 방법으로 모든 node에서 user 추가 (home 디렉토리는 추가되어야 함)


sudo useradd -d /home/cephuser -m cephuser

sudo passwd cephuser

# set password

 

echo "cephuser ALL = (root) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/cephuser

sudo chmod 440 /etc/sudoers.d/cephuser

 

5. SSH keygen / 공개키 복사

ceph-deploy가 사용할 때가 있으므로 ceph-admin의 ssh keypair를 생성하고 각 node에 복사해준다.


ssh-keygen

ssh-copy-id cephuser@ceph-node01

ssh-copy-id cephuser@ceph-node02

 

6. Network / firewall 설정 (Optional)

Public network, cluster (internal) network으로 분리해서 설정하는 내용이 문서에 있으나 내부 IP로만 연결할 생각이어서 별도 조치없이 넘어감

 

7. ceph-deploy가 사용할 디렉토리 생성

현재의 working directory에서 ceph-deploy가 필요한 파일들을 생성하고 가져오므로 별도 디렉토리를 만들고 그 안에서 ceph-deploy를 실행하는게 좋다.


mkdir cluster && cd cluster

 

8. Monitor node 생성 / pool size 설정

Monitor가 돌아갈 node를 지정하는 내용으로 편의상 ceph-node01만 지정 (나중에 추가도 가능)


ceph-deploy new ceph-node01

이 과정을 거치면 working directory에 ceph.conf 파일이 생성되는데 osd pool 크기를 지정해줘야 한다. osd 하나에 파일을 저장하고 하나는 replicate 용도로 사용할거라 2로 지정


# add this in global section of ceph.conf

osd pool default size = 2

 

9. Ceph 설치

이제 ceph과 관련된 것들을 설치하는 과정을 수행하면 된다. Admin node에서 설치할 node를 지정할 수 있는데 아래처럼 admin node 포함 전체 node에 설치하도록 했다. (이 과정인지 다른 과정에서 자동으로 ceph repository가 최신인 jewel로 변경되는데 release 등의 option이 있어서 다른 버전 설치가 가능한 것처럼 보이지만 실제 option을 줘서 hammer로 강제 설정한 결과 오류 발생)


ceph-deploy install ceph-admin ceph-node01 ceph-node02

 

10. Monitor 초기화

Ceph까지 설치했으면 monitor 초기화를 해야 한다.


ceph-deploy mon create-initial

 

11. OSD 설정

(1) OSD가 사용할 경로 추가

OSD가 돌아갈 각 node에서  osd가 사용할 경로를 추가해준다. 여기서 중요한게 뒤에 있는 숫자를 임의의 숫자로 변경하면 나중에 activate 과정에서 오류가 발생한다. Manual 설치 과정을 잠깐 봤을 때 osd node 각각에 순서대로 숫자를 부여해서 그 숫자를 이용해 내부적으로 뭔가 작업을 하는 것 같은데 잘 이해가 안되는 부분이다.


# in ceph-node01

sudo mkdir /var/local/osd0

 

# in ceph-node02

sudo mkdir /var/local/osd1

(2) Prepare osd

이제 osd를 준비하는 초기화 과정인데 ceph-admin에서 아래의 command를 실행한 후 메세지를 유심히 보면 생성하는 몇 개 파일의 owner를 변경하는 과정을 확인할 수 있다.


ceph-deploy osd prepare ceph-node01:/var/local/osd0 ceph-node02:/var/local/osd1

ceph-chown(3) Activate osd

(Activate 하기 전에 각 osd path의 owner, group을 ceph으로 변경해주어야 함)


# in nodes

sudo chown -R ceph:ceph /var/local/osdX

위 그림처럼 일부 파일의 owner 설정과정을 언급한 이유는 activate 과정에서 오류가 발생하기 때문인데

ceph-osd-permission-error재미있는게 아래 그림에서처럼 ceph-deploy가 몇 개 파일만 owner 지정을 자동으로 하고 디렉토리 자체는 생성했을 때의 사용자 소유로 그대로 두고 있어서 권한 문제가 발생할 수 밖에 없다. (공식 문서에서 누락된 내용이기도 하고 스크립트 자체가 문제가 있다고 보여짐)

ceph-osd-path-permission그렇기 때문에 사전에 osd가 사용할 경로의 owner를 변경해주는게 꼭 필요하다. Activate은 아래의 command 실행


ceph-deploy osd activate ceph-node01:/var/local/osd0 ceph-node02:/var/local/osd1

 

12. Node 설정 및 keyring 파일 복사

ceph-admin에서 아래의 command를 실행하면 각 설정 및 keyring 등 필요한 파일이 /etc/ceph 경로에 복사되는데 그 후에 keyring 파일의 읽기 권한을 추가해줘야 한다.


ceph-deploy admin ceph-admin ceph-node01 ceph-node02

sudo chmod +r /etc/ceph/ceph.client.admin.keyring

 

13. Health check

기본 설정은 다 완료된 것이므로 각 node와 osd가 정상인지 ceph-admin에서 확인해본다. HEALTH_OK가 나오면 정상.


ceph health

 

14. 결론

ceph-deploy를 사용한 설치는 몇가지 문제가 있는 것으로 보이기 때문에 이후에 manual로 설치를 다시 해서 과정이나 기타 내용들을 좀 더 깊게 살펴본 후에 가능한 자동화까지 진행해보는게 좋을 것 같다. 또 확장이 용이한지 문제가 발생했을 때 복구 같은 것들은 어떻게 할 수 있는지 performance 측면에서 쓸만한지 등의 내용도 검토해볼 필요가 있겠다.

 

Ceph 가볍게 살펴보기

1. Ceph은 무엇인가?

분산 object store이자 file system으로 분산 클러스터 위에서 object storage를 구현해 object, block, file level의 storage 인터페이스를 제공한다. 하나로 object / block storage, file system 모두를 제공한다는게 장점. SPOF 없는 완전한 분산처리와 exabyte 단위까지 확장 가능하다고 한다.

 

2. Ceph architecture

20160801_ceph-stack

<출처 : http://docs.ceph.com/docs/master/architecture/>

실제 data 저장을 담당하는 것은 RADOS이고, CephFS (File System)는 FUSE 지원으로 RADOS에 직접 access가 가능하다. RBD는 일반적인 block device로 붙일 수 있도록 구성된 것으로 LIBRADOS를 통해 RADOS에 access 하도록 되어있고 RADOSGW 역시 LIBRADOS를 통해 object store에 접근할 수 있다. Application이 data를 block device로 ceph에 저장할 경우 ceph은 data를 잘라서 cluster에 replicate 한다.

 

3. 구성요소

(1) ceph-mon

Cluster monitor로 active / failed node 확인하는 역할을 수행하며 ceph storage cluster map의 master copy를 유지하고 각 cluster client들은 ceph monitor로부터 cluster map 정보를 가져가도록 되어있다.

(2) ceph-mds

Metadata server로 inode와 디렉토리들의 메타데이터(filesystem의 디렉토리 및 파일이름, RADOS cluster에 저장된 object로의 매핑정보) 를 저장하며 역시 cluster 구성이 가능하기 때문에 확장 및 cluster host 사이에서의 동적인 data 분산이 가능하다.

(3) ceph-osd

Object storage devices. 실제 파일 내용을 저장하고 OSD의 상태를 확인해서 monitor에 알려주는 역할도 수행한다. 일반적인 cluster system들은 중앙에서 lookup 테이블을 관리하거나 특정 component를 두고 각 client 들이 그 component에 접근하도록 되어있지만 이런 방식이 갖는 performance, scalability, SPOF 관점에서의 제한사항들 때문에 각 client 끼리 상호작용할 수 있도록 CRUSH 알고리즘이란 것을 사용해 OSD daemon에 직접 접근하도록 되어있다.

(4) ceph-rgw : RESTful gateways. Object storage layer를 외부에 노출시키기 위한 인터페이스

 

4. 참고

(1) http://ceph.com/

(2) https://en.wikipedia.org/wiki/Ceph_(software)

(3) http://docs.ceph.com/docs/master/architecture/

 

MyBatis와 싸우면서 얻은 것들

Java로 간단한 console application을 만들다가 이상한 문제들을 마주하게 되었다.  그 중 하나는 DB 연결이 계속 끊어지는 현상. 현재 시점에서도 DB에 가해지는 부하는 정말 작은 수준이었기 때문에 특별히 tuning할 이유는 없었고 퍼포먼스와 관련해서는 기본 설정값으로 사용하고 있었는데 끊어지는 이유를 알 수가 없었다. (MySQL 5.5의 default wait_timeout은 8시간)

1. 환경

Application 동작의 흐름은 DB select, 특정 행위, DB update 순서였는데 특정한 기능을 수행하는게 길게는 20분 정도 혹은 그 이상 소요되는 경우가 있었고 편의를 위해 MyBatis를 사용했으며 pool을 사용하도록 설정해 두었다. 연결이 끊어지는 현상을 보고 poolPingQuery, poolPingEnabled를 설정해 봤는데 마찬가지.

2. Azure에 idle timeout이 있다

우선은 MyBatis 설정과 별개로 왜 DB연결이 끊어지는지 궁금해졌다. DB와의 연결은 어차피 socket을 사용하기 때문에 DB와 application 사이의 통신에 영향을 줄 수 있는 것들은 많다. MyBatis 아래의 JDBC, Kernel의 socket timeout, 공유기 설정 등을 살펴봤는데 특이한 내용은 발견할 수 없었다.

다음으로 Azure에 어떤 특성이 있지 않을까 싶어서 알아보니 따로 idle timeout이 있다고 한다. 기본값이 4분이라고 하는데 테스트한 내용과 정확히 맞는다. (강제로 sleep 시간을 늘려가며 테스트해보니 3분까지는 문제가 없었고 4분부터 연결이 끊김을 확인) 이런 내용은 Azure 문서에 잘 보이지 않고 설정 또한 UI로는 불가능하다. PowerShell로만 가능한데 현재 열려있는 endpoint를 확인해보면 공백으로 표시되고 있고 powershell로 IdleTimeoutInMinutes 값을 30분까지 늘릴 수 있다고 한다.

3. Pool ping에 대한 잘못된 소문

Azure의 idle timeout과 별개로 MyBatis의 poolPing에 대해서 살펴보기로 했다. Pool ping 설정 중에 poolPingConnectionsNotUsedFor 가 있는데 문서 상으로는 마치 설정된 시간에 한번씩 DB에 ping으로 설정된 쿼리를 날려서 연결을 유지해줄 것처럼 보인다. 국내의 대부분 블로그 등에서도 비슷하게 설명하고 있다. 하지만 이 내용은 공식 문서가 잘못된 것인지 예상한대로 동작하지 않는다. 거의 동일한 의문을 가진 해외 사용자의 글을 보기도 했는데 소스를 보면 connection pool에서 실제 connection을 꺼내오거나 넣을 때만 connection이 유효한지 확인을 하는데 이 때 pool ping과 관련된 작업을 수행한다. poolPingConnectionsNotUsedFor에 설정된 값은 connection 유효성을 확인할 때만 영향을 주기 때문에 pool에서 connection을 꺼내오고 집어넣는 시점 이외에는 전혀 영향을 주지 않는다.

4. 결론

Azure나 기타 환경에 대한 timeout 값을 늘리는 것은 좋은 방법은 아니라고 본다. DB connection을 오래도록 유지해야만 하는 상황이라면 별도의 장치를 두어서 connection을 유지하도록 조치하거나 아니면 아예 비용이 소모되더라도 필요한 상황에서만 connection을 맺고 끊는 게 나을 것 같다..

5. 참고

(1) MyBatis 공식문서

http://www.mybatis.org/mybatis-3/configuration.html

(2) MyBatis 참고 소스

https://github.com/mybatis/mybatis-3/blob/mybatis-3.3.1/src/main/java/org/apache/ibatis/datasource/pooled/PooledDataSource.java

https://github.com/mybatis/mybatis-3/blob/mybatis-3.3.1/src/main/java/org/apache/ibatis/datasource/pooled/PooledConnection.java