<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>O's Of The Day</title>
    <link>https://5linesys.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Mon, 6 Jul 2026 07:50:17 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>5linesys</managingEditor>
    <item>
      <title>Jest private method mocking</title>
      <link>https://5linesys.tistory.com/36</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;Object.getPrototypeOf()&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;Object.getPrototypeOf() 를 사용하면 인스턴스의 원형에 접근할 수 있어 private 메서드도 mocking 할 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1733921459242&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MyClass {
  private myPrivateMethod(): string {
    return 'Original Private Method';
  }

  public callPrivateMethod(): string {
    return this.myPrivateMethod();
  }
}

describe('MyClass', () =&amp;gt; {
  it('should mock private method using `Object.getPrototypeOf`', () =&amp;gt; {
    const myInstance = new MyClass();
    const prototype = Object.getPrototypeOf(myInstance);

    const spy = jest.spyOn(prototype as any, 'myPrivateMethod').mockReturnValue('Mocked Private Method');

    const result = myInstance.callPrivateMethod();

    expect(spy).toHaveBeenCalled();
    expect(result).toBe('Mocked Private Method');
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;장점: 타입 시스템을 유지하며, 프로토타입 체인을 이용해 안정적으로 접근할 수 있다.&lt;/li&gt;
&lt;li&gt;단점: 약간의 복잡함이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;DI&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nestjs 의 경우 class 가 모듈화 되어있어 DI 를 활용하여 해결할 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1733922749918&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable } from '@nestjs/common';

@Injectable()
class HelperService {
  myHelperMethod(): string {
    return 'Original Helper Method';
  }
}

@Injectable()
class MyService {
  constructor(private readonly helperService: HelperService) {}

  public callPrivateMethod(): string {
    return this.helperService.myHelperMethod();
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1733922391241&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Test, TestingModule } from '@nestjs/testing';
import { MyService } from './my-service';
import { HelperService } from './helper-service';

describe('MyService', () =&amp;gt; {
  let myService: MyService;
  let helperService: HelperService;

  beforeEach(async () =&amp;gt; {
    const module: TestingModule = await Test.createTestingModule({
      providers: [MyService, HelperService],
    }).compile();

    myService = module.get&amp;lt;MyService&amp;gt;(MyService);
    helperService = module.get&amp;lt;HelperService&amp;gt;(HelperService);
  });

  it('should call myHelperMethod and return the mocked result', () =&amp;gt; {
    // 모킹 (mocking) 처리
    jest.spyOn(helperService, 'myHelperMethod').mockReturnValue('Mocked Helper Method');

    const result = myService.callPrivateMethod();

    expect(helperService.myHelperMethod).toHaveBeenCalled();
    expect(result).toBe('Mocked Helper Method');
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;설명
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HelperService 는 MysSevercie 의 private 메서드에 해당한다.&lt;/li&gt;
&lt;li&gt;DI 로 주입한 HelperSevice 는 독립된 서비스이므로, 재사용이 가능하고 직접 모킹이 가능하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;장점: 타입 시스템을 깨뜨리지 않으며 유지보수가 쉽다.&lt;/li&gt;
&lt;li&gt;단점: 의존성을 추가해야 하므로 구조에 따라 코드 리펙터링이 필요하다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>Node</category>
      <category>jest</category>
      <category>NestJS</category>
      <category>TDD</category>
      <category>test</category>
      <category>typeScript</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/36</guid>
      <comments>https://5linesys.tistory.com/36#entry36comment</comments>
      <pubDate>Wed, 11 Dec 2024 21:38:57 +0900</pubDate>
    </item>
    <item>
      <title>gRPC</title>
      <link>https://5linesys.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;gRPC 는 Google 에서 개발한 오픈 소스 원격 프로시저 호출(Remote Procedure Call) 프레임워크로, 기존의 RPC 시스템을 현대화하여 다양한 환경에서 효율적인 통신을 지원한다. gRPC는 HTTP/2 를 기반으로 하며, 프로토콜 버퍼(Protocol Buffers) 를 사용하여 데이터를 직렬화한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;전통적인 RPC 시스템과 gRPC 의 차이&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 직렬화 방식
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RPC: 일반적으로 XML이나 JSON 같은 텍스트 기반의 직렬화 형식을 사용한다.&lt;/li&gt;
&lt;li&gt;gRPC: 프로토콜 버퍼라는 이진 직렬화 형식을 사용하여 데이터의 크기를 줄이고, 직렬화 및 역직렬화 속도를 향상시킨다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;전송 프로토콜
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RPC: 주로 HTTP/1.1 을 사용하며, 요청-응답 방식으로 통신한다.&lt;/li&gt;
&lt;li&gt;gRPC: HTTP/2 를 기반으로 하여 멀티플렉싱, 헤더 압축, 서버 푸시 등 향상된 기능을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;스트리밍 지원
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RPC: 일반적으로 단방향 통신을 지원하며, 스트리밍 기능이 제한적이다.&lt;/li&gt;
&lt;li&gt;gRPC: 클라이언트 스트리밍, 서버 스트리밍, 양방향 스트리밍을 모두 지원하여 실시간 데이터 전송에 유리하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다양한 언어 지원 및 코드 생성
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RPC: 언어별로 상이한 구현이 필요하며, 코드 생성 도구의 지원이 제한적이다.&lt;/li&gt;
&lt;li&gt;gRPC: 프로토콜 버퍼를 통해 서비스와 메시지의 계약을 정의하고, 이를 기반으로 다양한 언어의 클라이언트 및 서버 코드를 자동으로 생성할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;gRPC 의 주요 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;고성능&lt;/b&gt;: 이진 직력화와 HTTP/2의 효율적인 전송 방식을 통해 낮은 지연 시간과 높은 처리량을 제공한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다양한 언어 지원&lt;/b&gt;: 하나의 프로토콜 버퍼 정의로 여러 언어의 클라이언트와 서버 코드를 생성할 수 있어, 이기종 시스템 간의 통신이 용이히다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;스티리밍 기능&lt;/b&gt;: 다양한 스티리밍 방식을 지원하여 실시간 데이터 처리에 적합하다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;엄격한 계약 기반 개발&lt;/b&gt;: 프로토콜 버퍼를 통한 명확한 인터페이스 정의로, 개발 단계에서오류를 줄이고 유지보수성을 높인다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;gRPC 의 주요 상태 코드 목록&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 160px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;코드&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;상태&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;0&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;OK&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;성공&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;1&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;CANCELLED&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;취소됨&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;2&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;UNKNOWN&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;알려지지 않은 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;3&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;INVALID_ARGUMENT&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;잘못된 인수&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;4&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;DEADLINE_EXCEEDED&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;타임아웃&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;5&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;NOT_FOUND&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;리소스를 찾을 수 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;6&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;ALREADY_EXISTS&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;리소스 이미 존재&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;7&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;PERMISSION_DENIED&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;권한 없음&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;8&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;RESOURCE_EXHAUSTED&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;리수소 부족&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;9&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;FAILED_PRECONDITION&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;작업 수행 불가 상태&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;10&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;ABORTED&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;작업 중단(충돌 발생 가능)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;11&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;OUT_OF_RANGE&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;허용범위 벗어남&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;12&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;UNIMPLEMENTED&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;서버에서 구현되지 않은 메서드 호출&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;13&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;INTERNAL&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;예기치 못한 오류&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;14&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;UNAVAILABLE&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;서비스 다운&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;15&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;DATA_LOSS&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;중요 데이터 손실&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;16&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;UNAUTHENTICATED&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%;&quot;&gt;인증 실패(권한 없음)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구현 코드(Nestjs)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/O-Seonsik/grpc-test/tree/release/1.0.0&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/O-Seonsik/grpc-test/tree/release/1.0.0&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1733752584658&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - O-Seonsik/grpc-test: grpc 테스트를 위한 저장소입니다.&quot; data-og-description=&quot;grpc 테스트를 위한 저장소입니다. Contribute to O-Seonsik/grpc-test development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/O-Seonsik/grpc-test/tree/release/1.0.0&quot; data-og-url=&quot;https://github.com/O-Seonsik/grpc-test&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bB3Z1i/hyXKmDzuys/QuL6F2TfeJzeGFTsREur80/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/sSsH4/hyXKptwEtI/WVBocf4EN04shmWPpDaMek/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/O-Seonsik/grpc-test/tree/release/1.0.0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/O-Seonsik/grpc-test/tree/release/1.0.0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bB3Z1i/hyXKmDzuys/QuL6F2TfeJzeGFTsREur80/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/sSsH4/hyXKptwEtI/WVBocf4EN04shmWPpDaMek/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - O-Seonsik/grpc-test: grpc 테스트를 위한 저장소입니다.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;grpc 테스트를 위한 저장소입니다. Contribute to O-Seonsik/grpc-test development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Backend</category>
      <category>backend</category>
      <category>grpc</category>
      <category>NestJS</category>
      <category>nodejs</category>
      <category>RPC</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/35</guid>
      <comments>https://5linesys.tistory.com/35#entry35comment</comments>
      <pubDate>Mon, 9 Dec 2024 22:54:18 +0900</pubDate>
    </item>
    <item>
      <title>마샬링(Marshalling)과 직렬화(Serialization)</title>
      <link>https://5linesys.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;마샬링(Marshalling)과 직렬화(Serialization)은 모두 데이터를 특정 형식으로 변환하는 과정이지만, 그 목적과 범위에서 차이가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;직렬화(Serialization)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;직렬화는 객체의 상태를 저장하거나 전송하기 위해 객체를 바이트 스트림과 같은 원시 데이터 형식으로 변환하는 과정이다. 이를 통해 객체를 파일에 저장하거나 네트워크를 통해 전송할 수 있으며, 나중에 이 바이트 스트림을 역직렬화(Deserialization)하여 원래의 객체로 복원할 수 있다. 직렬화는 주로 동일한 시스템 내에서 데이터를 저장하거나 전송할 때 사용된다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;마샬링(Marshalling)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마샬링은 직렬화와 유사하지만, 주로 서로 다른 시스템이나 프로그래밍 언어 간의 통신을 위해 데이터를 변환하는 과정이다. 이는 원격 프로시저 호출(RPC)에서 함수의 매개변수나 반환 값을 전달할 때 사용되며, 복잡한 객체를 단순한 원시 데이터로 변환하여 전송한다. 마샬링의 반대 과정은 언마샬링(Unmarshalling)으로, 전송된 데이터를 원래의 객체 형태로 복원한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;차이점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;목적: 직렬화는 주로 데이터를 저장하거나 동일한 시스템 내에서 전송하기 위한 것이며, 마샬링은 서로 다른 시스템이나 언어 간의 통신을 위함&lt;/li&gt;
&lt;li&gt;범위: 직렬화는 객체를 바이트 스트림으로 변환하는데 중점을 두지만, 마샬링은 데이터의 구조와 의미를 유지하면서 다른 형식으로 변환하는 것을 포함한다.&lt;/li&gt;
&lt;li&gt;사용 사례: 직렬화는 파일 저장, 메모리 버퍼, 네트워크 전송 등에 사용되며, 마샬링은 원격 프로시저 호출, 이기종 시스템 간의 데이터 교환 등에 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서, 직렬화는 객체를 저장하거나 전송하기 위한 변환 가정이며, &lt;b&gt;마샬링은&lt;/b&gt; 주로 이기종 시스템 간의 통신을 위해 데이터를 변환하는 &lt;b&gt;더 포괄적&lt;/b&gt;인 과정으로 볼 수 있다.&lt;/p&gt;</description>
      <category>기타</category>
      <category>marshalling</category>
      <category>serialization</category>
      <category>마샬링</category>
      <category>용어</category>
      <category>직렬화</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/34</guid>
      <comments>https://5linesys.tistory.com/34#entry34comment</comments>
      <pubDate>Sat, 7 Dec 2024 18:40:13 +0900</pubDate>
    </item>
    <item>
      <title>RPC(Remote Procedure Call)</title>
      <link>https://5linesys.tistory.com/33</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;RPC(Remote Procedure Call)는 네트워크를 통해 분산 시스템에서 서로 다른 컴퓨터 간의 프로시저(함수)를 호출할 수 있도록 하는 통신 메커니즘이다. RPC는 로컬 함수 호출처럼 보이지만, 실제로는 원격 서버에서 실행되는 프로세스다. 이를 통해 부산 시스템 간의 통신을 쉽게 구현할 수 있다. 이를 통해 개발자는 네트워크 통신의 복잡성을 신경 쓰지 않고도 원격 서버의 기능을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주요 특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;투명성&lt;/b&gt;: 개발자는 원격 함수 호출을 로컬 함수 호출처럼 수행할 수 있으며, 네트워크 통신의 복잡성을 숨겨준다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언어 및 플랫폼 독립성&lt;/b&gt;: RPC 는 다양한 언어와 플랫폼 간의 통신을 지원하여 이기종 시스템 간의 상호 운용성을 높인다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;계층 구조&lt;/b&gt;: 클라이언트와 서버는 서로 계층적으로 구성되며, 클라이언트와 서버가 명확히 구분된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;구성 요소&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트(Client)&lt;/b&gt;:&amp;nbsp; 원격 프로시저를 호출하는 주체&lt;/li&gt;
&lt;li&gt;&lt;b&gt;클라이언트 스텁(Client Stub&lt;/b&gt;): 클라이언트 측에서 원격 프로시저 호출을 대리하며, 매개변수를 직렬화하고 서버로 전송하는 역할을 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버 스텁(Server Stub)&lt;/b&gt;: 서버 측에서 클라이언트로부터 수신한 데이터를 역직렬화하고 실제 프로시저를 호출하며, 결과를 다시 직렬화하여 클라이언트로 전송한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;RPC 런타임(RPC Runtime)&lt;/b&gt;: 클라이언트와 서버 간의 통신을 관리하며, 메시지의 전송, 재전송, 라우팅 등을 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;동작과정&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;클라이언트 호출&lt;/b&gt;: 클라이언트는 원격 프로시저를 호출하듯이 클라이언트 스텁을 호출한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;마샬링(Marshalling)&lt;/b&gt;: 클라이언트 스텁은 전달받은 매개변수를 네트워크를 통해 전달할 수 있도록 직렬화한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;메시지 전송&lt;/b&gt;: 직렬화된 데이터는 네트워크를 통해 서버로 전송된다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언마샬링(Unmarshalling)&lt;/b&gt;: 서버 스텁은 수신한 데이터를 역직렬화 하여 원래의 매개변수 형태로 복원한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;서버 프로시저 실행&lt;/b&gt;: 서버 스텁은 실제 프로시저를 호출하여 작업을 수행한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;결과 반환&lt;/b&gt;: 서버 프로시저의 결과를 클라이언트로 전송하기 위해 다시 직렬화하고, 클라이언트는 이를 수신하여 역직렬화 후 최종 결과를 획득한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 구성 요소와 동작 과정을 통해 RPC는 분산 시스템에서의 통신을 효율적으로 처리하며, 개발자는 네트워크 통신의 복잡성을 신경 쓰지 않고 원격 함수를 호출할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;RPC와 HTTP API 의 차이&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;RPC(Remote Procedure Call)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념: 클라이언트가 원격 서버의 함수를 로컬 함수처럼 호출하여 실행 결과를 얻는 방식&lt;/li&gt;
&lt;li&gt;통신 방식:&lt;span&gt; &lt;/span&gt;일반적으로 TCP/IP를 통해 통신하며, 데이터 직렬화 형식에 따라 성능이 달라진다. 전통적인 RPC 시스템에서는 텍스트 기반의 직렬화 방식을 사용할 수 있어 데이터 크기가 커지고, 이로 인해 전송 속도가 느려질 수 있다.&lt;/li&gt;
&lt;li&gt;데이터 형식: 이진 데이터 형식을 사용하여 효율적인 통신을 지원함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;HTTP API
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;개념: HTTP 프로토콜을 기반으로 클라이언트와 서버가 요청과 응답을 주고받는 방식&lt;/li&gt;
&lt;li&gt;통신 방식: HTTP/1.1 또는 HTTP/2 를 사용하며, RESTful API 가 일반적이다.&lt;/li&gt;
&lt;li&gt;데이터 형식: JSON 이나 XML 과 같은 텍스트 기반의 데이터를 주로 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전통적인 RPC 시스템에서는 직렬화 방식과 통신 프로토콜에 따라 HTTP API보다 성능이 떨어질 수 있다. gRPC와 같은 현대적인 RPC 프레임워크는 효율적인 이진 직렬화와 HTTP/2의 장점을 활용하여 높은 성능을 제공한다. 그러나, 웹 기반의 공개 API나 브라우저와의 호환성이 중요한 경우에는 여전히 RESTful API가 널리 사용되고 있다. 따라서, 시스템의 요구사항과 환경에 따라 적합한 통신 방식을 선택하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;함께 보기 좋은 글&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;a href=&quot;https://5linesys.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://5linesys.tistory.com/34&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1733564534614&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;마샬링(Marshalling)과 직렬화(Serialization)&quot; data-og-description=&quot;마샬링(Marshalling)과 직렬화(Serialization)은 모두 데이터를 특정 형식으로 변환하는 과정이지만, 그 목적과 범위에서 차이가 있다.&amp;nbsp;직렬화(Serialization)직렬화는 객체의 상태를 저장하거나 전송하기 &quot; data-og-host=&quot;blog.oseonsik.com&quot; data-og-source-url=&quot;https://5linesys.tistory.com/34&quot; data-og-url=&quot;https://blog.oseonsik.com/34&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/5zZyW/hyXGNCutwE/qDoT2SpTIiP9W9GPGhxtZK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bbrTja/hyXGOuFonI/TYiTkjkSliHV8RrKzkQxUk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://5linesys.tistory.com/34&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://5linesys.tistory.com/34&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/5zZyW/hyXGNCutwE/qDoT2SpTIiP9W9GPGhxtZK/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bbrTja/hyXGOuFonI/TYiTkjkSliHV8RrKzkQxUk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;마샬링(Marshalling)과 직렬화(Serialization)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;마샬링(Marshalling)과 직렬화(Serialization)은 모두 데이터를 특정 형식으로 변환하는 과정이지만, 그 목적과 범위에서 차이가 있다.&amp;nbsp;직렬화(Serialization)직렬화는 객체의 상태를 저장하거나 전송하기&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;blog.oseonsik.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Backend</category>
      <category>backend</category>
      <category>MSA</category>
      <category>network</category>
      <category>RPC</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/33</guid>
      <comments>https://5linesys.tistory.com/33#entry33comment</comments>
      <pubDate>Sat, 7 Dec 2024 18:27:52 +0900</pubDate>
    </item>
    <item>
      <title>Terraform nonsensitive</title>
      <link>https://5linesys.tistory.com/32</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Terraform에서 &lt;span&gt;nonsensitive&lt;/span&gt; 함수는 민감한(Sensitive) 값의 민감성 표시를 제거하여 해당 값을 일반 값처럼 취급할 수 있게 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 함수는 Terraform 버전 0.15부터 사용 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용 목적&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Terraform은 민감한 정보를 보호하기 위해 변수나 리소스의 값을 &lt;b&gt;민감한 값(Sensitive Value)&lt;/b&gt;으로 표시할 수 있다. 이렇게 설정된 값은 Terraform의 출력이나 로그에 노출되지 않도록 처리한다. 그러나 특정 상황에서는 이러한 민감성 표시를 제거하고 값을 일반 값처럼 사용해야 할 필요가  있다. 이때 &lt;span&gt;nonsensitive&lt;/span&gt; 함수를 사용하여 민감성 표시를 제거할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;사용 예시&lt;/h3&gt;
&lt;pre id=&quot;code_1732799520972&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;variable &quot;secret_value&quot; {
  type      = string
  sensitive = true
}

output &quot;exposed_value&quot; {
  value = nonsensitive(var.secret_value)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;주의사항&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;보안 위험&lt;/b&gt;: 민감한 값을 일반 값으로 변환하여 출력하거나 로그에 노출하면 보안 위험이 발생할 수 있다. 따라서, 정말 필요한 경우에만 사용해야 하며, 사용 시 민감한 정보가 노출되지 않도록 주의해야 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;의도적인 사용&lt;/b&gt;: nonsensitive&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;함수는 Terraform의 기본 민감성 처리 동작을 무시하고 값을 노출시키는 기능이므로, 의도적으로 사용해야 한다. 불필요한 사용은 보안 사고로 이어질 수 있다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>기타</category>
      <category>DevOps</category>
      <category>HCL</category>
      <category>Infra</category>
      <category>nonsensitive</category>
      <category>sensitive</category>
      <category>terraform</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/32</guid>
      <comments>https://5linesys.tistory.com/32#entry32comment</comments>
      <pubDate>Thu, 28 Nov 2024 22:16:05 +0900</pubDate>
    </item>
    <item>
      <title>Nestjs Request Lifecycle</title>
      <link>https://5linesys.tistory.com/31</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;request lifecycle.png&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;896&quot;&gt;&lt;a href=&quot;https://velog.io/@youngkiu/NestJS-request-lifecycle&quot; target=&quot;_blank&quot; title=&quot;출처&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OQLvR/btsKVrkbDOA/pvWjHF7lno7mhzaASUHmbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOQLvR%2FbtsKVrkbDOA%2FpvWjHF7lno7mhzaASUHmbK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;2500&quot; height=&quot;896&quot; data-filename=&quot;request lifecycle.png&quot; data-origin-width=&quot;2500&quot; data-origin-height=&quot;896&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;Nestjs Request Lifecycle&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Middleware (미들웨어)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치: 요청 처리의 가장 첫 단계&lt;/li&gt;
&lt;li&gt;역할: HTTP 요청/응답을 가로채어 수정하거나 처리 여부를 결정&lt;/li&gt;
&lt;li&gt;주요 기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청 로깅&lt;/li&gt;
&lt;li&gt;헤더 조작&lt;/li&gt;
&lt;li&gt;요청 본문 파싱&lt;/li&gt;
&lt;li&gt;CORS 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732440867860&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// Interceptor 구현
@Injectable()
export class LoggerMiddleware implements NestMiddleware {
  use(req: Request, res: Response, next: NextFunction) {
    console.log(`Request ${req.method} ${req.url}`);
    next();
  }
}

// Interceptor 적용
import { Module, NestModule, MiddlewareConsumer } from '@nestjs/common';
import { LoggerMiddleware } from './common/middleware/logger.middleware';
import { CatsModule } from './cats/cats.module';

@Module({
  imports: [CatsModule],
})
export class AppModule implements NestModule {
  configure(consumer: MiddlewareConsumer) {
    consumer
      .apply(LoggerMiddleware)
      .forRoutes('cats');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. Guards(가드)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치: 미들웨어 다음, 라우트 핸들러 이전&lt;/li&gt;
&lt;li&gt;역할: 인증/인가 등 요청의 실행 허가 여부를 결정&lt;/li&gt;
&lt;li&gt;주요 기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인증 상태 확인&lt;/li&gt;
&lt;li&gt;권한 체크&lt;/li&gt;
&lt;li&gt;접근 제어&lt;/li&gt;
&lt;li&gt;IP 기반 필터링&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732440881990&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(context: ExecutionContext): boolean {
    const request = context.switchToHttp().getRequest();
    return !!request.headers.authorization;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Interceptors (인터셉터)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치: 가드 다음, 라우트 핸들러 전후&lt;/li&gt;
&lt;li&gt;역할: 요청/응답 변환, 추가 로직 실행&lt;/li&gt;
&lt;li&gt;주요 기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;응답 데이터 변환&lt;/li&gt;
&lt;li&gt;성능 모니터링&lt;/li&gt;
&lt;li&gt;캐시 처리&lt;/li&gt;
&lt;li&gt;로깅&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732440900022&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
export class TimingInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable&amp;lt;any&amp;gt; {
    const start = Date.now();
    return next.handle().pipe(
      tap(() =&amp;gt; console.log(`Request took ${Date.now() - start}ms`))
    );
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. Pipes (파이프)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치: 인터셉터와 라우트 핸들러 사이&lt;/li&gt;
&lt;li&gt;역할: 데이터 변환 및 유효성 검사&lt;/li&gt;
&lt;li&gt;주요 기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;입력 데이터 유효성 검사&lt;/li&gt;
&lt;li&gt;데이터 타입 변환&lt;/li&gt;
&lt;li&gt;DTO 검증&lt;/li&gt;
&lt;li&gt;기본값 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732440914275&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Post()
createUser(@Body(new ValidationPipe()) createUserDto: CreateUserDto) {
  return this.usersService.create(createUserDto);
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. Controller (컨트롤러)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치: 파이프 다음, 비즈니스 로직 이전&lt;/li&gt;
&lt;li&gt;역할: 요청 라우팅 및 요청/응답 처리&lt;/li&gt;
&lt;li&gt;주요 기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;요청 경로 매핑&lt;/li&gt;
&lt;li&gt;요청 파라미터 추출&lt;/li&gt;
&lt;li&gt;서비스 계층 호출&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732440931294&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Controller('users')
export class UsersController {
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.usersService.findOne(id);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. Service (서비스)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치: 컨트롤러 다음&lt;/li&gt;
&lt;li&gt;역할: 비즈니스 로직 실행&lt;/li&gt;
&lt;li&gt;주요 기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;데이터 처리&lt;/li&gt;
&lt;li&gt;외부 서비스 통신&lt;/li&gt;
&lt;li&gt;데이터베이스 작업&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732440945415&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Injectable()
export class UsersService {
  async findOne(id: string): Promise&amp;lt;User&amp;gt; {
    return this.usersRepository.findOne(id);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7.&amp;nbsp;Exception Filters (예외 필터)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위치: 전체 요청/응답 사이클에서 예외 발생 시&lt;/li&gt;
&lt;li&gt;역할: 예외 처리 및 에러 응답 생성&lt;/li&gt;
&lt;li&gt;주요 기능:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러 로깅&lt;/li&gt;
&lt;li&gt;사용자 정의 에러 응답&lt;/li&gt;
&lt;li&gt;예외 변환&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1732440956571&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp();
    const response = ctx.getResponse();
    const status = exception.getStatus();

    response.status(status).json({
      statusCode: status,
      timestamp: new Date().toISOString(),
      message: exception.message,
    });
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;통합 사용 예시&lt;/h3&gt;
&lt;pre id=&quot;code_1732440984576&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@UseGuards(AuthGuard)
@UseInterceptors(LoggingInterceptor)
@UseFilters(HttpExceptionFilter)
@Controller('users')
export class UsersController {
  @Post()
  @UsePipes(ValidationPipe)
  create(@Body() createUserDto: CreateUserDto) {
    return this.usersService.create(createUserDto);
  }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Node</category>
      <category>Lifecycle</category>
      <category>nesjts</category>
      <category>Nest</category>
      <category>request lifecycle</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/31</guid>
      <comments>https://5linesys.tistory.com/31#entry31comment</comments>
      <pubDate>Sun, 24 Nov 2024 18:41:06 +0900</pubDate>
    </item>
    <item>
      <title>Nestjs Lifecycle 과 Event hooks</title>
      <link>https://5linesys.tistory.com/30</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 라이프사이클&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS는 애플리케이션 시작과 종료 시 다양한 이벤트를 발생시킨다. 이를 통해 초기화 작업, 리소스 설정, 클린업(종료 작업) 등을 수행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전체 수명 주기를 초기화, 실행 및 종료의 세 단계로 나눌 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;lifecycle-events.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;820&quot;&gt;&lt;a href=&quot;https://docs.nestjs.com/fundamentals/lifecycle-events#lifecycle-sequence&quot; target=&quot;_blank&quot; title=&quot;lifecycle-event&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c1lhGF/btsKN3yshat/EfY4iAIklAvt2a03x6gXK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc1lhGF%2FbtsKN3yshat%2FEfY4iAIklAvt2a03x6gXK0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;970&quot; height=&quot;820&quot; data-filename=&quot;lifecycle-events.png&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;820&quot;/&gt;&lt;/a&gt;&lt;figcaption&gt;nestjs 공식 문서에 나와있는 라이프사이클 이벤트 설명&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 라이프사이클 이벤트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;NestJS 의 Lifecycle Events 는 애플리케이션 또는 특정 구성 요소(module, provider, controller)의 수명 주기 동안 특정 시점에 실행되는 메서드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명시적으로 각 훅의 인터페이스를 &lt;code&gt;implements&lt;/code&gt; 해야 훅이 정상적으로 트리거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.1. 애플리케이션 초기화 관련 이벤트&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.0077%;&quot;&gt;이벤트&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;대상&lt;/td&gt;
&lt;td style=&quot;width: 50.4263%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.0077%;&quot;&gt;OnModuleInit&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;모듈, 프로바이더&lt;/td&gt;
&lt;td style=&quot;width: 50.4263%;&quot;&gt;모듈이나 프로바이더가 생성되고 의존성이 주입된 후 호출된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 26.0077%;&quot;&gt;OnApplicationBootstrap&lt;/td&gt;
&lt;td style=&quot;width: 23.5659%;&quot;&gt;애플리케이션, 프로바이더&lt;/td&gt;
&lt;td style=&quot;width: 50.4263%;&quot;&gt;애플리케이션의 모든 초기화가 완료된 후 호출한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;예제: OnModuleInit&lt;/p&gt;
&lt;pre id=&quot;code_1732024244243&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable, OnModuleInit } from '@nestjs/common';

@Injectable()
export class AppService implements OnModuleInit {
  onModuleInit() {
    console.log('Module has been initialized');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;예제: OnApplicationBootstrap&lt;/p&gt;
&lt;pre id=&quot;code_1732024151560&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { Injectable, OnApplicationBootstrap } from '@nestjs/common';

@Injectable()
export class AppService implements OnApplicationBootstrap {
  onApplicationBootstrap() {
    console.log('Application has been bootstrapped');
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;2.2 애플리케이션 종료 관련 이벤트&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 74px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;이벤트&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;대상&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;OnModuleDestory&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;모듈, 프로바이더&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;모듈이 종료되기 전에 호출된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 18px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;BeforeApplicationShutdown&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;애플리케이션, 프로바이더&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 18px;&quot;&gt;애플리케이션 종료 전 호출된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;OnAppliationShutdown&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;애플리케이션, 프로바이더&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 20px;&quot;&gt;애플리케이션 종료 후 호출된다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종료 훅(hook) 리스너는 시스템 리소스를 소모하므로 기본적으로 &lt;b&gt;비활성화&lt;/b&gt;된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 테이블의 종료 관련 훅(&lt;code&gt;OnModuleDestory&lt;/code&gt;, &lt;code&gt;BeforeApplicationShutdown&lt;/code&gt;, &lt;code&gt;OnApplicationShutdown&lt;/code&gt;)은 명시적으로 &lt;code&gt;app.close()&lt;/code&gt; 를 호출하거나 특수 시스템 신호(예: &lt;code&gt;SIGTERM&lt;/code&gt;) 를 수신하고 애플리케이션 부트스트랩에서 &lt;code&gt;enableShutdownHooks&lt;/code&gt; 를 올바르게 호출한 경우에 트리거된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종료 훅(hook) 리스너 활성화 예시&lt;/p&gt;
&lt;pre id=&quot;code_1732024215176&quot; class=&quot;typescript&quot; data-ke-language=&quot;typescript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);

  // Starts listening for shutdown hooks
  app.enableShutdownHooks();

  await app.listen(process.env.PORT ?? 3000);
}
bootstrap();&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Node</category>
      <category>application</category>
      <category>application lifecycle</category>
      <category>event hook</category>
      <category>Lifecycle</category>
      <category>NestJS</category>
      <category>nestjs application lifecycle</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/30</guid>
      <comments>https://5linesys.tistory.com/30#entry30comment</comments>
      <pubDate>Tue, 19 Nov 2024 22:52:22 +0900</pubDate>
    </item>
    <item>
      <title>분산 락(Distributed lock)</title>
      <link>https://5linesys.tistory.com/29</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 분산 락의 상세 개념&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;정의&lt;/b&gt;: 분산 시스템에서 공유 자원에 대한 동시 접근을 제어하는 동기화 메커니즘입니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;작동 방식&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 서버/프로세스가 접근할 수 있는 공유 저장소(Redis, ZooKeeper 등)에 락을 저장&lt;/li&gt;
&lt;li&gt;락을 획득하려는 프로세스는 원자적 연산으로 락 생성을 시도&lt;/li&gt;
&lt;li&gt;락을 획득한 프로세스만 공유 자원에 접근 가능&lt;/li&gt;
&lt;li&gt;작업 완료 후 락을 해제하여 다른 프로세스가 사용할 수 있게 함&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 분산 락의 핵심 요구사항&lt;b&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;상호 배제(Mutual Exclusion)&lt;/b&gt;: 특정 시점에 하나의 프로세스만 락을 보유할 수 있음&lt;/li&gt;
&lt;li&gt;&lt;b&gt;데드락 방지(Deadlock Prevention)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;락 획득 실패 시 적절한 타임아웃 설정&lt;/li&gt;
&lt;li&gt;락 보유자가 비정상 종료된 경우를 대비한 자동 해제 메커니즘&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;고가용성(High Availability)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;락 서비스 자체의 안정성 보장&lt;/li&gt;
&lt;li&gt;장애 상황에서도 시스템 전체가 마비되지 않도록 설계&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;성능(Performance)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;최소한의 네트워크 통신으로 락 획득/해제&lt;/li&gt;
&lt;li&gt;적절한 락 밀도(Granularity) 설정&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 활용 예시&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;다중 서버/인스턴스 환경
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 서버가 동일한 리소스에 접근하는 MSA(Microservice Architecture) 환경&lt;/li&gt;
&lt;li&gt;오토스케일링으로 인스턴스가 동적으로 증감하는 클라우드 환경&lt;/li&gt;
&lt;li&gt;서버가 물리적으로 다른 위치에 분산되어 있는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;다중 database 사용환경&lt;br /&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;글로벌 트랜잭션 관리의 어려움
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;여러 DB간의 트랜잭션 정합성 보장이 필요&lt;/li&gt;
&lt;li&gt;Two-Phase Commit의 성능 오버헤드가 큼&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;DB간 동기화 시점 관리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 DB의 복제 지연 발생 가능&lt;/li&gt;
&lt;li&gt;Master-Slave 구조에서의 지연 시간 차이&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;단일 DB의 락으로는 전체 시스템의 동시성 제어가 불가능
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;각 DB는 자신의 트랜잭션만 관리 가능&lt;/li&gt;
&lt;li&gt;DB간 상호 락 인지 불가능&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;외부 api 요청
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;같은 요청을 2번 이상 하면 안되는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;4. 분산 락의 구현&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;각 프로세스는 임계구역에 접근하는 작업시에 락 획득을 요청&lt;/li&gt;
&lt;li&gt;락 획득 실패(다른 프로세스에서 이미 점유 중)시에는 락 획득 요청 재시도(spin lock)&lt;/li&gt;
&lt;li&gt;락 획득 제한 횟수 초과시에 작업 실패 처리 후 프로세스 종료&lt;/li&gt;
&lt;li&gt;락 획득 시에는 프로스에서 임계구역 접근하여 작업처리
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최대한 짧은 단위로 작업을 수행하여 빠르게 락을 반환해야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;락 반환&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와같이 특정 임계구역에 동시에 접근하여 중복된 작업이 생기는 것을 방지하기 위해 분산 락(Distributed Lock)을 활용할 수 있따.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Redis 를 통해 분산 락을 구현한 코드는 다음 링크에서 확인 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/distributed-lock&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/distributed-lock&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;분산 락 테스트를 위한 모듈을 같은 프로젝트의 다른 모듈에 구성해두었다. 다음 링크에서 확인 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/products&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/products&lt;/a&gt;&lt;/p&gt;</description>
      <category>Backend</category>
      <category>Distributed Lock</category>
      <category>Redis</category>
      <category>분산 락</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/29</guid>
      <comments>https://5linesys.tistory.com/29#entry29comment</comments>
      <pubDate>Sun, 17 Nov 2024 20:19:30 +0900</pubDate>
    </item>
    <item>
      <title>낙관적 락(Optimistic Lock)과 비관적 락(Pessimistic Lock)</title>
      <link>https://5linesys.tistory.com/28</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 낙관적 락(OPtimistic Lock)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;낙관적 락은 충돌이 잘 발생하지 않는다고 가정하고 자원을 제어하는 방식이다. 자원을 사용하는 동안 락을 거는 대신, 작업을 끝내기 직전에 충돌이 발생했는지 검사한다. 낙관적 락은 다음과 같은 과정으로 동작한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원을 사용할 때 락을 걸지 않고, 다른 프로세스도 동시에 접근할 수 있도록 허용한다.&lt;/li&gt;
&lt;li&gt;자원 사용이 완료되면, 그 동안 자원이 변경되지 않았는지 확인한다.&lt;/li&gt;
&lt;li&gt;만약 다른 프로세스가 자원을 변경한 것이 확인되면, 작업을 취소하고 다시 시도한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 방식은 자원을 사용하는 동안 락이 걸리지 않기 때문에 성능이 높으며, 충돌이 거의 발생하지 않는 환경에서 효과적이다. 하지만 충돌이 빈번하다면 작업을 반복해야 할 수 있어 비효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 비관적 락 (Pessimistic Lcok)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비관적 락은 충돌이 발생할 가능성이 높다고 가정하여 자원에 접근하기 전에 락을 거는 방식이다. 락을 건 프로세스가 작업을 완료하기 전까지 다른 프로세스는 자원에 접근할 수 없다. 비관적 락의 동작 과정은 다음과 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원에 접근할 때 락을 걸고, 다른 프로세스가 접근하지 못하도록 막는다.&lt;/li&gt;
&lt;li&gt;자원 사용이 끝난 후 락을 해제하여 다른 프로세스가 자원에 접근할 수 있도록 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비관적 락은 충돌이 빈번하게 발생하는 환경에서 유리하며, 충돌이 발생할 가능성이 낮아도 확실하게 자원을 보호할 수 있따. 그러나 항상 락을 거는 동작이 있어 자원 사용에 따라 성능에 부담이 될 수 있따.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;낙관적 락: 충돌 가능성이 낮은 경우에 유리하며, 충돌이 발생하지 않을 것이라고 가정. 작업 종료시 변경 검증.&lt;/li&gt;
&lt;li&gt;비관적 락: 충돌 가능성이 높은 경우에 유리하며, 자원을 사용할 때 락을 걸어 안전하게 보호.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 두 방식은 시스템의 특성에 따라 선택되며, 서로 다른 상황에서 적합하게 사용될 수 있다.&lt;/p&gt;
&lt;div style=&quot;color: #333333; text-align: left;&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;nestjs + typeorm 으로 구현한 간단한 코드를 다음 링크에서 확인 가능&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/seller&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/seller&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>DB</category>
      <category>db</category>
      <category>NestJS</category>
      <category>optimistic lock</category>
      <category>pessimistic lock</category>
      <category>typerom</category>
      <category>낙관적 락</category>
      <category>비관적 락</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/28</guid>
      <comments>https://5linesys.tistory.com/28#entry28comment</comments>
      <pubDate>Thu, 14 Nov 2024 20:51:54 +0900</pubDate>
    </item>
    <item>
      <title>DB - 블로킹(Blocking)과 데드 락(Deadlock)</title>
      <link>https://5linesys.tistory.com/27</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;블로킹(Blocking)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정의&lt;/b&gt;:&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;한 트랜잭션이 자원(테이블, 행 등)을 Lock 하고 있을 때, 다른 트랜잭션이 해당 자원에 접근하지 못하고 기다리는 현상&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;특징&lt;/b&gt;:&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일시적인 현상으로, Lock 이 해제되면 자연스럽게 해결됨&lt;/li&gt;
&lt;li&gt;정상적인 데이터베이스 동작의 일부&lt;/li&gt;
&lt;li&gt;데이터 일관성을 보장하기 위한 매커니즘&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예시 코드&lt;/b&gt;)&lt;/h4&gt;
&lt;pre id=&quot;code_1731326247489&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 블로킹 예시

-- 트랜잭션 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 여기서 잠시 멈춤 (아직 COMMIT하지 않음)

-- 트랜잭션 2 (동시 실행)
BEGIN;
UPDATE accounts SET balance = balance + 50 WHERE id = 1;  
-- 트랜잭션 1이 COMMIT할 때까지 대기 (블로킹)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;데드 락(Deadlock)&lt;/b&gt;&lt;/h3&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정의&lt;/b&gt;:&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;두 개 이상의 트랜잭션이 각각의 자원을 점유한 상태에서 상대방의 자원을 요청하며 무한히 기다리는 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;특징&lt;/b&gt;:&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자연스럽게 해결되지 않음&lt;/li&gt;
&lt;li&gt;시스템의 개입이 필요함&lt;/li&gt;
&lt;li&gt;순환 대기가 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;발생조건&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;상호 배제(Mutual Exclusion)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자원은 한 번에 하나의 트랜잭션만 사용 가능&lt;/li&gt;
&lt;li&gt;다른 트랜잭션은 해당 자원 사용 불가&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;점유와 대기(Hold and Wait)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션이 최소한 하나의 자원을 보유&lt;/li&gt;
&lt;li&gt;다른 트랜잭션이 사용 중인 자원을 추가로 요청&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;비선점(No Preemption)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미 할당된 자원을 강제로 빼앗을 수 없음&lt;/li&gt;
&lt;li&gt;자원을 가진 트랜잭션이 자발적으로 해제하기 전까지 계속 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;순환 대기(Circular Wait)
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;트랜잭션들이 순환 형태로 자원을 요청&lt;/li&gt;
&lt;li&gt;각 트랜잭션은 다음 트랜잭션이 가진 자원을 요청&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예시 코드&lt;/b&gt;)&lt;/h4&gt;
&lt;pre id=&quot;code_1731326315084&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 데드락 예시

-- 트랜잭션 1
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
-- 여기서 id=2인 레코드의 락을 기다림
UPDATE accounts SET balance = balance + 100 WHERE id = 2;

-- 트랜잭션 2 (동시 실행)
BEGIN;
UPDATE accounts SET balance = balance - 100 WHERE id = 2;
-- 여기서 id=1인 레코드의 락을 기다림
UPDATE accounts SET balance = balance + 100 WHERE id = 1;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데드락 해결 방안&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 1. 예방(Prevention)&lt;/p&gt;
&lt;pre id=&quot;code_1731326707759&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 1. 순서 기반 접근
BEGIN;
SELECT * FROM accounts 
WHERE id IN (1, 2) 
ORDER BY id FOR UPDATE;  -- 항상 작은 ID부터 잠금

-- 2. 한 번에 모든 자원 획득
BEGIN;
SELECT * FROM accounts 
WHERE id IN (1, 2, 3) FOR UPDATE;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&amp;nbsp; 2. 회피(Avoidance)&lt;/p&gt;
&lt;pre id=&quot;code_1731326745680&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 타임아웃 설정
SET innodb_lock_wait_timeout = 50;  -- 50초 후 타임아웃

-- 트랜잭션 격리 수준 조정
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; 3. 감지 및 복구(Detection &amp;amp; Recovery)&lt;/p&gt;
&lt;pre id=&quot;code_1731326761794&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 데드락 정보 확인
SHOW ENGINE INNODB STATUS;

-- 데드락 발생 시 자동으로 롤백되는 트랜잭션 처리
BEGIN;
DECLARE EXIT HANDLER FOR DEADLOCK
BEGIN
    ROLLBACK;
    -- 재시도 로직
END;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;데드락 방지를 위한 Best Practices&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;애플리케이션 레벨
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;트랜잭션 범위를 최소화&lt;/li&gt;
&lt;li&gt;일관된 순서로 데이터 접근&lt;/li&gt;
&lt;li&gt;대량 처리 시 배치 처리 활용&lt;/li&gt;
&lt;li&gt;적절한 인덱스 설계&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;데이터베이스 레벨
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;적절한 격리 수준 설정&lt;/li&gt;
&lt;li&gt;인덱스 최적화&lt;/li&gt;
&lt;li&gt;주기적인 모니터링&lt;/li&gt;
&lt;li&gt;타임아웃 설정&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;운영관리
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;데드락 로그 모니터링&lt;/li&gt;
&lt;li&gt;성능 지표 관리&lt;/li&gt;
&lt;li&gt;주기적인 테이블 유지보수&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결론&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;블로킹과 데드락은 모두 동시성 제어 과정에서 발생하는 현상이지만, 블로킹은 정상적인  동작의 일부로 볼 수 있는 반면, 데드락은 비정상적인 상황으로 보고 적극적인 방지가 필요하다. 효과적인 데이터베이스 설계와 모니터링을 통해 두 현상 모두 최소화할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;특히 실제 운영환경에서는 데드락 발생 시 자동으로 재시도하는 로직을 구현하는 것이 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버측에서 재시도 관련 처리를 테스트를 진행한 코드를 다음 링크에서 확인 가능&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/products&quot;&gt;https://github.com/O-Seonsik/lock-test/tree/master/src/modules/products&lt;/a&gt;&lt;/p&gt;</description>
      <category>DB</category>
      <category>blocking</category>
      <category>Database</category>
      <category>db</category>
      <category>DEADLOCK</category>
      <category>데드 락</category>
      <category>블로킹</category>
      <author>5linesys</author>
      <guid isPermaLink="true">https://5linesys.tistory.com/27</guid>
      <comments>https://5linesys.tistory.com/27#entry27comment</comments>
      <pubDate>Mon, 11 Nov 2024 22:27:25 +0900</pubDate>
    </item>
  </channel>
</rss>