Dynamic Contents 와 Static Contents 의 차이는 명확하다.

용어가 생소하더라도 개념은 익히 알려진 내용일 것이다. 그럼에도 짚고 넘어가자면,

Static Contents 는 유저/지역 등 어떤 기준을 막론하고 같은 데이터, 즉 정적 데이터를 말하고,

Dynamic Contents 는 유저/지역 또는 어떤 기준에 대하 다를 수 있는, 동적 데이터를 말한다.

 

쉽게 이해하자면 변수와 상수의 차이 정도로 보면 쉽다.

 

너무나도 간단한 개념이지만, 캐싱의 관점에서는 또 다르게 적용될 수 있다.

Static Contents 의 캐싱은 간단하다. 단순히 변하지않는 정적 데이터를 캐싱해주면 된다.

일반적으로 API 등에서 Meta data 를 캐싱하는 경우 In memory 에 캐싱하거나 혹은 설정값으로 관리하는 경우가 많다.

Meta data 가 아닌 종류의 리소스들이라면 CDN 이라는 훌륭한 솔루션이 있고, Cache-invalidation 정책만 조절하여 관리해준다.

 

반면 Dynamic Contents 의 캐싱은 조금 다르다. 계속 변하는 컨텐츠이기 때문에 자체만으로는 캐싱이 불가능하다.

가령 "Wellcome Home" 과 "Wellcome Tom" 이라는 두 종류의 웹페이지가 있다고 해보자. 앞선 페이지는 Static web page 이고 다음 페이지는 Dynamic web page 이다.

Static web page 의 캐싱은 간단하며, 단순히 해당 페이지(컨텐츠)를 저장하지만, Dynamic web page 의 경우 동적 요소를 따로 분리해서 로직으로 저장해주고(web page 의 경우 javascript 객체로 매핑시켜줄 수 있겠다.) static contents 만 캐싱해서 응답을 재구성하다.

 

CDN 및 캐시 솔루션 중에는 Dynamic Contents 에 대한 캐싱을 서비스해주려는 노력들이 꽤 있다.

가령 AWS 의 CloudFront 같은 경우 별도의 Backbone Network 를 구성해서 오리진 서버(비즈니스 로직이 처리될 서버)까지의 Latency 를 줄이고 Region 을 확장하는 방식으로 노력을 하고 있다.

 

 

 

Spring AOP(Aspect Of Control) 란, DI(Dependency Injection), PSA(Portable Service Abstraction) 와 같이 Spring Framework 의 주요 Feature 이다.

 

AOP 란 공통된 관심사(Aspect)로 구분된 로직을 필요한 위치에 동적으로 삽입할 수 있게 해주는 기술로,

Advice, JoinPoint, PointCut, Advisor 등의 용어가 사용되며, 비즈니스 로직과 연계되어 공통적으로 사용하는 부분(Transaction 이나 Filter, Security 등의 Layer)을 코드를 특정시점에 코드에 삽입하는 기술이다.

 

이러한 핵심 로직 코드에의 적용을 Weaving 이라 하며 Compile , Class Loading , Runtime AOP의 구현이 가능하다.

 

다음은 몇가지 AOP 에 사용되는 용어들에 대한 정리이다.

 

- Aspect : 핵심기능에 부가될 수 있는 모듈을 말한다. 재사용 가능하며 핵심적인 기능에 부가되어 의미를 가질 수 있는 모듈이다.

 

- Advice : Aspect 에 대한 구현체가 된다. 주로 어느시점에 어떤 동작을 할지가 기술된다.

 

- Point Cut : 핵심 모듈을 분리할 선이자, 어드바이스를 적용할 시점(Join Point)을 정의하는 모듈이 된다.

 

- Proxy : 타겟은 프록시를 통해 호출되며 타겟 메서드 실행에 대한 전처리 후처리를 담당해줌과 동시에 AOP 추상화에 있어서 인터페이스를 제공한다.

 

- Weaving : 핵심 로직 코드에의 적용을 말하며, Aspect 가 적용됨으로써 새로운 Proxy 객체가 생성된다.

 

- Cross Cut : 공통 로직을 비즈니스 로직에서 추출해내는 것을 Cross Cutting 이라 한다.

 

하지만 위의 내용들은 사실 용어와 사용하는 기술들에 대한 내용으로 실제 Spring 에서 추구하는 AOP 의 개념 그 자체는 서버의 기능을 비즈니스 기능과 공통 기능으로 나누고, 공통 기능을 코드 밖에서 필요한 시점에 재사용 가능하도록 적용시켜 주겠다는 개념이다.

 

결국 공통 기능을 따로 분리해서 재사용하겠다는 관점을 말하는 것이다.

 

 

 

서버의 Scalability 를 관리하기 위한 방법은 굉장히 중요하다.

 

실 서비스의 아키텍처를 구조화할 때도 반드시 고려해야할 부분이고, 이 결정은 실제로 서비스에 큰 영향을 주게 된다.

 

가령 사용자가 갑자기 증가할 경우, 엄청난 수의 요청에 대한 처리를 어떻게 할 것인가는 Backend 에서 가장 중요하게 고려해야할 부분 중 하나이다.

 

Scaling 의 방법에는 크게 Scale Up 과 Scale Out 이 존재한다.

 

Scale Up : 서버 자체의 Spec 을 향상시킴으로써 성능을 향상시킨다. Vertical Scaling 이라 불리기도 한다. 서버 자체의 갱신이 빈번하여 정합성 유지가 어려운 경우(주로 OLTP 를 처리하는 RDB 서버의 경우) Scale Up 이 효과적이다.

 

성능 향상에 한계가 있으며 성능 증가에 따른 비용부담이 크다. 대신 관리 비용이나 운영 이슈가 Scale Out 에 비해 적어 난이도는 쉬운 편이다. 대신 서버 한대가 부담하는 양이 많이 때문에 다양한 이유(자연 재해를 포함한다...)로 서버에 문제가 생길 경우 큰 타격이 불가피하다.

 

Scale Out : 서버의 대수를 늘려 동시 처리 능력을 향상시킨다. Horizon Scaling 으로 불린다. 단순한 처리의 동시 수행에 있어 Load 처리가 버거운 경우 적합하다. API 서버나, 읽기 전용 Database, 정합성 관리가 어렵지않은 Database Engine 등에 적합하다.

특히 Sharding DB 를 Scale Out 하게 된다면 주의해야하는데, 기존의 샤딩 알고리즘과 충돌이 생길 수도 있고(샤드가 갯수에 영향을 받을 경우...) 원하는 대로 부하의 분산이 안생길 수 있으니 각별히 주의할 필요가 있다.

 

스케일 아웃은 일반적으로 저렴한 서버 여러 대를 사용하므로 가격에 비해 뛰어난 확장성 덕분에 효율이 좋지만 대수가 늘어날 수록 관리가 힘들어지는 부분이 있고, 아키텍처의 설계 단계에서부터 고려되어야 할 필요가 있다.

 

 

요즘은 클라우드를 사용하기 때문에 Scaling 에 있어서 큰 이점이 있으며, 서비스의 목표치에 알맞게 Scalability 를 설계하고 두 스케일링 방법을 모두 적용시키는 것이 일반적이다.

 

 

 

실제 라이브 서비스를 위해 서버 산정을 할 때, 서비스 규모에 걸맞는 트래픽을 감당하기 위한 테스팅은 필수적이다.

 

근래에는 클라우드의 발전으로 Scalability 나 Elasticity 를 확보할 수 있는 많은 방법과 기술들이 생겼다고는 해도, 결국 해당 솔루션을 사용하는 것은 "비용" 이며 서버개발자라면 이 비용을 최소화하고 효율적인 서버를 구축해내는 것이 "실력" 을 증명해내는 일이다.

 

여기서 피할 수 없는 백엔드 테스트의 종류들이 나타나는데, 일반적으로 스트레스 테스트 또는 부하 테스트라고 알려진 테스트들이다.

이 테스트들은 중요하지만, 개발자들이라도 차이를 잘 모르는 사람들이 꽤나 있고 서비스의 규모가 작다면 혼용되어 쓰는 경우가 다수이기 때문에 정리해서 알아둘 필요가 있다.

 

(1) Load Testing (부하 테스트)

말그대로 시스템이 얼마만큼의 부하를 견뎌낼 수 있는 가에 대한 테스트를 말한다.

 

보통 Ramp up 이라하여 낮은 수준의 부하부터 높은 수준의 부하까지 예상 트래픽을 꾸준히 증가시키며 진행하는 테스트로, 한계점의 측정이 관건이며, 그 임계치를 높이는 것이 목적이라 할 수 있다.

 

일반적으로 "동시접속자수" 와 그정도의 부하에 대한 Response Time 으로 테스트를 측정한다.

예를들어 1분동안 10만명의 동시접속을 처리할 수 있는 시스템을 만들수 있는지 여부가 테스트의 주요 관건이 된다.

 

(2) Stress Testing (스트레스 테스트)

스트레스 테스트는 "스트레스받는 상황에서 시스템의 안정성" 을 체크한다.

 

가령 최대 부하치에 해당하는 만큼의 많은 동시접속자수가 포함된 상황에서 시스템이 얼마나 안정적으로 돌아가느냐가 주요 관건이 된다. 

스트레스 상황에서도 시스템의 모니터링 및 로깅, 보안상의 이슈나 데이터의 결함 등으로 서비스에 영향이 가서는 안되므로 결함에 대한 테스트가 일부 포함된다.

가령 메모리 및 자원의 누수나 발생하는 경우에 대한 Soak Test 나 일부러 대역폭 이상의 부하를 발생시키는 Fatigue Test 가 포함된다.

 

이처럼 부하가 심한 상황 또는 시스템의 복구가 어려운 상황에서 얼마나 크래시를 견디며 서비스가 운영될 수 있으며 빠르게 복구되는지, 극한 상황에서도 Response Time 등이 안정적으로 나올 수 있는지 등을 검사하게 된다.

예를들어 10만명의 동시접속 상황에서 크래시율을 얼마나 낮출 수 있는가, 혹은 데이터 누락을 얼마나 방지할 수 있는가 에 대한 테스팅이 있을 수 있다.

 

(3) Performance Testing (퍼포먼스 테스트)

Load Test 와 Stress Test 의 모집합 격인 테스트의 종류이다. 리소스 사용량, 가용량, 부하 한도(Load Limit) 를 포함해서 응답시간, 에러율 등 모든 부분이 관건이 된다.

 

특정 상황에서 어떤 퍼포먼스를 보이는지에 대한 측정이 주가 되며, 서비스의 안정성보다는 퍼포먼스 자체에 집중한다.

 

주로 서비스적 관점에서는 Performance Test 보다는 Load Test 나 Stress Test 가 더 중점이 되며, 시스템 전체적인 성능의 양적 측정과 같은 관점에서 Performance Test 로 분류한다.

보통 그럴 때에 수행하는 테스트로 Benchmark 라고 하기도 한다.

 

 

위와 같은 종류의 테스트 들을 수행하는 데 있어 제일 중요한 부분 중 하나는 모니터링과 리포팅이라고 할 수 있겠다.

관련해서 경험과 같이 포스팅으로 정리할 예정이다.

 

 


Spring 3.1 버전부터 추가된 FlashMap 은 스프링에서 파라미터를 간편하게 전달하기 위한 자료구조이다.


주로 같은 도메인에서 Controller 간, 혹은 웹페이지에서 발생하는 Redirect 시 데이터 처리를 간단하게 하기 위한 목적으로 사용된다.


플래시 맵을 사용하는 용도는, URL 에 데이터를 노출시키지 않으면서 데이터를 전달하고 싶으면서도 Session 데이터에 넣기에 적합하지 않을 경우이다.

(Session 은 사용 후 값을 지워줘야 하므로 실수로 누락되는 경우를 방지해야하며 실제로 유저 정보들이 많이 관리되므로 가벼운 데이터의 경우에도 세션을 이용하기 부담스러운 경우가 많다.)


FlashMap 의 특징은 일반 Map 자료구조처럼 쉽고 간단하게 사용될 수 있으면서 사용되고 난 이후에는 Spring 에서 값을 자동으로 지워준다는 점에 있다.


즉, FlashMap 은 휘발성이며 사용하는 개발자 입장에서는 관리에 부담없이 가볍게 Attribute를 다룰 수 있다.


단, 휘발성이므로 서버가 지속적으로 관리하면서 사용해야 하는 공유 Attribute 에는 적합하지 않다고 한다.



참조 : 


https://docs.spring.io/spring/docs/3.1.x/javadoc-api/org/springframework/web/servlet/FlashMap.html


https://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-flash-attributes





백엔드를 개발하다보면, Client 의 요청을 자체 처리하는 경우가 아닌 다른 url 핸들러에게 위임하는 경우가 종종 있다.


이렇게 클라이언트 요청에 대해서 다른 리소스로 연결을 할 때, redirect 와 forward 라는 2가지 테크닉이 있다.


Redirect 와 Forward 모두 클라이언트 요청에 대한 처리를 다른 url 로 보내서 처리를 위임하는 개념이지만, 


두 개념에는 차이가 있다. 각각의 개념을 통해 차이점을 정리해보자.



redirect - 클라이언트의 요청에 대해 서버가 다른 url 로 요청을 하게끔 만듬.




이 때, 원래 클라이언트가 요청한 url 의 핸들링 시, 서버는 다른 url 로 클라이언트가 "요청" 을 던지게끔 한다.


이 후 클라이언트는 서버로부터 전달받은 다른 url, 즉 위의 예제에서 /home 으로 다시 요청을 하게 하고, 해당 url 매퍼에서 요청에 대한 응답이 처리되게 된다.


즉, 연결이 끊기고 재연결이 들어가는 등 요청이 여러번 왕복하기 때문에 Rquest - Response 쌍이 하나 이상 생기게 된다.




forward - 서버가 클라이언트의 요청을 다른 서버로 넘김(forwarding)




서버는 클라이언트로부터 요청을 전달받았을 때, 이 요청을 서버 내부에서 다른 url 핸들러로 요청을 "전달" 한다.


즉, 클라이언트가 다시 서버에 대한 요청을 할 필요 없이 서버가 다른 url 매퍼에서 처리된 응답을 받기만 하면 되는 구조가 된다.


실제 처리는 "다른 url" 에서 처리되었지만 응답은 초기 url 핸들러로부터 내려받으며, 서버와 클라이언트 간 Request - Response 쌍은 하나만 존재하며 연결이 끊기지 않음. (연결이 하나로 유지됨)




실무에서도 많이 쓰이는 개념이고 익숙해지면 차이를 헷갈릴 수 있으니 틈틈히 정리하고 알아두는게 필요하다.



'Server > Basic' 카테고리의 다른 글

Message Oriented Middleware 및 Message Queue 에 대한 설명  (0) 2019.03.13
COMET 이란?  (0) 2019.01.23
Java Servlet 에 대하여  (0) 2018.12.23
HTTP/2 특징들에 대한 정리  (0) 2018.12.17
무중단 배포의 원리와 솔루션 종류  (0) 2018.12.09

 

Servlet 은 WAS에서 동작하는 Java 의 클래스를 말하며, 단순히 HTTP Request 에 대해 HTTP Response 를 응답하는 고차원 추상화를 제공하는 클래스를 말한다.

Java로 웹 어플리케이션 제작 시 동적인 처리를 담당한다.

 

Web Server 의 성능 향상을 위해 사용되는데, 외부 요청에 대해 Thread 로 할당하여 응답하므로 아주 가벼운 서버로 구현되고 Java 의 특성 상 다양한 플랫폼에서도 동작이 가능하다.

 

Servlet 은 일반적으로 HttpServlet  클래스를 상속받으며 웹페이지 개발시 JSP 와 Servlet 을 함께 이용하는 것이 도움이 된다.

(JSP 는 HTML 문서 안에서 Java 코드를 포함하는 반면, Servlet 은 Java 코드 안에서 HTML 코드를 사용하곤 한다.)

 

Servlet 3.0 미만의 버전에서는 web.xml 파일에 Servlet 을 등록하고 사용하도록 되어있지만, 

Servlet 3.0 이상에서는 web.xml 파일을 사용하지 않으며 대신 Annotation 을 이용해 정의한다.

 

3.0 이상에서 어노테이션을 이용해 서블릿을 작성할 때에는

 

@WebServlet("/test")
public class TestServlet extends HttpServlet {

 protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 response.setContentType("text/html;charset=utf-8");
 PrintWriter out = response.getWriter();
 out.print("Hello world");
 out.close();
 }
}

위와 같이 작성하게 된다.

 

Java Servlet 은 Servlet Container 위에서 동작가능한데, Tomcat 과 같은 서블릿 컨테이너 들은 다음과 같은 기능들을 지원함으로써 서블릿의 동작을 돕는다.

 

 - Network Services : Remote System 및 네트워크 서비스를 접근하고 이용할 수 있도록 제공한다.

 - Decode and Encode MIME based Message : MIME 타입의 메세지에 대한 인코딩 / 디코딩을 제공한다.

 - Manage Servlet container : 서블릿 들의 라이프사이클을 관리해준다.

 - Resource Management : HTML, JSP 등과 같은 static 및 dynamic 리소스 들을 관리해준다.

 - Security Service : 리소스 접근에 대한 인증과 권한을 담당한다.

 - Session Management : 세션을 관리한다.

 

Tomcat 과 같은 Servlet Container 들은 서블릿들을 구동시켜 WAS 로써 동작할 수 있도록 해준다.

 

 무중단 배포란 알고있는대로, 서버를 실제로 서비스할 때 서비스적 장애와 배포에 있어서 부담감을 최소화할 수 있게끔 서비스가 중단되지 않고도 코드를 Deploy할 수 있는 기술이다


예전에는 배포 자체가 하나의 거대한 일이었고, 이를 위한 팀과 개발팀이 날을 잡고 새벽에 배포하는 일이 잦았지만, 최근에는 무중단 배포 기능을 탑재한 Deploy 자동화 툴을 이용해서 개발자들이 스스로 배포까지 담당하는 DevOps 의 역할을 하게되면서, DevOps 의 필수 기술 중 하나가 되었다.


 무중단 배포 방식에는 주로 사용되는 것들에 AWS에서 Blue-Green 무중단 배포(Blue는 기존버전, Green은 새로운버전. Router를 통해 Blue로 이동하는 트래픽을 Green으로 변경시켜준다. 원리는 동일하다.), Docker를 이용한 웹서비스 무중단 배포가 있다


IDC에서 직접 L4 스위치를 이용해서 하는 방안도 간단하지만, 이는 비용적으로 효율적이지 않아 많이 없어지는 추세이다


또한 NginX 등을 이용해서 저렴하게 무중단 배포를 하는 방식도 있다


이 방법을 사용하면 클라우드 인프라가 갖춰져있지 않아도 되고 별도의 인스턴스를 갖고 있지 않아도 가능하다

(Spring jar 2개를 여러 포트에 나눠서 배포하고 그 앞에 NginX 로 밸런싱해주면 된다.)


 무중단 배포의 원리




간단한 원리는 위와 같다. 핵심은 Reverse Proxy 가 서로 다른 인스턴스의 각기 다른 포트와 서브 도메인으로 연결하고, 지속적으로 Health Check 하면서 배포시 서브도메인을 메인 도메인으로 Switching 해주고, 배포가 끝나면 다시 메인도메인으로 Reload 해주는 것이다


이 구조에서 주의해야할 점은, 배포가 서비스에 영향을 주지 않도록 해야한다는 것이다. 예를들어 DB의 구조를 바꾸는 JPA와 같은 기술들이 사용되어 있을 경우 검토가 필요하다.


 도커 컨테이너를 이용하면 이는 매우 간단해진다

하나의 이미지에서 여러 컨테이너를 생성해서 호스트의 docker 명령어를 이용해서 손쉽게 서버 이중화 및 Switch, Reload 가 이루어진다

빌드 서버에서 이미지를 만들고 해당 이미지를 distribution 을 통해 다른 서버에서 이를 가져오는 식으로 구성된다.


 도커의 Service Discovery 라는 개념을 이용하면 nGinX 를 통해 배포할 때의 단점인 설정 파일의 수정과 재시작이 수반되어야 한다는점과 Proxy 대상 IP Port 가 고정이어야 한다는 점, Health Check 오버헤드를 피할 수 있다


Service Discovery는 서버들의 정보를 포함한 정보들을 저장해서 가져오고, 값의 변화가 일어날 때 이벤트 형식으로 설정을 수정하고 재시작하는 개념이다.




위의 구조에서는 Key/value 스토어를 이용해서 서버 정보를 저장하였으며 Configuration Manager 가 이를 watch하면서 이벤트 방식으로 설정 파일을 만들고 기존 파일에 덮어 쓰는 작업을 하고 있다


docker에서 대표적인 Service discovery tool docker-gen 이 있다


자세한 내용 참조

(https://subicura.com/2016/06/07/zero-downtime-docker-deployment.html)


실습가능한 참조 링크

http://jojoldu.tistory.com/267



Spring 의 Bean 이 정의될 경우 정의하는 Bean 의 Scope 에 대해 옵션을 부여할 수 있다.


예를 들어 Prototype Scope 는 해당 Bean 을 사용할 때마다 재정의하게끔 성질을 부여한다.


반면 Bean 을 Spring project 전역에서 단 하나의 객체로 취급하고 접근하고자 할 경우 해당 Bean 의 Scope 는 Singleton 으로 정의되는 것이 옳다.


Spring 프레임워크는 현재 5개의 Scope 를 제공하고 있다.


(1) Singleton : Spring 컨테이너 하나당 한개의 Bean 만이 생성되고 해당 Bean 이 요청될 때마다 모든 객체는 한 객체를 가리킨다.


(2) Prototype : 하나의 Bean 은 사용할 때마다 새로운 객체를 할당하여 사용하게 된다.


(3) Request : HTTP request 가 상주하는 Spring Application Context 내에서만 유효한 객체를 생성하고 재사용한다. (web-aware)


(4) Session : Bean 을 해당 세션이 가진 Application Context에 바인딩한다. (web-aware)


(5) Global session : HTTP 세션 전역에서 같은 Bean 을 사용가능하다. (web-aware)


Spring Bean 들의 Default scope 는 Singleton 이기 때문에 대부분 Bean 을 사용할 경우 @Autowired 를 통해 간편하게 사용이 가능하다.


만약 어플리케이션에 따라 다른 종류의 Scope 가 필요하다면 다음 예시와 같이 설정에서 변경이 가능하다.



<bean id = "..." class = "..." scope = "prototype">
//...
</bean>



보통의 어플리케이션에서는 Singleton 으로 설계하고 사용할 수 있으나 간혹 prototype 등으로 특정할 수 있으니 상황에 따라 유용하게 사용할 수도 있다.


<보다 나은 예시 참조 : https://www.tutorialspoint.com/spring/spring_bean_scopes.htm>



Spring 의 Application Context 는 Spring 에서 설정 정보의 제공을 위한 핵심 인터페이스이다.


런타임 이전에 로드가 되며, 런타임에서 일반적으로 Read-Only 로 구성되지만, 사용에 따라 런타임에 Re-load 하는 경우가 종종 있다.


프로젝트의 설정 작업을 하는 클래스 들의 경우 ApplicationContextAware 등의 인터페이스를 상속해서 ApplicationContext 에 접근하곤 한다.


ApplicationContext 를 이용하면 다음과 같은 작업이 가능하다.


 - Application 에서 Component 로 갖고 있는 Bean 에 대해 접근이 가능하다. (즉, Bean factory 를 제공한다)


 - Resource 를 직접 가져올 수 있다. 리플렉션과 유사하게 명시된 이름을 주로 사용한다.


 - 이벤트를 직접 발행할 수 있으며 이벤트는 context 에 등록된 Listener 에 작용한다.


 - 상속된 Context 컴포넌트들에 접근이 가능하다.


ApplicationContext 에 접근하는 클래스는 다음과 같이 만들 수 있다.




@Component
public class ContextAccessor implements ApplicationContextAware {
private ApplicationContext applicationContext;

    /*
     *
     * @see org.springframework.context.ApplicationContextAware#setApplicationContext
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.applicationContext = applicationContext;
    }
}



위와 같이 ApplicationContextAware 를 구현하면, ApplicationContext 에 접근이 가능하며, 클래스를 컴포넌트화 시켜서 프로젝트에 광범위하게 사용하곤 한다.



+ Recent posts