如何在 Azure Spring Apps 中使用 gRPC。

注意

基本、标准和企业计划将从 2025 年 3 月中旬开始弃用,停用期为 3 年。 建议转换到 Azure 容器应用。 有关详细信息,请参阅 Azure Spring Apps 停用公告

标准消耗和专用计划将于 2024 年 9 月 30 日开始弃用,并在六个月后完全关闭。 建议转换到 Azure 容器应用。

本文演示如何在 Azure Spring Apps 中使用 gRPC。

在本文中,你将修改并重新部署 Spring Boot Pet Clinic 示例应用程序。 在本地环境中,通过修改 customers-service 微服务创建 gRPC 服务,将修改后的示例部署到 Azure Spring Apps,然后使用 grpcurl 命令通过调用 gRPC 方法来测试服务。

先决条件

分配公共终结点

为便于测试,请分配公共终结点。 公共终结点在命令中 grpcurl 用作主机名。 有关详细信息,请参阅fullstorydev/grpcurl

使用以下命令分配公共终结点。 请务必将占位符替换为满足先决条件时使用的资源组名称、服务实例名称和应用名称。

az spring app update \
    --resource-group <resource-group-name> \
    --service <Azure-Spring-Apps-instance-name> \
    --name <app-name> \
    --assign-public-endpoint true

还可以使用 Azure 门户来分配公共终结点。 有关详细信息,请参阅将 Azure Spring Apps 上的应用程序从公用网络公开到 Internet

将现有服务修改为 gRPC 服务

在将服务更改为 gRPC 服务器之前,请查看已部署的 PetClinic 实例应用程序的“所有者”页,检查当前的宠物所有者数据。 还可以通过添加到 /owners URL 路径来列出所有所有者,可以从Azure 门户 customers-service 页的“概述”页获取该路径。

使用以下步骤更改为 customers-service gRPC 服务器:

  1. spring-petclinic-customers-service 文件夹中找到 pom.xml

  2. pom.xml 文件中,删除定义 spring-boot-starter-web 依赖项的以下元素:

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    

    如果不删除此依赖项,应用程序将同时启动 Web 服务器和 gRPC 服务器。 然后,Azure Spring Apps 会将基本/标准计划的服务器端口重写为 1025,从而阻止使用静态服务器地址正确路由 gRPC。

  3. 将以下元素添加到 pom.xml 文件。 这些元素定义 gRPC 所需的依赖项和生成插件。

    <dependencies>
        <!-- For both gRPC server and client -->
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-spring-boot-starter</artifactId>
            <version>2.5.1.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>io.grpc</groupId>
                    <artifactId>grpc-netty-shaded</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- For the gRPC server (only) -->
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-server-spring-boot-starter</artifactId>
            <version>2.5.1.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>io.grpc</groupId>
                    <artifactId>grpc-netty-shaded</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-client-spring-boot-autoconfigure</artifactId>
            <version>2.5.1.RELEASE</version>
            <type>pom</type>
        </dependency>
    </dependencies>
    <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.6.1</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.6.1</version>
                <configuration>
                    <protocArtifact>
                        com.google.protobuf:protoc:3.3.0:exe:${os.detected.lassifier}
                    </protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>
                        io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}
                    </pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    

生成 gRPC 服务

使用以下步骤创建并运行定义消息类型和 RPC 接口方法的 .proto 文件:

  1. 在源代码文件夹中创建一个扩展名为 .proto 的新文件,其中包含以下内容:

    syntax = "proto3";
    option java_multiple_files = true;
    package org.springframework.samples.petclinic.customers.grpc;
    import "google/protobuf/empty.proto";
    
    message OwnerRequest {
        int32 ownerId = 1;
    }
    
    message PetRequest {
        int32 petId = 1;
    }
    
    message OwnerResponse {
        int32 id = 1;
        string firstName = 2;
        string lastName = 3;
        string address = 4;
        string city = 5;
        string telephone = 6;
        repeated PetResponse pets = 7;
    }
    
    message PetResponse {
        int32 id = 1;
        string name = 2;
        string birthDate = 3;
        PetType type = 4;
        OwnerResponse owner = 5;
    }
    
    message PetType {
        int32 id = 1;
        string name = 2;
    }
    
    message PetTypes {
        repeated PetType ele = 1;
    }
    
    message Owners {
        repeated OwnerResponse ele = 1;
    }
    
    service CustomersService {
        rpc createOwner(OwnerResponse) returns (OwnerResponse);
        rpc findOwner(OwnerRequest) returns (OwnerResponse);
        rpc findAll(google.protobuf.Empty) returns (Owners);
        rpc updateOwner(OwnerResponse) returns (google.protobuf.Empty);
        rpc getPetTypes(google.protobuf.Empty) returns (PetTypes);
        rpc createPet(PetResponse) returns (PetResponse);
        rpc updatePet(PetResponse) returns (google.protobuf.Empty);
        rpc findPet(PetRequest) returns (PetResponse);
    }
    
  2. 请使用以下命令生成 gRPC 服务文件:

    mvn package
    

    可以使用 .proto 文件中定义的 RPC 方法实现 gRPC 服务。 在示例应用程序中,生成的文件包括 gRPC 插件定义的 CustomersServiceGrpc.javaproto

实现 gRPC 服务

在开发环境中,为项目创建一个 Java 类文件,其中包含实现 .proto 文件中定义的 RPC 方法的以下内容。 使用注释 @GrpcService 扩展自动生成的 gRPC 服务基类,以实现其方法。 下面的示例演示一些方法的实现:

@GrpcService
@Slf4j
public class CustomersServiceImpl extends CustomersServiceGrpc.CustomersServiceImplBase {
    @Autowired
    private OwnerRepository ownerRepository;

    @Autowired
    private PetRepository petRepository;

    @Override
    public void createOwner(OwnerResponse request, StreamObserver<OwnerResponse> responseObserver) {
        Owner owner = new Owner();
        BeanUtils.copyProperties(request, owner);
        ownerRepository.save(owner);

        responseObserver.onNext(request);
        responseObserver.onCompleted();
    }
}

配置服务器端口

接下来,将基本/标准计划的服务器端口配置为 1025,以便流入量规则正常工作。 将以下行添加到 spring-petclinic-customers-service/src/main/resources 文件夹中的 application.properties 文件。

grpc.server.port=1025

生成服务 JAR 文件

使用以下命令生成 gRPC 服务器 JAR 文件:

mvn package

customers-service 的修改现已完成,现在已经是 gRPC 服务。

将应用程序部署到 Azure Spring Apps

现在可以配置服务器并部署应用程序。

使用以下命令将新生成的 JAR 文件部署到 Azure Spring Apps 实例。

注意

Microsoft 建议使用最安全的可用身份验证流。 本过程中介绍的身份验证流程(例如数据库、缓存、消息传送或 AI 服务)需要非常高的信任度,并携带其他流中不存在的风险。 仅当更安全的选项(例如无密码连接或无密钥连接的托管标识)不可行时,才使用此流。 对于本地计算机操作,首选无密码连接或无密钥连接的用户标识。

az spring app deploy \
    --name ${CUSTOMERS_SERVICE} \
    --artifact-path ${CUSTOMERS_SERVICE_JAR} \
    --jvm-options='-Xms2048m -Xmx2048m -Dspring.profiles.active=mysql' \
    --env MYSQL_SERVER_FULL_NAME=${MYSQL_SERVER_FULL_NAME} \
          MYSQL_DATABASE_NAME=${MYSQL_DATABASE_NAME} \
          MYSQL_SERVER_ADMIN_LOGIN_NAME=${MYSQL_SERVER_ADMIN_LOGIN_NAME} \
          MYSQL_SERVER_ADMIN_PASSWORD=${MYSQL_SERVER_ADMIN_PASSWORD}

部署可能需要几分钟才能完成。

现在,应用程序已部署在 Azure Spring Apps 中,请从 Azure Spring Apps 服务实例外部调用 gRPC 服务。 如前所述,测试 customers-service 终结点以尝试通过将 /owners 添加到 URL 路径来列出所有宠物所有者。 这一次,测试按预期失败,因为无法使用 HTTP 协议访问 gRPC 服务。

设置入口配置

将后端协议设置为使用 gRPC,以便可以使用 grpcurl 命令来测试 gRPC 服务器。 更新应用程序的入口设置。 有关详细信息,请参阅在 Azure Spring Apps 中自定义入口配置

从本地环境调用示例应用程序

可以使用 grpcurl 来测试 gRPC 服务器。 来自 Azure Spring Apps 外部的 gRPC 调用支持的唯一端口是端口 443。 流量会自动路由到后端的端口 1025。

使用以下 grpcurl 命令通过列出所有宠物所有者来检查 gRPC 服务器。

grpcurl <service-instance-name>-customers-service.microservices.azure.cn:443 list
grpcurl <service-instance-name>-customers-service.microservices.azure.cn:443 org.springframework.samples.petclinic.customers.grpc.CustomersService.findAll
grpcurl -d "{\"ownerId\":7}" <service-instance-name>-customers-service.microservices.azure.cn:443 org.springframework.samples.petclinic.customers.grpc.CustomersService.findOwner

常见问题

  • 如何使用测试终结点?

    使用以下 curl 和 HTTP 命令来使用 gRPC 服务器的测试终结点:

    echo -n '0000000000' | xxd -r -p - frame.bin
    curl -v --insecure --raw -X POST -H "Content-Type: application/grpc" -H "TE: trailers" --data-binary @frame.bin <test-endpoint/org.   springframework.samples.petclinic.customers.grpc.CustomersService/findAll
    

    有关详细信息,请参阅在 Azure Spring Apps 中设置过渡环境中的查看应用和部署部分。

后续步骤