11/28/2018

Istio & Envoy에서 OpenTracing 사용 하기

Sidecar Proxy는 코드 삽입없이 모니터링 데이터를 얻는 매우 간단한 방법을 제공한다. Tracing은 대규모 분산 시스템에서 가장 어려운 부분이기 때문에 Sidecar Pattern은 큰 이점으로 작용한다.

Sidecar Proxy에서 Tracing을 하기 위해서는 Inbound에서 Outbound 요청으로 일부 Header를 전달해야 한다. Application단에서는 매우 간단하지만 전달받은 Header를 넘기는 로직을 처리하면 불편 할 수 있다. 비즈니스 레이어에서 Header를 전달하는 것을 조정한다고 상상해보면 Sidecar Pattern을 사용하는 이점이 없을 수 도 있다.

Tracing은 Envoy만 사용

Header 전달이 기존 Application 코드에서는 아래처럼 작성된다.

@RestController
public class HelloController {
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/hello")
public String hello() {
return "Hello from Spring Boot!";
}
@RequestMapping("/chaining")
public String chaining(@RequestHeader HttpHeaders headers) {
HttpHeaders tracingHeaders = new HttpHeaders();
extractHeader(headers, tracingHeaders, "x-request-id");
extractHeader(headers, tracingHeaders, "x-b3-traceid");
extractHeader(headers, tracingHeaders, "x-b3-spanid");
extractHeader(headers, tracingHeaders, "x-b3-parentspanid");
extractHeader(headers, tracingHeaders, "x-b3-sampled");
extractHeader(headers, tracingHeaders, "x-b3-flags");
extractHeader(headers, tracingHeaders, "x-ot-span-context");
ResponseEntity<String> response = restTemplate
.exchange("http://spring-boot:8080/hello", HttpMethod.GET, new HttpEntity<>(tracingHeaders), String.class);
return "Chaining + " + response.getBody();
}
private static void extractHeader(HttpHeaders headers, HttpHeaders extracted, String key) {
List<String> vals = headers.get(key);
if (vals != null && !vals.isEmpty()) {
extracted.put(key, Arrays.asList(vals.get(0)));
}
}
}

위의 코드상에서는 특별한 것은 없다. 하지만 코드상에 header 정보를 set하기에 변경이 생기면 리팩토링이 필요할 수 도 있다. 그리고 코드에 header 정보를 set하기에 잊어버릴 가능성도 존재한다.

Envoy and OpenTracing

OpenTracing의 일부 기능을 어플리케이션에 추가 한다. Spring Boot는 classpath에 jar를 추가하는 것만으로도 구현이 가능하다. Auto Configuration은 개발자가 개입하지 않아도 필요한 Tracing Code를 어플리케이션에 추가합니다.

OpenTracing은 Vendor 중립적이기에 Tracing 구현을 제공해야 한다. 이 경우 일반적으로 jaeger-java-client를 사용하게 된다. 끝으로 Tracing Bean을 Instance화하고 구성해야 한다. Envoy는 기본적으로 Jaeger에서 활성화되지 않고 명시적으로 등록되어야 한다.

@Bean
public io.opentracing.Tracer jaegerTracer() {
Builder builder = new Builder("spring-boot",
new RemoteReporter(new HttpSender("http://jaeger-collector.istio-system:14268/api/traces"), 10,
65000, new Metrics(new StatsFactoryImpl(new NullStatsReporter()))),
new ConstSampler(true))
.registerInjector(Builtin.HTTP_HEADERS, new B3TextMapCodec())
.registerExtractor(Builtin.HTTP_HEADERS, new B3TextMapCodec());
return builder.build();
}

Istio, Jaeger 및 어플리케이션을 kubernetes에 배포한다. 배포가 완료되면 /chaining endpoint에 요청을 할 수 있다.


Proxy 범위에 적용되는 Timeout 규칙은 두 가지이다.

첫번째는 Proxy Client의 지속 기간이 원래 지속 기간보다 항상 짧아야 한다.

두번째는 첫번째와 반대이며 Proxy Server 기간이 항상 길어야 한다.


span과 관련된 로그 내에서 어떤 컨트롤러 메소드가 호출되었는지 확인할 수 있다.

Envoy만 Tracing하면 설치가 매우 간단해진다. OpenTracing을 사용하면 이 작업을 자동으로 할 수 있으며 모니터링되는 프로세스에 대한 가시성을 높일 수 있다.

11/18/2018

Service Mesh 알아 보기

지난 몇년간 Micro Service Architecture는 많이 발전되어 왔습니다. 그리고 현 시점에 몇 가지 새로운 개념과 패턴이 등장하고 있습니다. 이 중 “Service Mesh” 개념은 많은 인기를 얻고 있습니다. 본 글에서는 Service Mesh와 관련된 주요 개념에 대해서 설명합니다.

Service Mesh의 등장 배경

현재까지 대부분의 사람들은 마이크로 서비스가 SOA/ESB와 같은 이전 아키텍처에서 가진 문제점들의 해답이라고 생각합니다. 그러나 실제 마이크로 서비스를 구현할 때, ESB가 지원하는 대부분의 기능들이 마이크로 서비스 수준에서 구현 가능하다는 것을 알 수 있습니다.



예를 들어서 여러 가지 다운 스트림 서비스를 호출하고 이 기능을 다른 서비스로 노출해야 하는 시나리오가 있습니다. 위의 그림에서 볼 수 있듯이 ESB 아키텍처(왼쪽)를 사용하면 서비스 간 통신 중에 Circuit Breaker, Timeout 및 Service Discovery등과 같은 기능을 구축하기 위해 ESB내에 내장된 기능을 쉽게 활용 할 수 있습니다.

Micro Service를 사용하여 동일한 시나리오는 구현한다고 하면, 중앙 집중 방식의 ESB가 아니라 Code Level에서의 마이크로 서비스가 제공됩니다. 따라서 마이크로 서비스를 하기 위해서는 이러한 모든 기능이 구현되어야 합니다.


위의 그림과 같이 상호간 통신하는 마이크로 서비스는 다음과 같이 구성됩니다.

  • Business Logic, Process 및 서비스 구성
  • Network Functions: OS의 네트워크 스택위에 구축(본 기능을 통해 기본 서비스 호출, 탄력성 및 안정성 패턴 적용, Service Discovery등을 적용)

ESB 대비하여 위의 그림처럼 마이크로 서비스를 구현하기 위해서 필요한 노력을 생각해보면 생각보다 심플하지 않습니다. 비즈니스 로직에 초점을 맞추기보다는 서비스 간 통신 기능을 구현하는 데 많은 시간을 투자해야 합니다. 또한 Polyglot 형태의 여러 프로그래밍 언어를 지원해야 할 경우에는 각 언어별로 노력을 들여야 하기 때문에 다중 기술을 사용하여 마이크로 서비스를 구현하는 것은 쉽지 않습니다.

마이크로 서비스 아키텍처 구현에서 가장 복잡한 부분은 서비스 자체를 구축하는 것이 아니라 서비스 간의 통신입니다.

마이크로 서비스간 커뮤니케이션의 요구 사항은 매우 일반적이기에 이러한 모든 작업을 다른 Layer에서 Offloading 하는 것에 대해서 생각해 볼 수 있습니다. 그래서 “Service Mesh”가 등장했습니다.

Service Mesh란 무엇인가?

Service Mesh는 서비스간 커뮤니케이션 인프라입니다. Service Mesh를 사용하게 되면 아래의 특징을 가질 수 있습니다.

  • 마이크로 서비스는 다른 마이크로 서비스와 직접 통신하지 않습니다.
  • 모든 마이크로 서비스간 통신은 Service Mesh(or Sidecar Pattern)를 통하게 됩니다.
  • Service Mesh는 탄력성, Service Discovery등과 같은 일부 네트워크 기능을 기본적을 지원 합니다.
  • Service Mesh를 이용하면 개발자는 비즈니스 로직에 더 집중 할 수 있으며 네트워크 통신과 관련된 대부분의 작업은 Service Mesh로 Offloading 하게 됩니다.
  • 예를 들어서, 마이크로 서비스가 다른 서비스를 더이상 호출하지 않을 때 Circuit Breaker에 대해 걱정할 필요가 없습니다. 이 또한 Service Mesh의 일부로 제공되고 있습니다.
  • Service Mesh는 프로그래밍 언어에 제약을 받지 않습니다. 마이크로 서비스는 항상 HTTP1.x/2.x, gRPC등과 같은 표준 프로토콜을 사용하기 때문에 이를 기반으로 마이크로 서비스를 작성 할 수 있습니다.

위의 그림에서 언급된 서비스 상호 작용 및 책임에 대해서 설명합니다.

비즈니스 로직

서비스 구현에 필요한 기능을 의미합니다.

기본 네트워크 기능

대부분의 네트워크 기능을 Service Mesh로 Offloading 할지라도 특정 서비스는 Service Mesh / Sidecar Pattern Proxy와 연결하기 위해 기본적인 네트워크 상호 작용 기능을 포함해야 합니다. 따라서 서비스 구현은 주어진 네트워크 라이브러리(ESB와 다르게 간단한 추상화를 사용)를 사용하여 네트워크 호출을 해야 합니다. (Service Mesh 전용)

어플리케이션 네트워크 기능

Circuit Breaker, Timeout, Service Discovery등과 같이 네트워크에 밀접하게 결합된 어플리케이션 기능이 존재합니다. 초기 마이크로 서비스를 구현할 경우에는 ESB Layer에서 제공되는 네트워크 기능을 무시하고 각 마이크로 서비스 수준에서 모든 기능을 처음부터 구현했습니다. 현 시점에서 분산형 Mesh와 비슷한 공유 기능을 갖는 것이 중요하다는 사실을 깨닫기 시작했습니다. 즉 서비스 코드/비즈니스 로직과 명시적으로 분리된 Service Mesh의 기능을 사용 할 수 있도록 합니다.

Service Mesh 제어 기능

모든 Service Mesh Proxy는 Control Plane에 의해 중앙에서 관리됩니다. Access 제어, Service Discovery등과 같은 Service Mesh 기능을 지원할 때 매우 유용합니다.

Service Mesh 기능

Service Mesh는 어플리케이션 네트워크의 기능을 제공하는 반면 일부 네트워크 기능은 여전히 마이크로 서비스 수준 자체로 구현됩니다. Service Mesh에서 어떤 기능이 제공되어야 하는지에 대한 규칙은 없습니다. 아래는 Service Mesh에서 가장 일반적으로 제공되는 기능입니다.

  • Resiliency for inter communications: Circuit Breaker, Timeouts, Retries, Fail injection, fault handling, load balancing, failover
  • Service Discovery: 전용 Service Registry를 통해 Service Endpoint를 검색
  • Routing: 서비스 비즈니스 기능과 관련된 라우팅 제공
  • Observability: Metrics, monitoring, distributed logging, distributed tracing 제공
  • Security: TLS 제공 및 Key 관리
  • Access Control: Blacklist/Whitelist 기반 Access 제어
  • Deployment: Container 배포 지원
  • Interservice communication protocols: HTTP1.x, HTTP2, gRPC 제공

Servie Mesh 구현체

Linkerd 및 Istio와 같은 오픈소스 구현체가 존재합니다. 여기에서 둘 간의 차이를 확인하세요.

Service Mesh 장단점

장점

  • 마이크로 서비스 코드 외부에서 구현되기에 다양한 프로그래밍 언어도 지원하고 재사용 가능합니다.
  • Ad-hoc 솔루션을 사용한 마이크로 서비스 아키텍처의 대부분의 문제를 해결합니다: Distributed tracing, logging, security, access control등
  • 다양한 프로그래밍 언어 지원: 특정 언어가 네트워크 어플리케이션 기능을 구축 할 수 있을지 또는 라이브러리가 지원되는지에 대해 걱정이 없습니다.

단점

  • 복잡성: Service Mesh를 사용하면 런타임 인스턴스 수가 증가합니다.
  • Extra hop 추가: 각 서비스 호출은 Service Mesh의 Sidecar Proxy를 통해서 호출되어야 합니다.
  • Service Mesh는 서비스 간 통신 문제를 다루지만 복잡한 라우팅, Mediation등의 기능을 제공하진 않습니다.

결론

Service Mesh는 마이크로 서비스 아키텍처의 구현과 관련하여 주요 과제중 일부를 해결 합니다. 그리고 다양한 마이크로 서비스 구현 기술 집합을 선택할 수 있고 서비스 간 네트워크 기능을 지원해주므로써 개발자는 비즈니스 로직에 더 집중 할 수 있습니다. 그러나 Service Mesh는 비즈니스 로직과 관련된 서비스 통합 문제를 해결하지는 못합니다.

References: https://medium.com/microservices-in-practice/service-mesh-for-microservices-2953109a3c9a


11/07/2018

GraphQL로 BFF 대체하기

 

위의 그림에서 BFF의 목적은 Orchestration, Business Logic을 공유하고 Backend 서비스가 제공하는 것보다 UI에 친화적인 모델을 제공하는 것입니다. 그래서 각 클라이언트별로 BFF가 존재하게 됩니다. Netflix는 Client Adapter라는 이름으로 SoundCloud는 BFF라는 이름으로 UI에 친화적인 Backend 서비스를 제공하고 있는데, 이런 BFF에도 문제점이 존재합니다.

  • 업무 조직간 교차 관리가 어렵습니다.
  • Traffic에 대한 용량 사이징을 예측하기 어렵습니다.
  • 단일 실패 지점이 될 가능성이 존재합니다.
  • 추가적인 아키텍처 복잡성이 발생합니다.

다른 접근 방법은 클라이언트가 서비스를 제공하거나 Backend와 직접 상호 작용을 하는 것입니다.

위의 그림처럼 BFF를 걷어내면 심플해보이는 장점이 있지만, 여전히 BFF와 공통된 문제점이 존재합니다. Application Server는 PC, Mobile의 데이터 요구를 구별해야 하며 각 클라이언트별로 API가 달라질 가능성이 존재합니다.

GraphQL을 써보자

이러한 상호 작용을 깔끔하게 하고 최종 사용자에게 더 나은 서비스를 제공하기 위해서 GraphQL을 사용해 볼 계획을 가지고 있습니다. GraphQL은 API Graph에서 구성 요소를 관리하는 복잡성에 대처할 수 있도록 Facebook에서 개발했습니다.

GraphQL을 사용하면 UI가 데이터와 선언적으로 상호 작용할 수 있으며 서버에서 UI를 분리 할 수 있습니다. UI에서 필요한 데이터를 지정하기에 UI에 친화적인 API를 구축하는 것에 대해 고민할 필요가 없습니다. 또한 GraphQL은 일반적인 AJAX 요청보다 더 쉽게 최적화되기에 Request 개수가 줄어들게 됩니다.


앞으로는 GraphQL이 주류가 될 것입니다. Amazon의 AppSync 혹은 Graphcool 같은 서비스가 주류가 되는데에 일조 할 것으로 보여집니다.


11/04/2018

Simple Work., 단순하게 일하기

 


애플의 스티브 잡스와의 회의는 힘든 여정이었다고 합니다. 회의 가 끝난 후 안좋은 표정으로 회의실을 나서는 직원들에게 무슨일이 있냐고 물어보면 “Simple Stick으로 맞았다.”라고 얘기한다고 합니다. 스티브 잡스는 비효율적인 회의, 프로젝트라고 판단될 경우 바로 중단을 시키거나 없애버렸다고 합니다. 이런 스티브 잡스의 Simple Stick이 오늘의 Apple을 만든 원동력이라고 평가되고 있습니다. 모든 업무를 단순화 하여 “세상을 바꿀 수 있는 제품과 서비스를 만들자”라는 핵심 가치에 다가서기 때문입니다.

아마존의 사명은 “클릭 한번이면 된다.”입니다. 사실 클릭이 몇 번 필요하긴 하지만 제프 베조스는 이 문장으로 고객이 얻을 수 있는 가치를 설명하고 있습니다.

이러한 회사들의 사명 혹은 리더들의 스타일은 해당 기업의 조직 문화로 이어지게 됩니다. 조직 문화는 추상적으로 받아들여지기 쉽지만, 추상적이라기 보다는 직원들이 이해하고 달성하기 위해 함께 노력해 나가는 것입니다. 이 문화를 이루기 위해 직원들을 설득 하고 이끌어 나가는 것이 리더의 역할입니다.

스티브 잡스와 제프 베조스같은 리더들은 괴짜처럼 보여지기도 하고 냉혹해보이기도 합니다. 이렇게 보이는 것은 그들이 지닌 가치관에 따라 결정하기 때문입니다. 이 가치관에 벗어나는 그 어떤 것에도 타협하지 않기 때문입니다. 작업 수준이 낮으면 다시 만들어야 하고 속임수를 쓰지 않습니다. 좋은 말로 사람을 현혹하지도 않습니다. 현실을 알고 그 상황을 객관적으로 판단 합니다. 남들의 기분을 생각해서 애매하게 말하지 않습니다. 이들은 좋고 싫고가 명확하고 일관성이 있습니다. 그래서 괴짜, 냉혹한으로 보여지기도 합니다.

그리고 이들은 직접 일을 챙기기 때문에 조직을 단순화 시켜 직접 챙기거나 적임자를 배치합니다. 적임자에게는 책임과 권한을 부여하여 철저히 믿고 일을 맡깁니다. 그리고 업무 프로세스를 최대한 단순화 합니다. 그리고 단순화된 업무 프로세스에서 일할 직원을 채용하는데에 심혈을 기울입니다.

스티브 잡스의 경우 직원을 뽑을 때, 엄청 공을 들인다고 합니다. 그의 평가 기준은 “세상을 변화 시킬 수 있는 사람인가”입니다. 그리고 면접자에게 질문을 한다고 합니다. “당신은 세상을 바꾸기 위해 무엇을 했습니까?” 그동안 해왔던 경력을 얘기하던 우리의 면접과정과는 많은 차이가 있지요.

이렇게 직원들을 뽑아 프로젝트에 투입하고 단순화된 프로세스내에서 업무를 수행합니다. 애플의 경우, 프로젝트의 결과물을 검증하지 않는다고 합니다. 우리는 일반적으로 시장에 제품을 내놓기 전에 무수히 많은 시험을 했는데 말이죠. (물론, 제품의 퀄리티를 위한 품질 관리, 테스트는 하겠지요;;) 결과물을 검증하지 않는다는 말의 의도는 이렇습니다. 할 수 있는 일이 아니기 때문이기 때문입니다. 시장이 검증해야 한다는 의미지요.

이런 단순함이 고객에게도 영향을 미칠까요? 만약 고객에게 많은 선택권을 주면 고객이 좋아 할까요? 좋아하지 않는다고 합니다. 옵션이 많을 수록 잘 결정한 것인지에 대해 의문을 갖게 만든다고 합니다. 그럼에도 많은 기업들은 많은 옵션을 내놓고 있습니다. 시장의 심리를 파악하기가 어렵기에 많은 선택권을 주는 것이지요. 반면 애플은 라인업이 간단합니다.

단순하게 일한다는 것은 일을 대충한다는 의미는 아닙니다. “똑똑한 소수 정예”들을 통해 구체적으로 일한다는 의미입니다. 그리고 조직 문화도 단순하게 세팅이 되어야 하고요.

물론, 단순함을 추구한다는 것은 더 적은 인력을 효율적으로 일한다는 것을 의미하기에 구조조정을 겪기도 합니다. 하지만 맞는 사람들을 적절히 배치한다는 점에서 기업이 성공 확률이 높아진다고 생각됩니다.

당신은 단순한 조직에서 단순하게 일하고 있습니까?