코레일 명절 기차표 예매 시스템에 관한 고찰

by 컴토피아 posted Jan 17, 2013
?

단축키

Prev이전 문서

Next다음 문서

ESC닫기

크게 작게 위로 아래로 댓글로 가기 인쇄

capture_01.jpg EXIF Viewer사진 크기1084x898

부제: 왜 코레일 명절 기차표 예매 시스템은 쉽게 맛탱이가 갔는가?

사실, 말하자면 명절 기차표 예매 시즌때마다 그 기차표 하나 놓치지 않기 위해 나는 별의별 짓을 다해봤다. 그래도 다른사람들처럼 표를 몽땅 쓸어담아서 되팔만큼 사재기를 하거나 하지는 않고, 딱 우리 가족이 필요한 만큼만 구매하니, 그나마 양호한 편이다. 그 때는 창을 막 30개씩 열기도 하면서 생쇼를 했다. 그래도 그때는 그리 쉽게 서버가 맛이가지 않았다.

 

그럼 대체 왜 이번엔 유달리 코레일 서버가 쉽게 맛탱이가 가셨을까?

우선 1차적 원인은, 엄청난 인원이 접속을 시도하면서 일어난 서버 과부하가 가장 근본적인 원인일 것이다. 한 순간에 갑자기 국민 대 다수가 접속을 하면서 일어난 문제이다.

하지만, 그 문제뿐만이 아니다. 우선, 프로그램 상으로 분석해보기 시작했다. 자세히 들여다 보면 그 속에는 코레일 명절 기차표 예매 시스템에도 문제가 있었다. 지난 2012년 설 기차표 예매 이후로 코레일의 명절 기차표 예매 시스템에는 크고 작은 변화가 있었다.

제일 큰 변화가 예매요청(쿼리)방식을 일반적인 방법에서 POST방식으로 바꾼 것이다. 그래서 프로그램이 해야 할 일과 자바스크립트 상의 코드는 더 간결해졌지만, 문제는 이렇게 처리된 결과물을 넘겨받는 서버의 부하가 심해진다는 것이다.

 

capture_02.jpg EXIF Viewer사진 크기1440x760

예전 일반적인 방식으로는, 실제 예매에 필요한 값만 URL로 넘겨주어 팝업을 열게 하였다. 쿼리는 실제 예매에 필요한 만큼만 있었고, 필요없는 요청 값은 거의 없을 만큼 매우 양호한 수준이었다.

하지만 POST 방식으로 바꾸면서 사실 상 예매과정에서 필요없는 요청은 물론, 똑같은 값을 두 번 중복해서 보내는 헛수고까지 하시느라 쿼리의 수는 2배 가까이 불어났고, 이는 곧 서버의 과부하에 한 몫을 하게 된다. 접속자 수가 별로 없다면, 이는 서버에 별다른 영향을 미치지 않았을 것이다.

하지만 명절 기차표는 예매 특성상 아이폰 구매 예약, 콘서트 티켓, 야구장 관람 티켓 등에 비해 엄청난 인원이 코레일 서버로 몰리게 된다. 거의 전 국민 중 대 다수 이상이 예약을 시도할 것이다. 이렇게 인원이 몰리게 된다면 이 2배이상 늘어난 쿼리는 서버에 영향을 미치기 시작한다. 즉 서버의 과부하도 실제로 그 만큼의 과부하가 오진 않겠지만, 늘어난 요청을 받아들이기 위해 1.5배 내지 2배 정도 빠르게 온다는 것이다.

 

왜 똑같은 사람이 표 하나를 예매할 뿐인데 요청은 2배로 불어났을까?

코레일은 특이하게, 사용자가 입력한 정보를 가지고 그대로 보내는게 아닌, 비슷한 변수로 그 값을 그대로 가져와 그 변수를 사용자가 입력한 값으로 수정하는 작업을 거친 뒤 최종적으로 그 쿼리를 토대로 서버로 보내게 된다.

예를들면 사용자가 명절 예매 당시 휠체어석을 요청하기 위해 드롭다운 박스에서 '휠체어석'을 선택하게 되면 txtSeatAttCd 값을 다른 값으로 바꾸게 되는데 이 값을 기반으로 txtSeataAttCd 값도 수정한 다음 최종적으로는 txtSeataAttCd 값 만을 서버에 전송하는 식으로 이루어 졌다.

하지만 POST로 바뀐 뒤의 명절 예매절차는, 필요없는 요청을 보낼 뿐 만이 아니라, 저런 특이한 구조의 예매시스템 덕분에 불필요한 값을 2번이나 반복하여 보내는 과잉친절 배푸는 프로그램이 되었다. 혹여나, 서버가 실수할까봐 값을 두번이나 보내는건가? ㅎ

즉, 위에서 나온 txtSeatAttCd 값과 txtSeataAttCd 값 모두 결국은 '휠체어석'을 달라는 말인데 똑같아서 사실 상 하나는 보내지 않아도 되는데도 불구하고 요청하는 식이다.

즉 한 명이 요청하면 두 번 서버로 날리는 꼴이 되고, 결국 두 명이 요청하면 네 번 서버로 날리는 꼴이나 마찬가지다. 결국은 서버에 과부화를 가져올 수 있다는 말이다. 설렁 서버가 그 값을 무시하더라도, 일단 POST로 보낸 이상 일단 서버는 받아들인 뒤, 프로그램 상에서 필요없는 값이라면 그 때 되어서야 정작 버리기 때문이다.

 

http://www.korail.com/servlets/bt.pr12100.sw_pr12111_i1Svt?txtDptDt1_1=20120208&radIngrDvCd=1&strMemberNo1='회원번호'&strMemberNo2=&txtPswd1='비밀번호'&txtPwd2=&txttPsgTpCd1=1&txttPsgTpCd2=3&txttPsgTpCd3=1&txttPsgTpCd4=3&txttPsgTpCd5=1&txttPsgTpCd6=1&txttPsgTpCd7=1&txxtDiscKndCd1=&txxtDiscKndCd2=&txxtDiscKndCd3=P21&txxtDiscKndCd4=P21&txxtDiscKndCd5=P41&txxtDiscKndCd6=P11&txxtDiscKndCd7=P22&ttxtCompaCnt1=1&ttxtCompaCnt2=0&ttxtCompaCnt3=0&ttxtCompaCnt4=&ttxtCompaCnt5=0&ttxtCompaCnt6=&ttxtCompaCnt7=0&txtTotPsgCnt=1&txtComeFlag=false&txtGoStart1_1=서울&txtGoEnd1_1=부산&txtGoStart2_1=부산&txtGoEnd2_1=서울&txtJobId=1191&txtSeataAttCd1=00&txtSeataAttCd2=00&txtSeataAttCd3=00&txtSeataAttCd4=15&txtSeataAttCd5=00&txtStandFlg=0&txtSrcareCnt=0&txtJrnyCnt=1&radJobId1_1=1&radJobId2_1=1&txtTrnNoFlag1_1=false&txtTrnNoFlag2_1=false&txtTrainNo1_1=&txtTrainNo2_1=&txtDptTm1_1=000000&selGoTrain1_1=00&hidGoRoom1_1=1&txtDptDt2_1=20120208&txtDptTm2_1=000000&selGoTrain2_1=00&hidGoRoom2_1=1&checkStnNm=Y

http://www.korail.com/servlets/bt.pr12100.sw_pr12111_i1Svt?radIngrDvCd=1&strMemberNo1='회원번호'&strMemberNo2=&txtPswd1='비밀번호'&txttPsgTpCd1=1&txttPsgTpCd2=3&txttPsgTpCd3=1&txttPsgTpCd4=3&txttPsgTpCd5=1&txttPsgTpCd6=1&txttPsgTpCd7=1&txxtDiscKndCd1=&txxtDiscKndCd2=&txxtDiscKndCd3=P21&txxtDiscKndCd4=P21&txxtDiscKndCd5=P41&txxtDiscKndCd6=P11&txxtDiscKndCd7=P22&ttxtCompaCnt1=1&ttxtCompaCnt2=0&ttxtCompaCnt3=0&ttxtCompaCnt4=&ttxtCompaCnt5=0&ttxtCompaCnt6=&ttxtCompaCnt7=0&txtSeataAttCd1=00&txtSeataAttCd2=00&txtSeataAttCd3=00&txtSeataAttCd4=15&txtSeataAttCd5=00&txtStandFlg=0&txtSrcareCnt=0&hidGoTrain1_1=00&hidTrainNo1_1=&hidGoTrain2_1=00&hidTrainNo2_1=&txtMemberNo1='회원번호'&txtMemberNo2=&txtPwd1='비밀번호'&txtPwd2=&radJobId1_1=1&txtGoStart1_1=%BC%AD%BF%EF&txtGoStart1_1Code=&txtGoStart2_1Code=&txtGoEnd1_1=%BA%CE%BB%EA&txtGoEnd1_1Code=&txtGoEnd2_1Code=&selGoYear=2013&selGoMMDD1_1=0208&txtGoYoil1_1=%B1%DD&txtGoYoil2_1=%B1%DD&radTrainNo1_1=1&selGoHour1_1=00&selGoMinute1_1=00&selGoTrain1_1=00&selGoRoom1_1=1&txtPsgFlg_1=1&txtPsgFlg_2=0&txtPsgFlg_3=0&txtPsgFlg_7=0&txtPsgFlg_5=0&txtSetFlg_1=1&txtMemberNoHid=&txtMemberPwdHid=&txtCustNo=&txtPsgTpCd1=1&txtPsgTpCd2=3&txtPsgTpCd3=1&txtPsgTpCd4=3&txtPsgTpCd5=1&txtPsgTpCd6=1&txtPsgTpCd7=1&txtDiscKndCd1=&txtDiscKndCd2=&txtDiscKndCd3=P21&txtDiscKndCd4=P21&txtDiscKndCd5=P41&txtDiscKndCd6=P11&txtDiscKndCd7=P22&txtTotPsgCnt=1&txtCompaCnt1=1&txtCompaCnt2=0&txtCompaCnt3=0&txtCompaCnt4=&txtCompaCnt5=0&txtCompaCnt6=&txtCompaCnt7=0&txtSeatAttCd1=00&txtSeatAttCd2=00&txtSeatAttCd3=00&txtSeatAttCd4=15&txtSeatAttCd5=00&selGoSeat=15&txtJobId=1191&hidGoRoom1_1=1&hidGoRoom2_1=&txtStndFlg=0&txtSrcarCnt=0&txtJrnyCnt=1&txtComeFlag=false&txtTrnNoFlag=false&txtTrnNoFlag1_1=false&txtTrnNoFlag2_1=false&txtDptDt1_1=20130208&txtDptDt2_1=20130208&txtDptTm1_1=000000&txtDptTm2_1=000000&checkStnNm=Y

 

▲2012년 설 예매 당시 코레일 명절 예매 서버에 요청하던 쿼리

▲2013년 설 예매 당시 코레일 명절 예매 서버에 요청하던 쿼리

 

한 눈에 보아도 길이차이가 실감되지 않는가? 그렇다. 필요 없는 값과 중복되는 요청 값이 들어가면서 엄청나게 길어진 주소다. 이 쿼리는 2012년 추석예매부터 바뀐 것으로 파악하고 있다. 이렇게 길어진 주소는 결국 서버에 영향을 미치게 된다.

웹은 일반 프로그램과 다르게 용량에도 민감하다. HTML이나 CSS를 짜다보면 공백이나 엔터 한줄이라도 아껴보려고 노력하는 경우를 간간히 볼 수 있다. 한 줄 한 칸의 차이지만 모이면 제법 속도에 차이가 난다.

코레일도 결국 공식 웹사이트를 명절 예매 시간에 그대로 운영하게 되면 필요없는 홍보나 이미지/배너/링크를 가져오기 때문에 서버에 엄청난 과부하가 걸릴 걸 알고있었을테고, 그렇기 때문에 자체적으로 명절 기차표 예매를 위한 별도의 프로그램을 특정 일시에 운영했을 것이다.

하지만, 최적화되지 않은 POST 방식의 요청은 결국 이 최적화의 조건을 충족시키지 못하였다. 오르지 URL 요청 방식을 염두에 두고 짜여진 프로그램을 최적화 하지 않고 그대로 둔 채 POST 방식으로 바꾸었고, 그 결과는 기존 예매시스템의 2배에 달하는 엄청난 쿼리를 서버로 요청하는 것이 되어버렸다.

앞으로 POST 방식으로 운영하기 위해서는 이런 프로그램을 최적화 해야 할 것이다.

 

예매 시간 조정 건도 배제할 수는 없다

사실 오래 전 부터 새벽 6시부터 명절 기차표 예매를 시작하여 오전 8시에 마감하는 코레일에 굉장히 파격적인 변화가 하나 있었다. 바로 몇 년 동안 새벽 6시에 시작하던 예매가 지난 예매부터는 오전 7시로 조정되어 운영되더니, 이번엔 오전 11시로 조정하였다. 예전부터, 이 예매일시가 과연 효율적인지 등에 대하여 문제제기가 끊임없이 이어졌지만 변화가 없었다. 그러다가 이번에 이렇게 오전 11시로 크게 조정한 것은 굉장히 파격적인 변화라고 볼 수 있다.

코레일 관련 담당자는 직장인의 출근시간을 고려하여 오전 11시로 늦췄다고 하였다. 오전 시간대로 예매시간이 조정되며, 종전 새벽 6시에 시작되었던 예매에 비해 접속자수가 증가하였을 것이다.

 

우수회원의 명절 기차표 선 예매 혜택 폐지도 한 몫

capture_03.jpg EXIF Viewer사진 크기630x284

2012년 설 예매부터 코레일 멤버십의 최고등급, 즉 VIP회원이라 말할 수 있는 '다이아몬드회원'의 명절 기차표 선 예매 혜택이 폐지되었다.

하지만 단순히 서버측에서 본다면 이런 선 예매 혜택은 굳이 이렇게 미리 예매를 한 사람들은 일반 고객의 예매 시간에 코레일에서 다시 예매를 할 필요가 없기 때문에 트래픽 관리 측면에선 효율적이었다고 본다. 적절히 예매일을 조정하여 서로 다른 날짜에 예매를 하도록 하여 트래픽이 분산되어 서버의 과부하를 막는 역활도 톡톡히 했단 것이다.

이런 제도가 폐지되었기 때문에 이런 트래픽이 다수 유입되어 앞서 말했던 문제와 함께 곂쳐지면서 문제는 더욱 악화된 것이다. 물론 이 제도는 공공성과 암시장에서의 불법적인 이용 등 문제가 있었던 제도이기 때문에 공공적인 측면에선 폐지한 것이 맞았다고 본다. 하지만 그런 문제를 제외하고 오르지 트래픽 관리 측면에서 볼땐 그럭저럭 괜찮았던 방법이라 생각된다.

 

결론?

중요한 결론은 결국 하나다. 결국 프로그램을 개선하는 것이다. POST방식이 불법적인 과정으로서의 예매를 막을 수 있다는 잇점도 존재하긴 하지만, 현재로서는 잃는 점이 더 많는 것 같다. 예매 프로그램은 사람들이 많이 접속하는 만큼 한 줄이라도 더 줄이고 한 칸이라도 붙이며, 한 과정이라도 더 단순화 시켜 프로그램을 최적화하여야 더 많은 사람을 받으면서도 서버 과부화가 발생되지 않게 해 준다.

물론 코레일이 작년 추석부터 프로그램을 표준에 가깝게 수정하고 있고, 보다 보기좋고 효율적으로 관리할 수 있도록 만들기 위해 노력하는 것이 눈에 보인다. 하지만 무엇보다 동시접속자가 엄청나게 많은 프로그램 특성 상 가장 중요한 '최적화' 작업은 아직 이루어지지 않은 것 같았다.

우선 위에서 밝혔던 POST로 넘기는 쿼리를 단순화 하는 것이 가장 큰 과제일 것이다. 과거엔 이용되었지만 지금은 사용하지 않는 쿼리도 그대로 고정시켜놓고 전송하는 등 불필요한 쿼리가 너무 많다. 이런 쿼리를 하나 하나 줄여나간다면 예매 과정 중 서버가 맛탱이가 가버리는 현상을 조금이나마 줄일 수 있을 것이다.

그리고 조금이나마 트래픽관리를 할 수 있는 방법을 마련하는 것이다. 사실 이러한 대규모 트래픽을 앞두고 대책을 세우는게 뭐가 있겠나마는, 앞서 말했던 열차를 많이 이용해 준 VIP 이용자들을 위해 조금이나마 혜택을 위의 문제를 해결하면서 다시 제공하는 것도 나쁘지 않을 것으로 보인다. 물론 기업이 아닌 이익과 공공성을 동시에 추구하는 공기업인 코레일 입장에서는 다소 무리가 있는 방안일 수가 있다. 혹은 다른 방법으로 트래픽을 조절할 수 있는 방법이 있다면 그렇게 해보는 것이 당연 더 좋은 방법일 것이다.