분산 환경의 처리는 일반적인 환경의 구성과 많이 다르며 분산시스템의 특이성에 대한 개념들이 있다.

특히나 자주 듣게 되는 단어 중 하나는 결과적 일관성(Eventual Consistency) 라는 개념으로, 분산 시스템(Distributed System) 을 운영하게 되면 흔치않게 접하게 된다.

이는 개념과 관련된 이론이 그만큼 중요한 내용임을 반증한다.

 

먼저 예로 들은 Eventual Consistency 에 대해 설명하자면 이는 분산 컴퓨팅(Distributed Computing) 에서 고가용성(High Availability)을 보장하기 위한 방법의 하나로

"주어진 데이터에 대한 변경이 없다면 해당 Element 에 대한 모든 Access 는 가장 최근에 변경된 내용을 가리킨다" 는 정의를 말한다.

분산 시스템에서 데이터를 조회할 때 모든 시스템이 동일한 데이터를 가질 수 있다고 보장할 수는 없으며 결과적 일관성은 어느 시점에는 데이터가 다를 수 있지만, 결국에는 모든 시스템이 최신의 데이터를 가질 수 있도록 보장된다는 내용이다.

 

분산 환경에서는 데이터에 대해 단지 "시간" 뿐 아니라 "공간(다른 시스템)" 도 고려의 대상이 된다.

 

이는 BASE 원칙의 일종으로 분류되기도 한다. BASE 원칙이란 다음의 원칙들이 포함된다.

- Basically Available : 일반적인 Read / Write 에 대한 동작이 "가능한만큼" 지원된다.

(여기서 가능한만큼 이라 함은, 동작이 가능하나 Consistency 에 대한 보장이 되지않는다는 점이다.)

- Soft state : Consistency 가 보장되지 않기 때문에 상태(State) 에 대해 Solid 하게 정의하지 못하다.

- Eventually consistent : 위에 언급된 Eventual Consistency 개념에 따라 충분한 시간이 흐르면 모든 시스템 환경 내에서 데이터는 최신의 데이터가 보장된다.

 

BASE 원칙은 전통의 트랜잭션 시스템을 위한 ACID 원칙에 반대된다. 이는 분산 환경에서 나타나는 특징이기 때문이다.

이러한 특징에 대해 CAP Theorem 은 다음 3가지 조건을 모두 만족하는 분산 시스템을 만드는 것이 불가능함을 정의한다.

 

- 일관성(Consistency) : 모든 시스템의 데이터는 어떤 순간에 항상 같은 데이터를 갖는다.

- 가용성(Availability) : 분산 시스템에 대한 모든 요청은 내용 혹은 성공/실패에 상관없이 응답을 반환할 수 있다.

- 내구성(Partition Tolerance) : 네트워크 장애 등 여러 상황에서도 시스템은 동작할 수 있다.

 

분산환경 특징 상 3가지 성질을 모두 만족할 수는 없고, 일반적으로 다음과 같이 선택된다.

 

- CP (Consistency & Partition Tolerance) : 어떤 상황에서도 안정적으로 시스템은 운영되지만 Consistency 가 보장되지 않는다면 Error 를 반환한다. (어떤 경우에도 데이터가 달라져서는 안된다.)

이는 매 순간 Read / Write 에 따른 정합성이 일치할 필요가 있는 경우 적합한 형태이다.

 

- AP (Availability & Partition Tolerance) : 어떤 상황에서도 안정적으로 시스템은 운영된다. 또한 데이터와 상관없이 안정적인 응답을 받을 수 있다. 다만 데이터의 정합성에 대한 보장은 불가능하다. (특정 시점에 Write 동기화 여부에 따라 데이터가 달라질 수 있다.)

이는 결과적으로는 일관성이 보장된다는 Eventual Consistency 를 보장할 수 있는 시스템에 알맞는 형태이다.

 

 

서버시스템 및 분산시스템에 있어서 핵심적인 개념이므로 잘 정리해두고 아키텍처를 고려할 때 항상 생각해두자




Spring 은 기본적으로 Framework 의 사용자, 즉 개발자가 비즈니스 로직의 구현에만 집중할 수 있게 서블릿 처리와 같은 기타 작업을 대신해주는 잘 구성된 프레임워크이다.


개발을 하다보면 비즈니스 로직 이외에도 Request 와 Response 에 대해 직접 처리하거나 비즈니스 로직을 처리하기 이전, 혹은 이후에 작업을 처리해야할 때가 있다.


예를 들어 Request 와 Response 에 대한 로깅이나 API 전반에 걸친 인증 등 Framework Layer 에서 처리할 수 있는 작업들이 있으며, 이 때 Filter 와 Interceptor 로 작업을 처리한다.





<출처 : https://justforchangesake.wordpress.com/2014/05/07/spring-mvc-request-life-cycle/>



1. 필터 (Filter)



public interface Filter {

public void init(FilterConfig filterConfig) throws ServletException;

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;

public void destroy();
}




Filter 는 Servlet Container 에 의해 동작이 제어되는 Java Class 로 HTTP Request 가 Service 에 도착하기 전에, HTTP Response 가 Client 에 도착하기 전에 제어할 수 있다.


Filter 는 Request 를 처리할 때 Dispatcher Servlet 이 작업을 처리하기 전에 동작하고, Response 를 처리할 때에는 Dispatcher Servlet 에 의해 작업이 끝난 이후에 동작한다.


정확히 분류하자면 Filter 는 J2EE 의 표준이며 Servlet 2.3 부터 지원되는 기능으로 Spring Framework 에서 지원을 하고는 있지만 Spring 프레임워크만의 기능은 아님을 알아두자.


Filter 는 Filter Chain 을 갖고 있으며 Application Context 에 등록된 필터들이 WAS 구동 시에 Context Layer 에 설정된 순서대로 필터 체인을 구성한다.


구성된 체인은 맨 처음 인스턴스 초기화(init())를 거친 후 각 필터에서 doFilter() 를 통해 필터링 작업을 처리하고 Destroy 된다.


이 때의 환경 설정은 주로 톰캣을 사용할 경우 web.xml 또는 Java Configuration 을 이용해서 구현하게 된다.




2. 인터셉터 (Interceptor)



public interface HandlerInterceptor {

    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception;

    void postHandle(
            HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception;

    void afterCompletion(
            HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception;

}


Interceptor 는 필터와는 다르게 Spring 레벨에서 지원하는 Servlet Filter 이다. Spring Context 내에서 HTTPRequest 와 HTTPResponse 처리에 대해 강력한 기능을 제공한다.


Java Servlet 레벨에서 동작하는 Filter 와 다르게 Spring Context 레벨에서 동작하므로 Dispatcher Servlet 이 Request 및 Response 를 처리하는 시점에 Interceptor Handler 가 동작한다.


Dispatcher Servlet 에서 요청이 처리되고 나면 요청받은 URL 에 대해 등록된 Interceptor 가 호출되며 Prehandle - Controller 실행 - PostHandle - AfterCompletion 의 순서로 인터셉터가 작업을 처리한다.


이 때의 환경 설정은 주로 servletContext.xml 또는 Java Configuration 을 이용해서 구현하게 된다.



필터와 인터셉터는 현업에서도 자주 사용되는 유용한 도구이니 확실하게 알아두고 꼭 필요할 때 응용해서 사용할 필요가 있다.



참조 : 

http://www.mkjava.com/tutorial/filter-vs-interceptor/

https://justforchangesake.wordpress.com/2014/05/07/spring-mvc-request-life-cycle

https://supawer0728.github.io/2018/04/04/spring-filter-interceptor/




메시지 지향 미들웨어(Message Oriented Middleware)란 독립될 수 있는 서비스간에 데이터를 주고받을 수 있는 형태의 미들웨어를 말한다.


구성요소간 통신을 하는 방법에 있어서 네트워크(Network) 를 이용하거나 Process 간 통신 등의 중계를 해주는 미들웨어의 경우에도 Message Oriented Middleware 라고 부를 수 있지만, 일반적으로 Server to Server 로 전달되는 Message 서비스를 말한다.


메시지 지향 미들웨어의 사용은 통신을 통해 Service 들 간의 분리와 독립, 그럼에도 불구하고 안정적인 기능을 제공해줌으로써 Software Architecture 를 설계하는 데 큰 유연성을 제공해준다.


메시지 지향 미들웨어는 대부분 메시지큐(Message Queue) 의 형태로 구현되어 있으며 줄여서 MQ라고 부른다.


MQ의 종류에는 흔히 알려진 Rabbit MQ 가 있으며 이런 종류의 메시지큐들은 AMQP(Advanced Message Queueing Protocol) 를 이용하여 구현되어 있다.


MQ 시스템을 인프라에 구축했을 때에 아키텍처상으로 이를 브로커(Broker)라고 부르기도 한다.


Message Queue 를 이용할 때 얻을 수 있는 장점으로는 다음과 같은 것들이 있다.


(1) Redundancy : 메시지의 실패는 보관 및 관리가 되며 메시지가 실패한다고 하더라도 시스템에 영향을 주지 않는다.


(2) Traffic : 메시지 큐에 메시지를 쌓아두면 무분별하게 증가할 수 있는 트래픽에 대해 느리더라도 안정된 처리가 가능하다.


(3) Batch : 메시지 큐는 메시지에 대한 일괄처리를 수행하며 특히 부하가 심한 Database 에 대한 처리에 대한 효율성을 기대할 수 있다..


(4) Decouple : 소프트웨어와 MQ는 분리되며, 이는 소프트웨어 설계에 큰 이점을 준다.


(5) Asynchronous : 큐에 넣기 때문에 영향을 받지않고 비즈니스 로직을 처리할 수 있다.


(6) Ordering : 트랜잭션의 순서가 보장되며 동시성 문제에서도 안전하다.


(7) Scalable : 다수의 서비스들이 접근하여 원하는 서비스를 이용하는데 용이하다. 이는 다수의 서비스를 분리하는 데에도 큰 도움을 준다.


(8) Resiliency : 연결된 서비스에 이상이 생기더라도 다른 서비스에 영향을 미치지 않는다.


(9) Guarantee : MQ 는 트랜잭션방식으로 설계되어 있으며 메시지 처리의 트랜잭션을 보장한다.


이러한 장점들을 갖고 있기 때문에 주로 API 서버를 구축할 때 중요하거나 그 자체로 무거울 수 있는 기능들을 별도의 서버로 분리하고, MQ 를 통해 통신하는 방식이 선호된다.


이는 프로젝트의 규모가 커짐에도 유연성을 확보할 수 있는 좋은 수단이며 서비스 자체에서 처리하기 부담스러운 요구사항들을 만족시킬 수 있는 옵션을 제공한다.



다음 링크들을 참조했습니다.


https://docs.oracle.com/cd/E19435-01/819-0069/intro.html

https://stackify.com/message-queues-12-reasons/

https://heowc.tistory.com/35





Cache 가 저장된 데이터를 Flush 시키는 전략은 캐시 서버의 유지에 있어서 중요한 부분이다.


가령 캐시에 저장된 데이터가 실제 데이터와 동기화가 안되어 잘못된 값이 참조된다거나, 이전 데이터가 만료되지 않는 경우,

혹은 저장된 정보인데 Key 값이 Mismatch 나거나 불필요하게 Flush 되어 Cache hit-ratio 가 낮아진다면 이는 전체 서버 구조에 영향을 미치게 된다.


다음은 Cache 서버를 사용할 때 유의해야할 몇가지 Cache 의 Flushing 전략 들을 정리해보았다.


주로 사용되는 캐시인 Redis 위주로 정리가 되어있으며, Cache 자체에 대한 범용적인 정리이지만 예시는 Redis 위주이며 캐시의 종류에 따라 차이가 있을 수 있다.



1. Cache 의 Flushing 은 일반적으로 Active 한 방법과 Passive 한 방법이 있음을 이해하자.


 : Active 한 방법은 별도의 요청에 따라 Cache 를 Flush 시키는 방법이고, Passive 한 방법은 자체에 Expire Time 을 이용해서 외부에서 별도 요청없이 캐시를 비우게끔 만드는 전략이다.

 

 만약 Active Flushing 을 하지 않는다면, 해당 캐시는 수동적으로만 갱신되므로 실시간적인 데이터 동기화 및 캐싱이 불가능하다.

 Passive Flushing 을 하지 않는다면, Active 한 방식으로 Flushing 되지않는 데이터는 영구히 캐시 서버에 남아서 공간을 차지하게 되며 이는 큰 비용이 될 수 있다.


 반대로 지나치게 Active 한 Flushing 이 많아진다면, Cache 는 Read 요청 대비 Write 요청의 비율이 높아져 쓰는 효율이 없어지게 되고, Passive Flushing 도 지나치게 짧은 단위로 Flushing 이 일어난다면 Cache hit ratio 가 줄어들 것이므로 설계에 유의가 필요하다.

 

 일반적으로 API 의 설계에 맞춰 Active Flushing 타이밍을 정확히 맞추고, Passive Flushing 을 위한 Expire Time 의 설정은 선험적 지식 또는 벤치마킹 등에 의해 측정되어 설정되게 된다.

 


2. Cache Refresh / Expire reset 기준을 확인하는 것이 중요하다.


 : 사용하는 캐시 서버 및 설정에 따라 다를 수 있지만, Cache Refresh 의 기준을 확인하는 것은 중요하다. 

 가령 Redis 의 경우 Cache hit Read 기준으로 Expire reset 이 발생하기 때문에, 계속적으로 Cache hit 이 발생하면 자동으로 Expire 는 되지않는다.

 단순 기능이라면 큰 문제가 안되겠지만 캐시를 바라보는 경우가 많을 경우 문제가 생기기 쉬운 상황이므로 잘 체크해주어야 한다.


 즉, 지속적으로 Cache-hit 이 발생하는 한, Active 한 방식의 Flushing 이 아닌 Passive Flushing 을 기대하는 건 잘못된 방식이다.

 개인적으로 QA 프로세스에서 Caching 문제가 발생하고 있었는데, 이 부분을 간과해서 문제가 해결되지 않은 버전이 Live 에 포함될 뻔 한 일이 있었다.



3. 사용하는 캐시 서버의 Expire 로직을 이해하자.


 : Cache 를 사용할 때 캐시 서버의 로직을 파악하고 있는 것이 중요하다. 중요한 것은 사용하는 Cache 서버가 어떻게 내부적으로 동작하냐는 것이다.

 가령 Redis 의 경우 일정한 주기를 갖고 랜덤하게 key 들을 뽑아서 expire 을 검사하고 expiration rate 가 높을 경우 다시 일정 주기로 검사하는 루틴을 지닌다.

 이러한 구조를 이해하는 것은 서버 설정하는 데 있어서 기본이 되며 보다 나은 환경을 구축하는 데 도움을 준다.




캐시에 대한 현업에서 이슈들로 겪으면서 가장 중요했던 기본 내용들만 정리해보았다.


실제 이슈와 그에 대한 트러블 슈팅은 따로 포스팅에 정리하도록 하겠다.




 로드밸런싱(Load Balancing) 이란 Software 용어로 부하 분산의 의미를 갖고 있다. 말그대로 동작에 있어서 부하가 심해져 병목현상이 생기는 것을 방지하기 위해 사용한다.

이는 컴퓨팅 리소스, 네트워크 리소스 등 모든 부분에서의 성능향상을 기대할 수 있게 한다.


일반적으로 L4 Load Balancer 와 L7 Load Balancer 가 존재한다.




(1) L4 Load Balancing


 L4는 네트워크 Layer 4번째 계층을 의미한다. 4번째 계층에서 수행되어야할 작업의 중요한 역할 중 하나는 IP, 포트, 세션을 기반으로한 LoadBalancing 작업이 있다.

이런 이유로 L4 Load Balancer 를 Connection Load Balancer 혹은 Session Load Balancer 라 부르기도 한다.


4계층에 포트정보가 들어감으로써 디테일한 로드밸런싱이 가능하기 때문에 일반적으로 Load Balancer 를 말할 때 L4 스위치 자체를 말하기도 한다.

이렇게 L4 스위치만 이용하더라도 부하분산 및 포트에 대한 필터링이 가능하다. 

로드밸런서가 있으면 서버 몇대에 이상이 생기더라도 다른 서버가 대신 작업을 수행하는 Failover가 가능하며,

또한 이 부분에서 TCP/UDP 패킷 분석이 가능하기 때문에 Firewall 처리도 수행한다.



보통 로드밸런서의 설정 시 서버들에 대한 주기적인 health Check를 통해 장애 여부를 판단할 수 있으며 분산알고리즘(metric)에는 흔히 알려진 라운드로빈, Least Connection, Response Time, Min miss, bandwidth based, 해싱 알고리즘이 있다.


- 라운드로빈 : 세션을 순차적으로 맺어주는 방식이다. 일반적으로 5:5의 분산이 가능하나 경로별로 같은 처리량이 보장이 안된다.


- Least Connection : 가장 적은 Open Session을 가진 서버로 연결을 붙여준다. 가장 많이 사용되는 방식이다.


- Response Time : 각 Real Server 들이 다루는 Resource의 양과 Connection 시간, 데이터 양이 다른 경우 사용하기 적합하다. 로드밸런서가 서버와 직접 통신을 하면서 응답시간이 빠른쪽으로 많은 세션을 할당해준다.


- Hash : 특정 클라이언트는 특정 서버로만 할당시키는 방식. 경로가 보장되며 접속자수가 많을수록 분산 및 효율이 뛰어나다. 다만 접속자수가 적을수록 공평하게 분산이 안될수도 있다.


- Minimum Missis : 해시 기법과 유사하지만 특정 서버 다운시 해시값의 재할당이 이루어진다. Source IP 기반으로 해싱을 하기 때문에 프록시를 사용하는 경우 Hashing이나 Min miss를 사용하면 안된다.


- Bandwidth based Loadbalancing : 서버들과의 대역폭을 고려하여 분산한다.



(2) L7 Load Balancing


 L4 Load Balancer 가 일반적으로 TCP / UDP 에 대해서만 동작하는 것과 다르게, L7 Load Balancer 는 OSI 7 층의 HTTP 에 대해서도 작동한다.

Layer 7 의 로드밸런서는 주로 HTTP 라우팅에 대한 처리를 담당한다. 


Layer 7 Load Balancing 의 주요 특징들은 다음과 같다.


- Persistence with Cookies : 주로 쿠키를 활용한 Connection Persistence 를 유지하며, 쿠키 정보를 분석한다. WAS 로 이루어지는 연결에 대해 해당 연결을 동일한 서버로 연결되게끔 해준다.


- Context Switching : 클라이언트가 요청한 리소스에 대해 Context 를 전환할 수 있다. 가령 Static 이미지 리소스 등에 대해 Load Balancer 가 확장명에 따른 분류로 Image Server 로 연결해줄 수 있다.


- Content Rewriting : 전달받은 Request 를 변환해서 재전송이 가능하다.


그 외에도 프록시 처리(X-forwarded-for) 및 보안 로직 처리 등도 이루어진다.

로드밸런싱 알고리즘은 L4 와 유사하며 역시 가장 간단하게 라운드로빈 알고리즘이 주로 사용된다.


일반적으로 L7 로드밸런서는 L4 로드밸런서보다 비싸지만 상위 프로토콜에서 그 이상의 유연성을 보여준다.





DNS란 웹사이트의 주소 이름을 IP Address 로 매핑시켜 기억할 수 있는 도메인으로 사이트에 접근할 수 있게 해주는 인터넷의 핵심 요소이다. 다음은 verisign 에서 제공하는 How DNS works 의 설명 내용이다.


(1) 쿼리 전송 : 브라우저가 유저로부터 입력받은 도메인 이름을 이용해 쿼리를 날린다. 쿼리는 ISP 나 무선 통신업체가 운영하는 DNS Resolver 서버에 도달하여 도메인네임을 IP로 바꾸기 위해 어떤 DNS 서버에 요청해야 하는지를 질의하게 된다.


(2) 루트 서버 : DNS Resolver 가 상호작용하는 첫번째 DNS 서버를 루트 서버라 하며, 루트 서버는 .com 과 같은 최상위 도메인에 대한 DNS 정보를 알고 있다. 이 루트서버는 쿼리를 요청한 지점에서 멀지 않은 도메인으로 전송시켜 준다.


(3) TLD 서버 : TLD 서버는 최상위 도메인 내에 차상위 도메인에 대한 주소 정보를 저장하는 서버로 쿼리가 TLD 서버에 도착하면 TLD 서버가 도메인 네임에 대한 IP주소를 답변한다.


(4) DNS : 서버를 거친 쿼리문이 도메인 네임에 대한 IP 주소를 DNS Resolver 로 전송한다.


(5) Web site : DNS Resolver 는 문의한 도메인 네임에 해당하는 IP주소를 브라우저에 알려주고 브라우저는 IP 주소로 접근하여 컨텐츠를 가져온다.



DNS 정보를 조회하는 Flow 는 다음과 같다.


1. 클라이언트(웹 브라우저)가 DNS 를 조회하는 쿼리를 발생시킨다.


2. 발생한 요청은 Local DNS 서버로 이동한다. 이 때의 요청은 다음과 같은 DNS Resolver 들을 거치게 된다.

 - 클라이언트에 저장된 로컬 네임 서버 DNS 캐시

 - Internet Service Provider(ISP) 가 제공하는 네임 서버 DNS 캐시

캐시에서 값이 있으면 해당 IP 정보를 응답값으로 전달한다.

여기서 ISP 가 제공하는 네임서버 DNS 캐시가 의무적으로 존재하지는 않는다. ISP 에 따라 존재하는 경우도 있고 없는 경우도 있다. 없다면 요청은 Local PC 의 설정만 조회해보고 바로 3번 이후로 넘어간다.


3. DNS 주소에 대한 쿼리가 Root 서버로 향한다. Root 서버는 .com 과 같은 최상위 도메인에 대한 DNS 정보를 포함한다.

도메인 정보에 따라서 일반 최상위 도메인(.com, .net, .org ...) 이나 국가 최상위 도메인(.kr, .jp ...) 으로 분류되어 각각에 알맞는 TLD 서버의 정보를 전달받는다.


4. TLD 서버 정보를 이용해 TLD 서버에서 해당 도메인 주소(tistory.com)에 대한 관리 주체 서버로 연결해준다. 


5. 도메인 주소를 관리하는 DNS 서버에서 해당 도메인 주소에 대한 IP 를 반환해준다.


6. 반환된 IP 가 응답으로 전달되면서 Local DNS 에 캐싱된다.


7. Local DNS 를 통해 클라이언트(웹 브라우저) 는 IP 정보를 얻게되고 해당 서버로 접근하게 된다.



DNS 를 관리하는 구조는 트리형태로 되어있으며 클라이언트가 트리 형태의 DNS 구조에서 쿼리를 통해 결과값을 받아가는 과정이 재귀적(Recursive)이라 하여, Resolver 를 Resulsive Resolver, Query 를 Recursive Query 등으로 부르기도 한다.




Scalability 와 Elasticity 는 클라우드 환경에서의 중요한 개념이고 면접에서도 심심치않게 등장하는 질문이다.


Scalability Cloud 에서 workload 증가할 부하를 감당할 있을만한 Resource Capacity 갖고 있느냐에 대한 내용이다

예상되는 요청에 대해서 아키텍쳐적인 관점에서 Scalable 하다는 것은 예상치를 충분히 감당할만한 Resource 갖고있다는 의미가 된다


반면에 Elasticity 막대한 양의 resource 용량에 대해서 순간적으로 할당하거나 해제하는 능력에 대한 성질이다. 요구에 걸맞는 resource 얼마나 빠르고 효과적으로 할당하는지를 말한다.


서버는 많은 양의 요청을 처리하기 위해 충분한 Scalability 를 갖추고 있어야 하며, 그를 위한 Scale Out 이나 Scale Up 등을 통해 리소스를 확보한다. 


이처럼 Scalable 한 시스템을 구축하기 위해서는 Elasticity 를 갖고 있어야 하며, 클라우드 환경에서는 리소스 추상화를 통해 빠른 할당과 회수를 가능하도록 환경을 구축하는 것이 중요하다.




 첫 회사에 입사해서 배운 개념이다. 글로벌 서비스를 하는 회사였기 때문에 필수적인 용어였고, 마침 OJT 첫 과제가 내부에서 사용할 수 있도록 CDN 을 구축해보는 것이었다.


 CDN컨텐츠를 효율적으로 전달하기 위해 여러 노드를 가진 네트워크에 데이터를 저장하여 제공하는 시스템이다

CDN 의 사용 목적은 거리가 멀어 물리적으로 네트워크 비용이 많이 요구되는 곳에도 데이터를 효과적으로 전달하기 위한 목적으로 구성된다.


주로 ISP에 직접 연결되어 데이터를 전송하여 컨텐츠 병목을 피할 수 있는 장점이 있다. CP들은 CDN 측에는 사용료를, CDN ISP 측에 호스팅 비용을 지불한다. 최신 트랜드는 P2P 기술을 서버와 같이 이용하는 하이브리드 모델을 사용하는 것이다.


 주로 웹요소(텍스트, 그래픽, 스크립트), 다운로드 가능한 파일들, 어플리케이션들이 주로 사용되며, 갱신과 전달이 빈번한 메시지 형태의 데이터나 로그성 데이터가 사용되는 경우도 있다.


사용자와 지리적으로 가까운 노드에 서버를 두는데 있어 주로 Content 캐싱 방식을 이용하며 Static caching 은 사용자의 요청이 없어도 리소스를 저장해 놓는 방식이고 Dynamic caching 은 사용자의 요청을 받으면 Origin server로부터 컨텐츠를 받아서(Cache fill) 캐시에 저장한다. 

주로 저장하는데 있어 TTL(Time To Live) 이 정의되어 있고 이는 상황에 따라 삭제되거나 계속 유지될 수도 있다.


 특히 회사에서 글로벌 서비스를 진행한다면 CDN 의 사용은 필수적이다. 많은 웹 기반 서비스들이 대용량의 리소스를 서버 자체에서 핸들링 하는 경우는 드물며, 지리적 이점 & 네트워크 효율성 및 안정성을 이유로 CDN 을 사용한다.

솔루션으로써 가장 훌륭한 평가를 받는건 Akamai 의 솔루션으로 생각된다.





 Grep 은 워낙 유명한 리눅스의 패키지이며 그만큼 쓸일이 많으므로 다음의 기본 사용법 정도는 꼭 알아두도록 하자.


 Grep 명령어는 파일 전체를 뒤져서 정규표현식에 해당하는 모든 행들을 출력하는 기능을 한다.


(ex) grep nw datafile -> datafile에서 nw를 포함하는 행 검색


grep nw d* -> d로 시작하는 모든 파일에서 nw를 포함하는 행을 검색


grep <keyword> * -> 모든 파일에서 키워드를 검색


grep '^n' datafile -> n으로 시작하는 datafile 내의 모든 행을 출력


grep '4$' datafile -> 4로 끝나는 datafile 내의 모든 행을 출력


grep '[^0-9]' datafile -> datafile 내에서 숫자가 아닌 문자를 하나라도 포함하는 모든 행을 출력


grep '[a-z]{9}' datafile -> datafile 내에서 소문자가 9번 이상 반복되는 문자열을 포함하는 모든 행을 출력한다.



 grep 실행시 다음 옵션을 부여함으로써 유용하게 정보를 가공할 수도 있다.


-r(하위 디렉토리를 모두 검사)

 

-n(행 번호를 함께 출력)


-i(대소문자 미구분)


-l(행 대신 파일명만 출력)


-w(정확히 일치하는 경우만 검색)


-v(포함되지 않은 행을 출력)


주로 사용하는 건 위의 옵션들이다. 더 많은 옵션은 다음 링크를 참조하자. 예제도 아주 잘 정리되어있다.

(https://en.wikibooks.org/wiki/Grep)


(ex) grep -v 'ffl' datafile > edit

// datafile에서 ffl이 있는 행만을 추출하여 edit 파일에 씀.


(ex) grep -rl "*print$"

// 현재 폴더를 루트로 하여 서브 디렉토리를 모두 검사하여 print 로 끝나는 행을 가진 파일의 이름을 출력.


 특히 서버에서 로그 분석 작업을 할 때, Grep 은 tail 과 함께 밥먹듯이 사용한다.

어느정도 프로젝트에서 자주 사용하는 정규식 포맷을 메모하여 grep 사용 시 적용시키는게 유용하다.





P2P 는 관심있게 보고있는 기술 중 하나이다. 본 포스팅은 P2P 특징과 연결을 위한 기술들을 기술한다.


P2P 기술 개요


 P2P 기술이란 Peer To Peer 의 약자로, 소수의 서버에 집중되는 형태의 네트워크가 아닌 구성원들의 대역폭에 의존하는 다대다 통신망 기술이다. 여기서 언급하는 Peer 란 하나이자 모든 네트워크 구성요소를 말하며 모든 Peer 가 서버이자 클라이언트가 될 수 있는 구조를 지향한다. 최근에는 그리드 컴퓨팅과 그 이상의 블록체인의 기반 기술로 진화해나가고 있는 기술이다.


P2P 의 특징


 IP 네트워크는 IP주소만 알고 있으면 어떠한 단말기에도 도달할 수 있다. 인터넷에서 P2P 응용기술은 IP 네트워크 오버레이 네트워크(Overlay Network : OLN)라고 볼 수 있다. P2P는 모든 단말이 동일하지만 특별한 기능과 역할을 가진 단말이 존재하지 않으므로 연결하는 사용자수가 방대하게 되어도 특정 단말에 부하가 집중(확장성이 높은 신뢰성)한다. 즉, 더 많은 단말기로 전달이 가능하게 된다. 반면 SC 모델(Server-Client 모델)의 경우 클라이언트의 수가 증가함에 따라 서버의 처리 능력 및 서버에 연결되어있는 네트워크 회선에 부하가 집중되게 된다.(확장성이 낮다) 이에 따라서 서버 회선 비용도 크게 절감할 수 있다. 


 P2P 방식은 통신 상대 특정에 있어서 곤란한 문제를 갖고 있다. 통신상대의 IP 주소를 확인 하는 방법을 마련할 필요가 있는 것이다. 또한 통신 경로에 의한 통신 속도의 제한이 발생하게 된다. 하지만 모든 단말간 회선 품질이 동일함을 보장하는 것은 인터넷에서 불가능한 요구이다. SC 모델이 클라이언트들에 대해서 가능한한 빠른 회선 서버에 연결하도록 설계할 수 있는 반면에 P2P 방식은 그렇지 않기 때문에 회선 망에 있어서 장애를 가져올 수 있다. 


P2P 연결을 위한 기술들

 

 P2P 연결을 위해선 기본적으로 네트워크 망에 대한 이해가 필수적이다. 전통적인 서버-클라이언트 모델이 아니기 때문에, 다음과 같은 테크닉(?) 을 이용해서 연결 구조를 형성한다.


- Relaying : ClientA와 ClientB가 통신을 하는데 있어서 경우에 따라 NAT(Network Address Translation) 하에 놓일 수 있다. 이들의 통신을 중계하기 위해서 중계서버를 두고 서버를 통해 통신하는 방식이다. 접속이 유효한 동안 계속 주고받을 수 있으나 불필요한 대역폭의 낭비와 서버의 리소스를 소모하게 된다. 


- Connection Reversal : 하나의 클라이언트가 NAT 뒤에 위치하는 경우 B가 A로 연결을 시도할 때, A의 사설 IP로는 당연히 접속이 불가능하고, 서버 S가 관찰하는 NAT의 공인 IP로의 접속은 A에서 나가는 것만 허용하기 때문에 역시 접속이 불가능하다. 그래서 중계 서버 S를 이용해서 B의 공인 IP를 서버 S에게 알려준 다음 역으로 A가 접속을 시도하여 커넥션을 맺게 한다. 


- UDP Hole punching : 두 개의 클라이언트가 전부 각각의 NAT 뒤에 위치한 경우이다. 이 경우에는 두 클라이언트가 같은 NAT 뒤에 있는가 혹은 다른 NAT 뒤에 있는가로 경우가 분류된다. 


두 클라이언트가 서로 다른 각각의 NAT 뒤에 있을 때 클라이언트 A가 클라이언트 B와 연결을 맺으려면 중계서버 S를 이용해야 한다. S에 접속할 때 서버는 클라이언트 A의 정보(사설 및 공인 IP)를 취득하여 저장하게 되고 B가 접속할 때도 이 정보를 저장하게 된다. 만약 A가 B에 대해 연결을 요청하게 되면 S는 A와 B에게 동시에 서로의 IP 정보를 보내주게 되고 각 클라이언트는 이를 통해 각각 연결시도를 하게 되어 커넥션이 맺어질 수 있게 된다. 



+ Recent posts