Basics
Basics
Nest ๋ง์ดํฌ๋ก ์๋น์ค๋ HTTP์ ๋ค๋ฅธ ์ ์ก ๊ณ์ธต์ ์ฌ์ฉํ๋ ์์ฉ ํ๋ก๊ทธ๋จ ์ ํ์ ๋๋ค.
Installation
๋จผ์ ํ์ํ ํจํค์ง๋ฅผ ์ค์นํด์ผ ํฉ๋๋ค.
$ npm i --save @nestjs/microservicesOverview
์ผ๋ฐ์ ์ผ๋ก Nest๋ ์ฌ๋ฌ ๋ด์ฅ ์ ์ก๊ธฐ๋ฅผ ์ง์ํฉ๋๋ค. ์์ฒญ-์๋ต ๋ฐ ์ด๋ฒคํธ ๊ธฐ๋ฐ ํจ๋ฌ๋ค์์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ฉฐ ์ ์ฒด ํต์ ๋ก์ง์ด ์ถ์ํ ๊ณ์ธต ๋ค์ ์จ๊ฒจ์ ธ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์ฝ๋ ๋ผ์ธ์ ๋ณ๊ฒฝํ์ง ์๊ณ ๋ ์ด์ก์ ์ฒด(transporter)๊ฐ์ ์ฝ๊ฒ ์ ํ ํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ ์์ฒญ-์๋ต ํจ๋ฌ๋ค์์ ๋ค์ํ ๋ฒ์์ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋๋ก ์ค๊ณ๋ Kafka ๋๋ NATS ์คํธ๋ฆฌ๋ฐ๊ณผ ๊ฐ์ ๋ก๊ทธ ๊ธฐ๋ฐ ์ง์์ฑ์ด ์ ๊ณต๋๋ ์คํธ๋ฆฌ๋ฐ ํ๋ซํผ์์๋ ๊ทธ๋ค์ง ์๋ฏธ๊ฐ ์์ต๋๋ค. ๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ์ด๋ฒคํธ ๊ธฐ๋ฐ (๋จ๋ฐฉํฅ) ํต์ ๋๋ ์์ฉ ํ๋ก๊ทธ๋จ ์ปจํ ์คํธ ๊ธฐ๋ฅ๊ณผ ํจ๊ป ์ฌ์ฉํ ์ ์์ต๋๋ค.
Getting started
๋ง์ดํฌ๋ก ์๋น์ค๋ฅผ ์์ฑํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ NestFactory ํด๋์ค์ createMicroservice()๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@@filename(main)
import { NestFactory } from '@nestjs/core';
import { Transport } from '@nestjs/microservices';
import { ApplicationModule } from './app.module';
async function bootstrap() {
const app = await NestFactory.createMicroservice(ApplicationModule, {
transport: Transport.TCP,
});
app.listen(() => console.log('Microservice is listening'));
}
bootstrap();info ํํธ ๋ง์ดํฌ๋ก ์๋น์ค๋ ๊ธฐ๋ณธ์ ์ผ๋ก TCP ํ๋กํ ์ฝ์ ํตํด ๋ฉ์์ง๋ฅผ ๋ฃ๊ณ ์์ต๋๋ค.
createMicroservice()๋ฉ์๋์ ๋ ๋ฒ์งธ ์ธ์๋ ์ต์
๊ฐ์ฒด์
๋๋ค. ์ด ๊ฐ์ฒด์๋ ๋ ๋ฉค๋ฒ๊ฐ ์์ ์ ์์ต๋๋ค.
transport
Specifies the transporter (for example, Transport.NATS)
options
ํธ๋์คํฌํฐ ๋์์ ๊ฒฐ์ ํ๋ ํธ๋์คํฌํฐ๋ณ ์ต์ ๊ฐ์ฒด
The ์ต์
๊ฐ์ฒด๋ ์ ํํ ํธ๋์คํฌํฐ์ ๋ฐ๋ผ ๋ค๋ฆ
๋๋ค. TCP ํธ๋์คํฌํฐ๋ ์๋์ ์ค๋ช
๋ ๋ช๊ฐ์ง ์์ฑ์ ๊ฐ์ ธ์ต๋๋ค.
host
์ฐ๊ฒฐ ํธ์คํธ ์ด๋ฆ
port
์ฐ๊ฒฐ ํฌํธ
retryAttempts
์ด ์ฐ๊ฒฐ ์๋ ํ์
retryDelay
์ฐ๊ฒฐ ์ฌ์๋ ์ง์ฐ(ms)
Patterns
๋ง์ดํฌ๋ก ์๋น์ค๋ ํจํด์ ํตํด ๋ฉ์์ง์ ์ด๋ฒคํธ๋ฅผ ๋ชจ๋ ์ธ์ํฉ๋๋ค. ํจํด์ ๋ฆฌํฐ๋ด ๊ฐ์ฒด ๋๋ ๋ฌธ์์ด๊ณผ ๊ฐ์ ์ผ๋ฐ ๊ฐ์ ๋๋ค. ๊ฒฐ๊ตญ ๋ชจ๋ ํจํด์ด ์ง๋ ฌํ๋๋ฏ๋ก ๋ฐ์ดํฐ์ ํจ๊ป ๋คํธ์ํฌ๋ฅผ ํตํด ์ ์ก๋ ์ ์์ต๋๋ค. ๋ฐ๋ผ์, ๋ฆฌ์๋ฒ๋ ๋ค์ด์ค๋ ๋ฉ์์ง๋ฅผ ๋์ํ๋ ํธ๋ค๋ฌ์ ์ฝ๊ฒ ์ฐ๊ด์ํฌ ์์๋ค.
Request-response
์์ฒญ-์๋ต ํต์ ๋ฉ์ปค๋์ฆ์ ๋ค์ํ ์ธ๋ถ ์๋น์ค๊ฐ์ ๋ฉ์์ง๋ฅผ ๊ตํํด์ผ ํ ๋ ์ ์ฉํฉ๋๋ค. ๋ํ ์ด ํจ๋ฌ๋ค์์ ์ฌ์ฉํ๋ฉด ์๋น์ค๊ฐ ์ค์ ๋ก ๋ฉ์์ง๋ฅผ ์์ ํ๋์ง ํ์ธํ ์ ์์ต๋๋ค.
์๋น์ค๊ฐ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ตํํ ์ ์๋๋ก Nest๋ ๋ ์ฑ๋์ ์์ฑํฉ๋๋ค. ํ๋๋ ๋ฐ์ดํฐ ์ ์ก์ ๋ด๋นํ๊ณ ๋ค๋ฅธ ํ๋๋ ๋ค์ด์ค๋ ์๋ต์ ์์ ํฉ๋๋ค. ๊ทธ๋ฌ๋ ํญ์ ๊ทธ๋ฐ ๊ฒ์ ์๋๋๋ค. ์๋ฅผ ๋ค์ด NATS์ ๊ฐ์ ํ๋ซํผ์ ์ด๋ฌํ ๊ธฐ๋ฅ์ ๊ธฐ๋ณธ์ ์ผ๋ก ์ ๊ณตํ๋ฏ๋ก ์์ฒด์ ์ผ๋ก ์ํํ ํ์๊ฐ ์์ต๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก, ์์ฒญ-์๋ต ํจ๋ฌ๋ค์์ ๊ธฐ๋ฐ์ผ๋ก ํ๋ ๋ฉ์์ง ํธ๋ค๋ฌ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ฐ๋ฆฌ๋ @nestjs/microservices ํจํค์ง์์ ๊ฐ์ ธ์จ @MessagePattern()๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@@filename(math.controller)
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
@Controller()
export class MathController {
@MessagePattern({ cmd: 'sum' })
accumulate(data: number[]): number {
return (data || []).reduce((a, b) => a + b);
}
}
accumulate() ํธ๋ค๋ฌ๋ cmd:'sum' ํจํด์ ์ถฉ์กฑ์ํค๋ ๋ฉ์์ง๋ฅผ ๋ฃ๊ณ ์์ต๋๋ค. ํจํด ํธ๋ค๋ฌ๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ ๋ฌ๋ data๋ผ๋ ๋จ์ผ ์ธ์๋ฅผ ์ทจํฉ๋๋ค. ์ด ๊ฒฝ์ฐ, ๋ฐ์ดํฐ๋ ๋์ ๋์ด์ผ ํ๋ ์ซ์์ ๋ฐฐ์ด์
๋๋ค.
Asynchronous responses
๊ฐ ๋ฉ์์ง ํธ๋ค๋ฌ๋ ๋๊ธฐ์ ๋๋ ๋น๋๊ธฐ์์ผ๋ก ์๋ตํ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ async ๋ฉ์๋๊ฐ ์ง์๋ฉ๋๋ค.
@@filename()
@MessagePattern({ cmd: 'sum' })
async accumulate(data: number[]): Promise<number> {
return (data || []).reduce((a, b) => a + b);
}
๋ํ Observable์ ๋ฐํํ ์ ์์ผ๋ฏ๋ก ์คํธ๋ฆผ์ด ์๋ฃ ๋ ๋๊น์ง ๊ฐ์ด ๋ฐฉ์ถ๋ฉ๋๋ค.
@@filename()
@MessagePattern({ cmd: 'sum' })
accumulate(data: number[]): Observable<number> {
return from([1, 2, 3]);
}
์์ ๋ฉ์์ง ์ฒ๋ฆฌ๊ธฐ๋ ๋ฐฐ์ด์ ๊ฐ ํญ๋ชฉ๊ณผ ํจ๊ป 3 ๋ฒ ์๋ตํฉ๋๋ค.
Event-based
์์ฒญ-์๋ต ๋ฐฉ๋ฒ์ ์๋น์ค๊ฐ์ ๋ฉ์์ง๋ฅผ ์ง์์ ์ผ๋ก ๊ตํํด์ผ ํ ๋ ์ ์ฉํ์ง๋ง ์๋ต์ ๊ธฐ๋ค๋ฆฌ์ง ์๊ณ ์ด๋ฒคํธ๋ฅผ ๊ฒ์ํ๋ ค๊ณ ํ ๋ ์์ ํ ์ธ๋ชจ์๋ ๋ถํ์ํ ์ค๋ฒ ํค๋๊ฐ ๋๋ฌด ๋ง์ด ๋ฐ์ํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์์คํ ์ ์ด ๋ถ๋ถ์์ ํน์ ์ํฉ์ด ๋ฐ์ํ์์ ๋ค๋ฅธ ์๋น์ค์ ์๋ฆฌ๋ ค๊ณ ํฉ๋๋ค. ๋ฐ๋ผ์, ์ด๋ฒคํธ ๊ธฐ๋ฐ ํต์ ๋ ์ง์ํฉ๋๋ค.
์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ฐ๋ฆฌ๋@nestjs/microservices ํจํค์ง์์ ๊ฐ์ ธ์จ @EventPattern ()๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํฉ๋๋ค.
@@filename()
@EventPattern('user_created')
async handleUserCreated(data: Record<string, unknown>) {
// business logic
}
handleUserCreated()๋ฉ์๋๋ user_created ์ด๋ฒคํธ๋ฅผ ์ฒญ์ทจํ๊ณ ์์ต๋๋ค. ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์ ๋ฌ ๋ data๋ผ๋ ๋จ์ผ ์ธ์๋ฅผ ๋ฐ์ต๋๋ค (์ด ๊ฒฝ์ฐ ๋คํธ์ํฌ๋ฅผ ํตํด ์ ์ก๋ ์ด๋ฒคํธ ํ์ด๋ก๋).
Client
๋ฉ์์ง๋ฅผ ๊ตํํ๊ฑฐ๋ Nest ๋ง์ดํฌ๋ก ์๋น์ค์ ์ด๋ฒคํธ๋ฅผ ๊ฒ์ํ๊ธฐ ์ํด ๋ช๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ์์ฑํ ์ ์๋ ClientProxyํด๋์ค๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋จผ์ ์ ์ register()๋ฉ์๋๋ฅผ ๋
ธ์ถํ๋ ClientsModule์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ด ๋ฉ์๋๋ ๋ชจ๋ ์์๊ฐ name (๋ง์ดํฌ๋ก ์๋น์ค ์๋ณ์์ ์ผ์ข
)๊ณผ ๋ง์ดํฌ๋ก ์๋น์ค ํน์ ์ต์
(์ด๊ฒ์ดcreateMicroservice() ๋ฐฉ๋ฒ์ ์ ๋ฌ๋ ๊ฒ๊ณผ ๋์ผํ ๊ฐ์ฒด)์ ๊ฐ๋ ๋งค๊ฐ ๋ณ์๋ก ๋ฐฐ์ด์ ์ทจํฉ๋๋ค.
ClientsModule.register([
{ name: 'MATH_SERVICE', transport: Transport.TCP },
]),info ํํธ
ClientsModule์@nestjs/microservicesํจํค์ง์์ ๊ฐ์ ธ์ต๋๋ค.
๋ชจ๋์ ๊ฐ์ ธ ์ค๋ฉด @Inject()๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ์ฌ MATH_SERVICE๋ฅผ ์ฃผ์
ํ ์ ์์ต๋๋ค.
constructor(
constructor(
@Inject('MATH_SERVICE') private readonly client: ClientProxy,
) {}
)info ํํธ
ClientProxyํด๋์ค๋@nestjs/microservicesํจํค์ง์์ ๊ฐ์ ธ์ต๋๋ค.
๊ทธ๋ผ์๋ ๋ถ๊ตฌํ๊ณ ,์ด ์ ๊ทผ๋ฒ์ ๋ง์ดํฌ๋ก ์๋น์ค ๊ตฌ์ฑ์ ๋น๋๊ธฐ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ์, ์ฐ๋ฆฌ๋ ํด๋ผ์ด์ธํธ ์ธ์คํด์ค ์ธ Custom provider๋ฅผ ๋ฑ๋กํ๊ธฐ ์ํด ClientProxyFactory๋ฅผ ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค :
{
provide: 'MATH_SERVICE',
useFactory: (configService: ConfigService) => {
const mathSvcOptions = configService.getMathSvcOptions();
return ClientProxyFactory.create(mathSvcOptions);
},
inject: [ConfigService],
}info ํํธ
ClientProxyFactory๋@nestjs/microservicesํจํค์ง์์ ๊ฐ์ ธ์ต๋๋ค.
๋ง์ง๋ง์ผ๋ก ๊ฐ๋ฅํ ํด๊ฒฐ์ฑ
์ @Client()์์ฑ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์
๋๋ค.
@Client({ transport: Transport.TCP })
client: ClientProxy;info ํํธ
@Client()๋@nestjs/microservicesํจํค์ง์์ ๊ฐ์ ธ์ต๋๋ค.
๊ทธ๋ฌ๋ ๋ฐ์ฝ๋ ์ดํฐ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅ๋์ง ์์ต๋๋ค (ํ ์คํธํ๊ธฐ ์ด๋ ต๊ณ ํด๋ผ์ด์ธํธ ์ธ์คํด์ค๋ฅผ ๊ณต์ ํ๊ธฐ๊ฐ ์ด๋ ต์ต๋๋ค).
ClientProxy๋ ๊ฒ์ผ๋ฅธ์
๋๋ค. ์ฆ์ ์ฐ๊ฒฐ์ ์์ํ์ง ์์ต๋๋ค. ๋์ , ์ฒซ ๋ฒ์งธ ๋ง์ดํฌ๋ก ์๋น์ค ํธ์ถ ์ ์ ์ค์ ๋๊ณ ์ดํ์ ๊ฐ ํธ์ถ์์ ์ฌ์ฌ์ฉ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์ ํ๋ฆฌ์ผ์ด์
๋ถํธ ์คํธ๋ฉ ํ๋ก์ธ์ค๋ฅผ ์ง์ฐ์ํค๊ณ ์ฐ๊ฒฐ์ ์๋์ผ๋ก ์ด๊ธฐํํ๋ ค๋ฉด OnModuleInit ๋ผ์ดํ ์ฌ์ดํด ํํฌ ๋ด์์ connect()๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
@@filename()
async onModuleInit() {
await this.client.connect();
}์ฐ๊ฒฐ์ ๋ง๋ค ์ ์์ผ๋ฉด connect()๋ฉ์๋๋ ํด๋น ์ค๋ฅ ๊ฐ์ฒด์ ํจ๊ป ๊ฑฐ๋ถ๋ฉ๋๋ค.
Sending messages
ClientProxy๋ send()๋ฉ์๋๋ฅผ ๋
ธ์ถ์ํต๋๋ค. ์ด ๋ฉ์๋๋ ๋ง์ดํฌ๋ก ์๋น์ค๋ฅผ ํธ์ถํ๊ธฐ ์ํ ๊ฒ์ด๋ฉฐ ์๋ต๊ณผ ํจ๊ป Observable์ ๋ฐํํฉ๋๋ค. ๋ฐ๋ผ์ ๋ฐฉ์ถ๋ ๊ฐ์ ์ฝ๊ฒ ๊ฐ์
ํ ์ ์์ต๋๋ค.
@@filename()
accumulate(): Observable<number> {
const pattern = { cmd: 'sum' };
const payload = [1, 2, 3];
return this.client.send<number>(pattern, payload);
}
send()๋ฉ์๋๋ pattern๊ณผ payload๋ผ๋ ๋ ๊ฐ์ ์ธ์๋ฅผ ์ทจํฉ๋๋ค. pattern์ @MessagePattern() ๋ฐ์ฝ๋ ์ดํฐ์ ์ ์๋ ๊ฒ๊ณผ ๋์ผํด์ผ ํ๋ฉฐ, payload๋ ๋ค๋ฅธ ๋ง์ดํฌ๋ก ์๋น์ค๋ก ์ ์กํ๋ ค๋ ๋ฉ์์ง์
๋๋ค.
Publishing events
๋ ๋ค๋ฅธ ๋ฐฉ๋ฒ์ emit()์
๋๋ค. ์ด ๋ฐฉ๋ฒ์ ์ฑ
์์ ์ด๋ฒคํธ๋ฅผ ๋ฉ์์ง ๋ธ๋ก์ปค์ ๊ณต๊ฐํ๋ ๊ฒ์
๋๋ค.
@@filename()
async publish() {
this.client.emit<number>('user_created', new UserCreatedEvent());
}
emit()๋ฉ์๋๋ pattern๊ณผ payload๋ผ๋ ๋ ๊ฐ์ ์ธ์๋ฅผ ์ทจํฉ๋๋ค. pattern์ @EventPattern() ๋ฐ์ฝ๋ ์ดํฐ์ ์ ์๋ ๊ฒ๊ณผ ๋์ผํด์ผํ๋ฉฐ, payload๋ ๋ค๋ฅธ ๋ง์ดํฌ๋ก ์๋น์ค๋ก ์ ์กํ๋ ค๋ ์ด๋ฒคํธ ํ์ด๋ก๋์
๋๋ค.
Last updated
Was this helpful?