画像サービスのような高 QPS、高トラフィックのサービスでは、VPC 直接接続を通じてサービスを呼び出すことで、パフォーマンスが大幅に向上し、レイテンシーが削減されます。しかし、この方法では複数のサービスインスタンス間での負荷分散は提供されません。マイクロサービスアーキテクチャで既に Nacos を使用している場合、EAS と統合してサービスアクセスを管理し、クライアントサイドロードバランシングを有効にすることができます。本トピックでは、EAS サービスを Nacos インスタンスに関連付けて呼び出す方法について説明します。
現在、Nacos 統合は LLM のインテリジェントルーティングをサポートしていません。
仕組み
EAS サービスに VPC を設定すると、システムはサービスの各 Pod に VPC IP アドレスを割り当てます。
EAS は、推論サービスの Pod を関連付けられた Nacos インスタンスに登録します。
クライアントは Nacos からのサービス登録イベントをサブスクライブします。
Nacos は、EAS サービスの IP アドレスリストの変更をクライアントにプッシュします。
クライアントは SDK を使用してインスタンスを選択します。この SDK には、加重ラウンドロビン (WRR) 負荷分散アルゴリズムが組み込まれています。
クライアントは、SDK から返された IP アドレスとポートを使用してサービスを呼び出します。
設定方法
コンソールでの設定
デプロイ設定ページの ネットワーク情報 セクションで、VPC を設定し、サービス検出 Nacos の関連付け を有効にします。
VPC の設定。Nacos と関連付けるには、EAS サービス用に VPC、vSwitch、およびセキュリティグループを設定する必要があります。まだ作成していない場合は、「VPC の作成と管理」および「セキュリティグループの管理」をご参照ください。
Nacos インスタンスは、EAS サービスと同じ VPC および vSwitch 内に存在する必要があります。
vSwitch の CIDR ブロックに十分な利用可能な IP アドレスがあることを確認してください。
重要ECS インスタンスなどのクライアントと EAS サービスインスタンス間のネットワークアクセスは、セキュリティグループルールによって制御されます。
デフォルトでは、基本セキュリティグループ内のインスタンスは、内部ネットワークを介して相互に通信できます。EAS サービスの VPC ダイレクト接続を設定する際に、EAS サービスにアクセスする必要がある ECS インスタンスが配置されているセキュリティグループを選択できます。
異なるセキュリティグループを使用するには、ECS インスタンス間の通信を許可するようにセキュリティグループルールを設定する必要があります。詳細については、「クラシックネットワーク内の異なるセキュリティグループのインスタンス間のアクセスを許可する」をご参照ください。
[Service Discovery Nacos] を[サービス検出 Nacos の関連付け]し、表示されるダイアログボックスから Nacos インスタンスを選択します。インスタンスがない場合は、まず「MSE レジストリインスタンスの作成」を行ってください。
ディザスタリカバリのために、1 つのサービスに複数の Nacos インスタンスを関連付けることができます。サービスは、関連付けられたすべてのインスタンスに登録されます。
JSON での設定
Nacos インスタンスを関連付けるには、次の JSON パラメーターが必要です。各パラメーターの詳細については、「コンソールでの設定」をご参照ください。
パラメーター | 説明 | ||
cloud | networking | vpc_id | EAS サービスの VPC、vSwitch、およびセキュリティグループの ID。 |
vswitch_id | |||
security_group_id | |||
networking | nacos | nacos_id | 作成した Nacos インスタンスの ID。 |
設定例:
{
"cloud": {
"networking": {
"security_group_id": "sg-*****",
"vpc_id": "vpc-***",
"vswitch_id": "vsw-****"
}
},
"networking": {
"nacos": [
{
"nacos_id": "mse_regserverless_cn-****"
}
]
}
}サービス登録の確認
サービスがデプロイされると、EAS はそれを関連付けられた Nacos インスタンスに登録します。登録情報は次のとおりです:
cluster:デフォルトで
DEFAULTクラスターになります。namespace:デフォルトのパブリック名前空間です。
serviceName:サービス名です。
groupName:システムが生成した値
pai-easです。
インスタンスの数とステータスが正しいことを確認してください:
サービス詳細ページの [Providers] タブで、インスタンスの [Health Status] と [Online/Offline Status] が両方とも正常 (緑色) であり、[Weight] が 100 であることを確認してください。
クライアントからの呼び出し
Go
package main
import (
"fmt"
"github.com/nacos-group/nacos-sdk-go/v2/clients"
"github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client"
"github.com/nacos-group/nacos-sdk-go/v2/common/constant"
"github.com/nacos-group/nacos-sdk-go/v2/model"
"github.com/nacos-group/nacos-sdk-go/v2/util"
"github.com/nacos-group/nacos-sdk-go/v2/vo"
"strconv"
"testing"
"time"
)
var Clients = make(map[string]NacosClientManager)
type NacosClientManager struct {
userId string
endPoint string
client naming_client.INamingClient
}
func NewAndGetNacosClient(userId string, endPoint string) (*NacosClientManager, error) {
key := generateKey(userId, endPoint)
client, exists := Clients[key]
if exists {
return &client, nil
}
client, exists = Clients[key]
if exists {
return &client, nil
}
newClient, err := clients.NewNamingClient(
vo.NacosClientParam{
ClientConfig: constant.NewClientConfig(
constant.WithNamespaceId(""),
constant.WithTimeoutMs(5000),
constant.WithNotLoadCacheAtStart(true),
constant.WithLogDir("/tmp/nacos/log"),
constant.WithCacheDir("/tmp/nacos/cache"),
constant.WithLogLevel("debug"),
),
ServerConfigs: []constant.ServerConfig{
*constant.NewServerConfig(endPoint, 8848, constant.WithContextPath("/nacos")),
},
},
)
if err != nil {
return nil, err
}
nacosClient := NacosClientManager{
userId: userId,
endPoint: endPoint,
client: newClient,
}
Clients[key] = nacosClient
return &nacosClient, nil
}
func (p *NacosClientManager) SelectOneHealthyInstance(param vo.SelectOneHealthInstanceParam) (*model.Instance, error) {
instance, err := p.client.SelectOneHealthyInstance(param)
if err != nil {
return nil, fmt.Errorf("SelectOneHealthyInstance failed: %v", err)
}
fmt.Printf("SelectOneHealthyInstance success, param: %+v\n", param)
return instance, nil
}
func (p *NacosClientManager) Subscribe(service string, group string) error {
subscribeParam := &vo.SubscribeParam{
ServiceName: service,
GroupName: group,
SubscribeCallback: func(services []model.Instance, err error) {
fmt.Printf("callback return services:%s \n\n", util.ToJsonString(services))
},
}
return p.client.Subscribe(subscribeParam)
}
func generateKey(userId string, endPoint string) string {
return userId + fmt.Sprintf("-%s", endPoint)
}
func Test(t *testing.T) {
nacosClient, err := NewAndGetNacosClient("yourAliyunUid", "yourNacosEndpoint")
if err != nil {
panic(err)
}
nacosClient.Subscribe("your_service", "pai-eas")
params := vo.SelectOneHealthInstanceParam{
ServiceName: "your_service",
GroupName: "pai-eas",
}
instance, err := nacosClient.SelectOneHealthyInstance(params)
fmt.Println(instance)
// コンソールの呼び出し情報にある IP アドレスとポートでホストを置き換えます。
url := fmt.Sprintf("http://%s:%s/api/predict/xxxxxxx", instance.Ip, strconv.FormatUint(instance.Port, 10))
fmt.Println(url)
// TODO: この URL を使用してサービスを呼び出します。
} Python
公式の Nacos Python SDK には、組み込みの負荷分散アルゴリズムがないため、加重ラウンドロビンなど、独自のアルゴリズムを実装する必要があります。
依存関係のインストール
pip install nacos-sdk-pythonサービスの呼び出し
# -*- coding: utf8 -*-
import nacos
# Nacos サーバーの設定
SERVER_ADDRESSES = "yourNacosEndpoint"
NAMESPACE = "" # 空の場合はデフォルトの名前空間を使用
SERVICE_NAME = "your_service"
GROUP_NAME = "pai-eas"
# Nacos クライアントの作成
client = nacos.NacosClient(SERVER_ADDRESSES, namespace=NAMESPACE)
def callback(args):
print(args)
if __name__ == '__main__':
# サービスインスタンスの変更をサブスクライブ
client.add_naming_listener(SERVICE_NAME, GROUP_NAME, callback)
# ネーミングインスタンスの詳細を取得して表示
b = client.list_naming_instance(SERVICE_NAME, group_name=GROUP_NAME, healthy_only=True)
print(b)
if "hosts" in b and b["hosts"]:
print("ip", b["hosts"][0]["ip"])
ip = b["hosts"][0]["ip"]
port = b["hosts"][0]["port"]
# コンソールの呼び出し情報にある IP アドレスとポートでホストを置き換えます。
url = f"http://{ip}:{port}/api/predict/xxxxxxx"
print(url)
# TODO: この URL を使用してサービスを呼び出します。 Java
Maven 依存関係の追加
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.3.2</version>
</dependency>サービスの呼び出し
package test;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.listener.AbstractEventListener;
import com.alibaba.nacos.api.naming.listener.Event;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.listener.NamingEvent;
import com.alibaba.nacos.api.naming.pojo.Instance;
public class NacosTest {
public static void main(String[] args) {
try {
String serverAddr = "yourNacosEndpoint:8848";
NamingService namingService = NacosFactory.createNamingService(serverAddr);
ExecutorService executorService = Executors.newFixedThreadPool(1);
EventListener serviceListener = new AbstractEventListener() {
@Override
public void onEvent(Event event) {
if (event instanceof NamingEvent) {
System.out.println(((NamingEvent) event).getServiceName());
System.out.println(((NamingEvent) event).getGroupName());
}
}
@Override
public Executor getExecutor() {
return executorService;
}
};
namingService.subscribe("your_service", "pai-eas", serviceListener);
Instance instance = namingService.selectOneHealthyInstance("your_service", "pai-eas");
System.out.println(instance.getIp());
System.out.println(instance.getPort());
// コンソールの呼び出し情報にある IP アドレスとポートでホストを置き換えます。
String url = String.format("http://%s:%d/api/predict/xxxxxxx", instance.getIp(), instance.getPort());
System.out.println(url);
// TODO: この URL を使用してサービスを呼び出します。
} catch (NacosException e) {
e.printStackTrace();
}
}
}