<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                企業??AI智能體構建引擎,智能編排和調試,一鍵部署,支持知識庫和私有化部署方案 廣告
                # 微服務 ## 概述 除了傳統的(有時稱為單片)應用程序架構之外,`Nest` 還支持微服務架構風格的開發。本文檔中其他地方討論的大多數概念,如依賴項注入、裝飾器、異常過濾器、管道、保護和攔截器,都同樣適用于微服務。`Nest` 會盡可能地抽象化實現細節,以便相同的組件可以跨基于 `HTTP` 的平臺,`WebSocket` 和微服務運行。本節特別討論 `Nest` 的微服務方面。 在 `Nest` 中,微服務基本上是一個使用與 `HTTP` 不同的傳輸層的應用程序。 ![](https://docs.nestjs.com/assets/Microservices_1.png) `Nest` 支持幾種內置的傳輸層實現,稱為傳輸器,負責在不同的微服務實例之間傳輸消息。大多數傳輸器本機都支持請求 - 響應和基于事件的消息樣式。`Nest` 在規范接口的后面抽象了每個傳輸器的實現細節,用于請求 - 響應和基于事件的消息傳遞。這樣可以輕松地從一個傳輸層切換到另一層,例如,利用特定傳輸層的特定可靠性或性能功能,而不會影響您的應用程序代碼。 ### 安裝 首先,我們需要安裝所需的軟件包: ```bash $ npm i --save @nestjs/microservices ``` ### 開始 為了創建微服務,我們使用 `NestFactory` 類的 `createMicroservice()` 方法。 > main.ts ```typescript import { NestFactory } from '@nestjs/core'; import { Transport, MicroserviceOptions } from '@nestjs/microservices'; import { AppModule } from './app.module'; async function bootstrap() { const app = await NestFactory.createMicroservice<MicroserviceOptions>( AppModule, { transport: Transport.TCP, }, ); app.listen(() => console.log('Microservice is listening')); } bootstrap(); ``` > 默認情況下,微服務通過 **TCP協議** 監聽消息。 `createMicroservice ()` 方法的第二個參數是 `options` 對象。此對象可能有兩個成員: ||| |---|---| | `transport` | 指定傳輸器,例如`Transport.NATS` | | `options` | 確定傳輸器行為的傳輸器特定選項對象 | `options` 對象根據所選的傳送器而不同。`TCP` 傳輸器暴露了下面描述的幾個屬性。其他傳輸器(如Redis,MQTT等)參見相關章節。 ||| |---|---| | `host` | 連接主機名 | | `port` | 連接端口| | `retryAttempts` | 連接嘗試的總數 | | `retryDelay` | 連接重試延遲(ms) | ### 模式(patterns) 微服務通過 **模式** 識別消息。模式是一個普通值,例如對象、字符串。模式將自動序列化,并與消息的數據部分一起通過網絡發送。因此,接收器可以容易地將傳入消息與相應的處理器相關聯。 ### 請求-響應 當您需要在各種外部服務之間交換消息時,請求-響應消息樣式非常有用。使用此范例,您可以確定服務確實收到了消息(不需要手動實現消息 `ACK` 協議)。然而,請求-響應范式并不總是最佳選擇。例如,使用基于日志的持久性的流傳輸器(如 `Kafka` 或 `NATS` 流)針對解決不同范圍的問題進行了優化,更符合事件消息傳遞范例(有關更多細節,請參閱下面的基于事件的消息傳遞)。 為了使服務能夠通過網絡交換數據,`Nest` 創建了兩個通道,其中一個負責傳輸數據,而另一個負責監聽傳入的響應。對于某些底層傳輸,比如 `NATS`,這種雙通道是支持開箱即用的。對于其他人,`Nest` 通過手動創建單獨的渠道進行補償。 這樣做可能會產生開銷,因此,如果您不需要請求-響應消息樣式,則應考慮使用基于事件的方法。 基本上,要創建一個消息處理程序(基于請求 - 響應范例),我們使用 `@MessagePattern()` ,需要從 `@nestjs/microservices` 包導入。 > math.controller.ts ```typescript 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` 。在這種情況下,數據是必須累加的數字數組。 ### 異步響應 每個模式處理程序都能夠同步或異步響應。因此,支持 `async` (異步)方法。 > math.controller.ts ```typescript @MessagePattern({ cmd: 'sum' }) async accumulate(data: number[]): Promise<number> { return (data || []).reduce((a, b) => a + b); } ``` 此外,我們能夠返回 [Rx](https://github.com/reactivex/rxjs) `Observable`,因此這些值將被發出,直到流完成。 ```typescript @MessagePattern({ cmd: 'sum' }) accumulate(data: number[]): Observable<number> { return from([1, 2, 3]); } ``` 以上消息處理程序將響應3次(對數組中的每個項)。 ### 基于事件 雖然 `request-response` 方法是在服務之間交換消息的理想方法,但是當您的消息樣式是基于事件的時(即您只想發布事件而不等待響應時),它不太適合。它會帶來太多不必要的開銷,而這些開銷是完全無用的。例如,您希望簡單地通知另一個服務系統的這一部分發生了某種情況。這種情況就適合使用基于事件的消息風格。 為了創建事件處理程序,我們使用 `@EventPattern()`裝飾器, 需要 ` @nestjs/microservices` 包導入。 ```typescript @EventPattern('user_created') async handleUserCreated(data: Record<string, unknown>) { // business logic } ``` > 你可以為單獨的事件模式注冊多個事件處理程序,所有的事件處理程序都會并行執行 該 `handleUserCreated()` 方法正在偵聽 `user_created` 事件。事件處理程序接受一個參數,`data` 從客戶端傳遞(在本例中,是一個通過網絡發送的事件有效負載)。 ### 裝飾器 在更復雜的場景中,您可能希望訪問關于傳入請求的更多信息。例如,對于通配符訂閱的 `NATS`,您可能希望獲得生產者發送消息的原始主題。同樣,在 `Kafka` 中,您可能希望訪問消息頭。為了做到這一點,你可以使用內置的裝飾如下: ```typescript @MessagePattern('time.us.*') getDate(@Payload() data: number[], @Ctx() context: NatsContext) { console.log(`Subject: ${context.getSubject()}`); // e.g. "time.us.east" return new Date().toLocaleTimeString(...); } ``` > `@Payload()`、`@Ctx()` 和 `NatsContext` 需要從 `@nestjs/microservices` 包導入。 > 你也可以為 `@Payload()` 裝飾器傳入一個屬性key值,來獲取通過此裝飾器拿到的對象的value值,例如 `@Payload('id')` ### 客戶端 為了交換消息或將事件發布到 `Nest` 微服務,我們使用 `ClientProxy` 類, 它可以通過幾種方式創建實例。此類定義了幾個方法,例如`send()`(用于請求-響應消息傳遞)和`emit()`(用于事件驅動消息傳遞),這些方法允許您與遠程微服務通信。使用下列方法之一獲取此類的實例。 首先,我們可以使用 `ClientsModule` 暴露的靜態`register()` 方法。此方法將數組作為參數,其中每個元素都具有 `name`屬性,以及一個可選的`transport`屬性(默認是`Transport.TCP`),以及特定于微服務的`options`屬性。 `name`屬性充當一個 `injection token`,可以在需要時將其用于注入 `ClientProxy` 實例。`name` 屬性的值作為注入標記,可以是任意字符串或`JavaScript`符號,[參考這里](https://docs.nestjs.com/fundamentals/custom-providers#non-class-based-provider-tokens)。 `options` 屬性是一個與我們之前在`createMicroservice()`方法中看到的相同的對象。 ```typescript @Module({ imports: [ ClientsModule.register([ { name: 'MATH_SERVICE', transport: Transport.TCP }, ]), ] ... }) ``` 導入模塊之后,我們可以使用 `@Inject()` 裝飾器將`'MATH_SERVICE'`注入`ClientProxy`的一個實例。 ```typescript constructor( @Inject('MATH_SERVICE') private client: ClientProxy, ) {} ``` > `ClientsModule`和 `ClientProxy`類需要從 `@nestjs/microservices` 包導入。 有時候,我們可能需要從另一個服務(比如 `ConfigService` )獲取微服務配置而不是硬編碼在客戶端程序中,為此,我們可以使用 `ClientProxyFactory` 類來注冊一個[自定義提供程序](https://docs.nestjs.com/fundamentals/custom-providers),這個類有一個靜態的`create()`方法,接收傳輸者選項對象,并返回一個自定義的 `ClientProxy` 實例: ```typescript @Module({ providers: [ { provide: 'MATH_SERVICE', useFactory: (configService: ConfigService) => { const mathSvcOptions = configService.getMathSvcOptions(); return ClientProxyFactory.create(mathSvcOptions); }, inject: [ConfigService], } ] ... }) ``` > `ClientProxyFactory` 需要從 `@nestjs/microservices` 包導入 。 另一種選擇是使用 `@client()`屬性裝飾器。 ```typescript @Client({ transport: Transport.TCP }) client: ClientProxy; ``` > `@Client()` 需要從 `@nestjs/microservices` 包導入 。 但是,使用 `@Client()` 裝飾器不是推薦的方法(難以測試,難以共享客戶端實例)。 `ClientProxy` 是惰性的。 它不會立即啟動連接。 相反,它將在第一個微服務調用之前建立,然后在每個后續調用中重用。 但是,如果您希望將應用程序引導過程延遲到建立連接為止,則可以使用 `OnApplicationBootstrap` 生命周期掛鉤內的 `ClientProxy` 對象的 `connect()` 方法手動啟動連接。 ```typescript async onApplicationBootstrap() { await this.client.connect(); } ``` 如果無法創建連接,則該 `connect()` 方法將拒絕相應的錯誤對象。 ### 發送消息 該 `ClientProxy` 公開 `send()` 方法。 此方法旨在調用微服務,并返回帶有其響應的 `Observable`。 因此,我們可以輕松地訂閱發射的值。 ```typescript 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` 是我們想要傳輸到另一個微服務的消息。該方法返回一個`cold Observable`對象,這意味著您必須在消息發送之前顯式地訂閱它。 ### 發布事件 另一種是使用 `ClientProxy` 對象的 `emit()`方法。此方法的職責是將事件發布到消息代理。 ```typescript async publish() { this.client.emit<number>('user_created', new UserCreatedEvent()); } ``` 該 `emit()`方法有兩個參數,`pattern` 和 `payload`。`pattern` 具有 `@EventPattern()` 修飾符中定義的這個模式,而`payload` 是我們想要傳輸到另一個微服務的消息。此方法返回一個 `hot Observable`(不同于`send()`方法返回一個 `cold Observable`),這意味著無論您是否顯式訂閱該 `Observable`,代理都將立即嘗試傳遞事件。 ### 作用域 對于不同編程語言背景的人來說,可能會意外地發現,在 `Nest` 中,幾乎所有內容都在傳入的請求之間共享。例如,我們有一個到數據庫的連接池,帶有全局狀態的單例服務,等等。請記住,`Node.js` 并不遵循`request-response`的多線程無狀態模型,在這種模型中,每個請求都由單獨的線程處理。因此,對于應用程序來說,使用單例實例是完全安全的。 但是,在某些情況下,當應用程序是基于生命周期的行為時,也存在邊界情況,例如 `GraphQL` 應用程序中的每個請求緩存、請求跟蹤或多租戶。在[這里](/8/fundamentals)學習如何控制范圍。 請求作用域的處理程序和提供程序可以使用 `@Inject()` 裝飾器結合`CONTEXT` (上下文)令牌注入`RequestContext`: ```typescript import { Injectable, Scope, Inject } from '@nestjs/common'; import { CONTEXT, RequestContext } from '@nestjs/microservices'; @Injectable({ scope: Scope.REQUEST }) export class CatsService { constructor(@Inject(CONTEXT) private readonly ctx: RequestContext) {} } ``` 還提供了對 `RequestContext` 對象的訪問,該對象有兩個屬性: ```typescript export interface RequestContext<T = any> { pattern: string | Record<string, any>; data: T; } ``` `data` 屬性是消息生產者發送的消息有效負載。 `pattern` 屬性是用于標識適當的處理程序以處理傳入消息的模式。 #### 處理超時 在分布式系統中,有時微服務可能宕機或者無法訪問。要避免無限等待,可以使用超時,超時是一個和其他服務通訊的可信賴的方法。要在微服務中應用超時,你可以使用`RxJS`超時操作符。如果微服務沒有在指定時間內返回響應,會拋出異常以便正確捕獲與處理。 要處理該問題,可以使用`[rxjs](https://github.com/ReactiveX/rxjs)`包,并在管道中使用`timeout`操作符。 ```TypeScript this.client .send<TResult, TInput>(pattern, data) .pipe(timeout(5000)) .toPromise(); ``` > `timeout`操作符從`rxjs/operators`中引入 5秒后,如果微服務沒有響應,將拋出錯誤。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看