マイクロサービスアーキテクチャ:サービス分割と通信実装

マイクロサービス

マイクロサービスは、単一責任に特化した多数の小規模プロジェクトを基盤として、複雑な大規模アプリケーションを構成するソフトウェアアーキテクチャスタイルです。

サービス分割戦略

いつ分割すべきか?

  • スタートアッププロジェクト:まず単一アーキテクチャを採用し、迅速な開発と試行錯誤を重ねます。規模が拡大するにつれて、段階的に分割します。
  • 大規模確定プロジェクト:資金が豊富で目標が明確な場合は、マイクロサービスアーキテクチャを直接選択し、後の分割作業を避けます。

どのように分割するか?

分割目標から見ると、以下の原則を満たす必要があります:

  • 高凝集性:各マイクロサービスの責務はできるだけ単一で、包含するビジネス間の関連性が高く、完全性が高い必要があります。
  • 低結合性:各マイクロサービスの機能は相対的に独立しており、他のマイクロサービスへの依存をできるだけ減らす必要があります。

分割方法から見ると、通常以下の2つの方式が含まれます:

  • 縦分割:ビジネスモジュールに基づいて分割します
  • 横分割:共通サービスを抽出し、再利用性を高めます

eコマースプラットフォーム例

eコマースプラットフォームを例に、元々すべてのビジネスが単一プロジェクト内にあったものを、以下の5つのマイクロサービスに分割できます:

  • ユーザーサービス
  • 商品サービス
  • 注文サービス
  • ショッピングカートサービス
  • 支払いサービス

以下は分割後のプロジェクト構造です。ここでは負荷分散をテストしたため、2つの商品マイクロサービスインスタンスを起動しています。

登録センター

マイクロサービス間のリモート呼び出しプロセスでは、2つの役割が含まれます:

  • サービスプロバイダ:他のマイクロサービスがアクセスするインターフェースを提供します(例:product-service
  • サービスコンシューマ:他のマイクロサービスが提供するインターフェースを呼び出します(例:cart-service

大規模マイクロサービスプロジェクトでは、サービスプロバイダの数が非常に多くなるため、これらのサービスを管理するために登録センターの概念が導入されます。

ここではNacos(Alibaba社製、現在SpringCloudAlibabaに統合されています)を採用しています。

データベースのインポート

まず、nacosが必要とするsqlファイルをデータベース(ここではmysqlを例に)にインポートする必要があります。

データベースの設定

次に、/root/nacos/custom.envに設定ファイルを作成します。

ここでは実際にnacosのデータベースを設定しています。

PREFER_HOST_MODE=hostname
MODE=standalone
SPRING_DATASOURCE_PLATFORM=mysql
MYSQL_SERVICE_HOST=192.168.88.188
MYSQL_SERVICE_DB_NAME=nacos
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_USER=root
MYSQL_SERVICE_PASSWORD=123
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai

Nacosコンテナの作成

dockerを使用してnacosコンテナを作成します。

docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slim

起動完了後、nacosログインページにアクセスできます:http://IP:8848/nacos/、アカウントとパスワードは両方ともnacosです。

サービス登録

application.ymlnacos設定を追加します。

spring:
  application:
    name: product-service # サービス名
  cloud:
    nacos:
      server-addr: 192.168.88.188:8848 # nacosアドレス

コンソールにアクセスすると、サービス登録が成功したことが確認でき、サービスインスタンス情報を見ることができます。

サービス発見

pom.xmlに依存関係を導入し、application.ymlnacos設定を追加します。

<!--nacos サービス登録と発見-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

その後、サービス呼び出し側は負荷分散アルゴリズムを利用して、複数のインスタンスから1つを選んで購読サービスにアクセスできます。

一般的な負荷分散アルゴリズムには以下のようなものがあります:

  • ランダム
  • ラウンドロビン
  • IPのハッシュ
  • 最近最少アクセス
  • など...

ここでは最もシンプルなランダム負荷分散を選択できます。

OpenFeignリモート呼び出し

依存関係の導入

OpenFeignはリモート呼び出しをローカルメソッド呼び出しのように簡単にします。

まずOpenFeignの依存関係と負荷分散の依存関係を導入します。

  <!--openFeign-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-openfeign</artifactId>
  </dependency>
  <!--負荷分散器-->
  <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-loadbalancer</artifactId>
  </dependency>

また、接続プールの依存関係としてokhttpを選択します。

<!--OK http 依存関係 -->
<dependency>
  <groupId>io.github.openfeign</groupId>
  <artifactId>feign-okhttp</artifactId>
</dependency>

application.ymlで接続プールを有効にします。

feign:
  okhttp:
    enabled: true # OKHttp機能を有効化

コンポーネントの有効化

次に、プロジェクト起動クラスにアノテーションを追加して、OpenFeign機能を有効化します:

@EnableFeignClients(basePackages = "com.example.hmall.api.client", defaultConfiguration = DefaultFeignConfig.class)
@MapperScan("com.example.hmall.pay.mapper")
@SpringBootApplication
public class PaymentApplication {
    public static void main(String[] args) {
        SpringApplication.run(PaymentApplication.class, args);
    }
}

使用方法

一般的に、重複したClientインターフェースの記述を避けるために、コードを抽出する2つの方法が採られます(図参照):

  • アプローチ1:マイクロサービス外の共通moduleに抽出
  • アプローチ2:各マイクロサービスが独自のmoduleを抽出

アプローチ1の抽出はよりシンプルで、プロジェクト構造も比較的明確ですが、欠点はプロジェクト全体の結合度が高くなることです。

アプローチ2の抽出は比較的複雑で、プロジェクト構造もより複雑ですが、サービス間の結合度が低くなります。

ここでは2番目の方法を採用しているため、他のサービスは依存関係を導入することでClientを使用できます。

  <dependency>
      <groupId>com.example.hmall</groupId>
      <artifactId>hm-api</artifactId>
      <version>1.0.0</version>
  </dependency>

続いてClientの記述方法を見てみましょう。

@FeignClient("product-service")
public interface ProductClient {

    @GetMapping("/products")
    List<ProductDTO> queryProductsByIds(@RequestParam("ids") Collection<Long> ids);

    @PutMapping("/inventory/reduce")
    void reduceInventory(@RequestBody List<OrderDetailDTO> items);
}

対応するserviceでは、Clientを通じてリモート呼び出しを行います。

//    private final IProductService productService;
    private final ProductClient productClient;
//        List<ProductDTO> products = productService.queryProductsByIds(productIds);
        List<ProductDTO> products = productClient.queryProductsByIds(productIds);

ログレベルの設定

開始クラスのアノテーション@EnableFeignClientsでグローバルに有効化する必要があり、ローカルで有効化したい場合は特定のClientで設定することもできます。

public class DefaultFeignConfig {
    @Bean
    public Logger.Level feignLogLevel(){
        return Logger.Level.FULL;
    }
}

タグ: Nacos Spring Cloud OpenFeign マイクロサービス サービス分割

7月5日 00:24 投稿