반응형

 


 안녕하세요. 오늘은 최근 작업했던 특정 서비스의 웹 개편 작업 중 경험한 장애 상황에 대해 포스팅 해볼까 합니다. 새롭게 단장한 고객센터 페이지를 해당 서비스에 적용하고 테스트 까지 잘 맞췄었는데 그 다음 날 장애 상황을 경험하게 되었습니다.

먼저 현재 회사의 많은 서비스 고객센터 페이지가 API 형태로 붙게 되는데요. 그렇다보니 그 많은 서비스들의 고객센터 페이지를 계속해서 만들어 낼 수도 없는 상황인지라 사이트메쉬와 데코레이터 패턴을 이용하여 신규 서비스가 오픈하면 해당 서비스에 맞게 CSS를 입혀 서비스하는 방식으로 몇몇 서비스들이 이루어지고 있습니다. 최근 특정 서비스의 웹 리모델링에 맞춰 변경된 CSS로 작업을 진행하는 도중 문제가 발생했습니다.


[상 황]

 웹페이지의 리모델링에 맞춰 CSS작업 팀으로 부터 변경 된 CSS를 받아 특정 서비스의 고객센터에 적용해야하는 상황. 물론 CSS를 새로 받게 되면 로컬에서 CSS를 적용시켜보고 웹 페이지를 띄워 노출되지 않는 이미지가 있는지 깨지는 부분이 있는지를 확인하는 작업이 요구된다. 그렇게 여러번의 수정 작업을 마치고 페이코 웹 개편 작업 반영을 하게 되었다. 

 이번 같은 경우에는 해당 서비스의 메인 페이지 및 다른 부분도 모두 개편되는 부분이라서 여러 팀이 순서대로 반영을 하는 상황. 테스터 분들도 모두 동참하여 반영이 이루어졌다. 그렇게 모든 팀의 반영 및 테스트 작업이 약 7~8시간에 걸쳐 진행되었고 잘 마무리 짓게 되었다.


[ 문제상황 ]

반영이 끝난 그 다음날 오전 TTS(TROUBLE TICKET SYSTEM) 5급(등급이 낮을 수록 심각 1~5)을 맞게 되었다. 특정 서비스에 문제가 생길 경우 해당 사이트에 문제 상황이 뜨고 담당자에게 연락이 감. 문제는 고객센터 '1:1문의 페이지'에서 문의를 작성한 후 '완료'하는 버튼이 보이지 않는 상황이었다.

 

[동의란 밑에 아무 버튼도 노출되지 않고 있음]



[정상적인 모습]

 

그 문제상황을 보고 받고 속으로 '어떻게 그렇게 테스트를 여러번 했는데 문제가 났다는 게 말이되나?'하는 의구심을 받고 페이지에 접속한 결과 정상적으로 버튼이 노출되고 있는 것을 확인하였다. 그럼 그렇지 하며 익스플로러에서도 확인 결과 정상적으로 버튼이 노출되고 있는 것을 확인하였다. 


[문제원인 & 처리]

그렇게 뭐지???하고 생각하던 중 팀장님께서 외부망으로 접속해보라고 하셨다. 그렇게 외부망으로 접속을 하자 버튼이 노출되지 않고 있음을 파악할 수 있었다. 문제는 변경된 CSS의 버튼의 이미지 경로가 내부망(#밑에 설명) 주소로 박혀있었던 것이다. 보통은 이미지 경로가 해당 작업 하시는 분의 디렉터리 구조에 맞춰 상대경로로 되어 있어 CSS를 받아 적용해보면 어떤 이미지가 없는지 파악이 가능했고 그 이미지를 요청해서 얻어오는 식이었는데 어떻게 보면 뒤통수를 맞은 격이었다. 그것도 딱 해당 2개의 버튼만 "http://{내부망ip}"로 되어 있었던 것이다. 이에 파일을 다운 받아 프로젝트 내에 넣고 경로를 맞추어 준 후 반영을 했지만 뭔가 씁씁한 기분은 가시 질 않았다.


#내부망 

내부망은 일정 조직 내에서 인터넷이 아닌 내부 네트워크를 통해 PC끼리 자원을 공유하게 하거나 그룹웨어 등을 사용할 수 있게 하는 근거리 통신망(LAN, Local Area Network)로 '인트라넷'을 생각하면 이해하기 쉬울 것 같다. 망분리는 현재 정통망법 시행령에 따라 망법 적용을 받는 기업중 개인정보 100만명 이상, 매출액 100억원 이상의 기업은 의무적으로 망 분리를 실시해야고 한다. 보통 보안적인 이슈 때문에 적용하는 듯 하다.


[느낀점]

이런 문제를 처음 경험해 본 나는 적잖이 당황했던 것 같다. 좀 더 꼼꼼히 파악을 했더라면 좋았을 텐데 그렇기엔 그 긴 CSS를 다 파악하기 힘든 상태였고 웹 페이지에 CSS를 적용 후 깨지는 이미지와 CSS에만 초점을 맞춰 작업을 했던게 이런 문제점을 나았다. 외부망으로 한 번 만 확인을 해보았으면 이런 실수가 발생하지 않았을텐데 하는 아쉬움이 남는다. 이번 경험을 계기로 다음부터는 꼭 외부망으로도 접속해 테스트 해보도록 해야겠다. 



똑같은 실수를 반복하지 말자.



반응형
반응형


 

안녕하세요. 오늘은 작년 신입 교육 때, 딱 1년 전 읽었던 책 ( 열혈강의, 자바 웹 개발 워크북 )에 대해 정리해 보는 시간을 갖도록 하겠습니다. 책상 옆에 놓여있길래 막상 꺼내 펼쳐 보니 잊고 있었던 내용들도 있고 다시 한 번 상기할만한 내용들이 있어 이렇게 정리하게 되었습니다. 이제 막 웹을 시작하시는 분들이 보시기에 좋은 책인 것 같습니다. 정리라는게 챕터별로 정리하는 게 아닌 개인적으로 메모해놓고 다음에 다시 상기해 볼 만한 내용들이나 괜찮은 내용이다 싶은 부분만을 추려 정리하는 것이기 때문에 자세한 내용을 알고 싶으실 경우 책을 사서 보시길 추천해드립니다.

 

 

[ 프록시 서버 (Proxy Server) ]

클라이언트와 서버 사이에서 통신을 중계해 주는 컴퓨터나 프로그램을 말합니다. 프록시 서버의 주된 용도 중 하나는 빠른 전송을 위하여 서버의 응답 결과를 캐시에 저장해 두는 것입니다. 프록시 서버를 두는 두 번째 이유는 보안적인 부분인데, 첨단 기술을 다루는 회사의 경우 내부 사용자의 기밀 유출에 민감할 수밖에 없습니다. 이런 경우 프록시 서버를 이용하면 외부로 전달되는 데이터를 검사하여 특정 단어가 포함된 자료의 송.수신을 차단하거나 보안 팀에 경고 메시지를 보낼 수 있습니다.

 

[ 멀티 프로세스와 멀티 스레드 ]

멀티 프로세스 방식은 클라이언트가 연결 요청을 하면 서버 프로그램은 자신을 복제하여 클라이언트에 대응하게 하고, 자신은 다른 클라이언트의 요청을 기다립니다. 이 방식은 원본 프로세스의 메모리를 모두 복제하기 때문에 자원 낭비가 심합니다. 그에 비해 멀티 스레드 방식은 클라이언트 요청을 처리하는 일부 코드만 별도로 분리하여 실행하기 때문에 전체 메모리를 복제할 필요가 없어, 멀티 프로세스 방식보다 메모리 낭비가 적습니다.

 

[ 요청 헤더 ]

헤더에는 세 가지 종류가 있는데 요청이나 응답 모두에 적용할 수 있는 '일반 헤더(General-header)'와 요청 또는 응답 둘 중 하나에만 적용할 수 있는 '요청 헤더 또는 응답 헤더(Request-header/Response-header)', 보내거나 받는 본문 데이터를 설명하는 '엔티티 헤더(Entity-header)'가 있습니다. 요청 헤더가 담는 헤더명중 User-Agent가 있는데 클라이언트의 정보를 서버에게 알려주는 헤더입니다. 웹 서버는 이 헤더를 분석하여 요청자의 OS와 브라우저를 구분합니다.

 

[ CGI(Common Gateway Interface) ]

웹 서버와 프로그램 사이의 데이터를 주고받는 규칙을 CGI(Common Gateway Interface)라고 합니다. 이렇게 웹 서버에 의해 실행되며 CGI 규칙에 따라서 웹 서버와 데이터를 주고 받도록 작성된 프로그램을 'CGI 프로그램'이라고 합니다.

 

[ 서블릿 컨테이너 ]

서블릿의 생성과 실행, 소멸 등 생명주기를 관리하는 프로그램을 '서블릿 컨테이너(Servlet Container)'라 합니다. 서블릿 컨테이너(Jave EE 기술 중에서 서블릿, JSP 등 웹 관련 부분만 구현한 서버로 아파치 재단의 톰캣, Jetty등)가 서블릿을 대신하여 CGI 규칙에 따라 웹 서버와 데이터를 주고받습니다.

 

[ WebContent/Web-INF ]

웹 애플리케이션의 설정과 관련된 파일을 두는 폴더로 이 폴더에 있는 파일은 클라이언트에서 요청할 수 없다. 따라서 HTML이나 JavaScript, CSS 등 클라이언트에서 요청할 수 있는 파일을 이 폴더에 두어서는 안 됩니다.

 

[ GET 요청으로 넘어온 매개변수 값의 인코딩 설정 ]

GET 요청은 매개변수 값이 URL에 포함되기 때문에 setCharacterEncoding()으로는 문자 집합을 설정할 수 없다. 톰캣 서버에서 server.xml을 열어 <Connector>태그에 URIEncoding 속성을 추가하고, 값은 UTF-8로 설정한다. 웹 브라우저가 웹 서버로 데이터를 보낼 때는 웹 페이지의 기본 문자집합으로 인코딩하여 보내기 때문에 사용자가 입력한 값은 UTF-8로 인코딩되어 서버에 전달된다. 반면 서블릿은 UTF-8(한글 한 자를 3바이트로 표현) 3바이트를 하나의 문자로 인식하지 않고 각각의 바이트를 개별 문자로 취급하여 유니코드로 변환한다. 이렇기에 server.xml에 설정을 해주지 않을 경우 한글이 깨지게 된다.

 

[ SeverletContext 보관소 ]

웹 애플리케이션이 시작될 때 생성되어 웹 애플리케이션이 종료될 때까지 유지된다. 이 보관소에 데이터를 보관하면 웹 애플리케이션이 실행되는 동안에는 모든 서블릿이 사용할 수 있다.

 

[ HttpSession 보관소 ]

클라이언트의 최초 요청 시 생성되어 브라우저를 닫을 때까지 유지됩니다. 보통 로그인할 때 이 보관소를 초기화하고, 로그아웃하면 이 보관소에 저장된 값들을 비웁니다. 따라서 이 보관소에 값을 보관하면 서블릿이나 JSP 페이지에 상관없이 로그아웃하기 전까지 계속 값을 유지할 수 있습니다. JSP에서는 session변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ ServletRequest 보관소 ]

클라이언트의 요청이 들어올 때 생성되어, 클라이언트에게 응답 할 때까지 유지됩니다. 이 보관소는 포워딩이나 인클루딩하는 서블릿들 사이에서 값을 공유할 때 유용합니다. JSP에서는 request변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ JspContext 보관소 ]

JSP 페이지를 실행하는 동안만 유지됩니다. JSP에서는 pageContext 변수를 통해 이 보관소를 참조할 수 있습니다.

 

[ HttpSession ]

HttpSession 객체는 클라이언트 당 한 개가 생성됩니다. 웹 브라우저로부터 요청이 들어오면, 그 웹 브라우저를 위한 HttpSession 객체가 있는지 검사하고, 없다면 새로 HttpSession 객체를 만듭니다. 이렇게 생성된 HttpSession 객체는 그 웹 브라우저로부터 일정 시간 동안 Timeout 요청이 없으면, 삭제됩니다.

 

[ JspContext의 활용 ]

JSP 페이지를 작성하다 보면 <jsp:include>와 같은 특별한 태그를 사용하게 됩니다. 이런 태그들은 JSP 엔진이 서블릿 클래스를 생성할 때 특정 자바 코드로 변환됩니다. 이때 이 태그의 값을 다루는 객체를 '태그 핸들러'라고 부릅니다. 바로 이 태그 핸들러에게 데이터를 전달하고자 할 때 JspContext 보관소를 사용하는 것입니다.  JSP 페이지에 선언된 로컬 변수는 태그 핸들러에서 접근할 수 없습니다. 따라서 태그 핸들러에게 전달할 데이터가 아니라면 JspContext에 값을 보관할 필요가 없습니다.

 

[ EL(Expression Language) ]

EL(Expression Language)은 콤마(.)와 대괄호([])를 사용하여 자바 빈의 프로퍼티나 맵, 리스트, 배열의 값을 보다 쉽게 꺼내게 해주는 기술로 스태틱(static)으로 선언된 메서드를 호출 할 수도 있습니다. EL은 ${}와 #{}를 사용하여 값을 표현합니다. ${표현식} 으로 지정된 값은 JSP가 실행될 때 JSP 페이지에 즉시 반영됩니다. 그래서 ${}을 '즉시 적용(immediate evaluation)'이라 부릅니다. #{}을 '지연 적용(deferred evaluation)'이라 부르는데 UI를 만들 때 사용된다고 합니다.

 

[ DI(Dependency Injection) ]

작업에 필요한 객체를 외부로부터 주입 받는 것으로 다른 말로 역제어(IoC, Inversion of Control)'라고도 부릅니다.

 

[ mybatis ]

mybatis는 반복적이고 지루한 JDBC 프로그래밍을 단순화하기 위해 클린턴 비긴이 만든 작은 라이브러리에서 출발하였다. 이 라이브러리는 iBATIS라는 이름으로 2004년 아파치 소프트웨어 재단에 기부되면서 알려지게 되었다. 좀 더 효율적인 개발 관리를 목표로 2010년 6월 아파치 재단에서 구글 코드로 이사하였고 프로젝트 이름도 mybaits로 바뀌었다. mybatis의 핵심은 개발과 유지보수가 쉽도록 소스 코드에 박혀있는 SQL을 별도의 파일로 분리하는 것이다. 또한 단순하고 반복적인 JDBC 코드를 캡슐화하여 데이터베이스 프로그래밍을 간결하게 만드는 것이다.

 

[ mybatis javaType속성 ]

<result>에서 javaType을 사용하면, 칼럼의 값을 특정 자바 객체로 변환할 수 있다. 다음과 같이 'STA_DATE'칼럼에 대해 javaType을 java.sql.Date으로 설정하면, 칼럼 값을 꺼낼 때 그 객체로 변환된다.

<result column="STA_DATE" property="startDate" javaType="java.sql.Date"/>

 

[ mybatis <id> 엘리먼트 ]

SELECT 문을 실행하면 레코드 값을 저장하기 위해 결과 객체가 생성되는데, SELECT문을 실행할 때마다 매번 결과 객체를 생성한다면 실행 성능이 나빠질 것입니다. 이를 해결하기 위해 SELECT를 통해 생성된 결과 객체들은 별도의 보관소에 저장(캐싱, caching)해두고, 다음 SELECT를 실행할 때 재사용합니다. 이때 보관소에 저장된 객체를 구분하는 값으로 <id>에서 지정한 프로퍼티를 사용합니다.

 

[ mybatis의 SELECT 결과 캐싱 ]

SELECT를 실행할 때마다 결과 레코드에 대해 매번 객체를 생성한다면, 속도도 느리고 메모리도 낭비됩니다. 이를 개선하기 위해 mybatis는 객체 캐싱을 제공합니다. 즉 한 번 생성된 객체는 버리지 않고 보관해 두었다가, 다음 SELECT를 실행할 때 재사용하는 것입니다. 첫 번째 질의를 수행할 때 생성된 결과 객체는 풀(pool)에 보관해 둡니다. 두 번째 질의에서는 질의 결과에 대해 새로 객체를 생성하기 전에, 객체 풀에 보관된 객체 중에서 해당 칼럼의 값과 일치하는 객체를 먼저 찾습니다. 있다면 기존 객체를 사용하고 없다면 새로 객체를 생성합니다. 이것이 mybatis의 객체 캐싱 기법입니다.

 



반응형

+ Recent posts