使用 Google Compute Engine 和 gRPC 构建移动应用

gRPC 框架让移动应用可以和调用本地对象一样直接调用后端服务器上的方法。您可以使用 gRPC 提高您的移动应用带宽效率,并降低应用和 Google Cloud Platform 上运行的后端服务之间的延时。

在 Google Compute Engine 上运行移动后端并使用 gRPC 作为移动应用和后端服务器之间的通信协议具有以下几个优点:

  • 它是将本地或虚拟机上运行的现有服务移动到 Cloud Platform 的最快方法。
  • 与 HTTP/S 相比,带宽效率更高。
  • 可让您完全控制虚拟机和服务器配置。
  • 您可以使用第三方库。
  • 您可以配置自动调节程序调整虚拟机的数量以满足需求。

在 Compute Engine 上运行服务的缺点是需要自行手动维护和更新服务器。如需了解构建移动后端服务的其他方式,请参阅使用 Google Cloud Platform 构建移动应用

本教程将指导您构建一个名为 Stickynotes 的示例移动应用。此示例应用使用 gRPC 连接到在 Compute Engine 上运行的后端服务。

Stickynotes 示例包括前端移动应用和后端服务的代码。在移动应用中,您可以在文本字段输入消息。接着,该应用使用 gRPC 将您的消息发送到后端服务,后者使用 draw2d 将文本消息转换为图像,然后将图像返回到移动应用。最后,移动应用将您的消息显示为黄色背景的图像。

客户端应用是 iOS 版应用,而后端服务以 Go 编写。

目标

在本教程中,您将学习如何完成以下操作:

  • 创建一个使用 gRPC 连接到后端服务的 iOS 移动应用。
  • 在 Compute Engine 上配置并运行 gRPC 后端服务。

费用

本教程使用 Cloud Platform 的可计费组件,包括:

  • Google Compute Engine

您可使用价格计算器根据您的预计使用情况来估算费用。 新用户可能有资格申请免费试用

准备工作

  1. 在 Cloud Console 中,转到项目选择器页面。

    转到项目选择器页面

  2. 选择或创建 Cloud 项目。

  1. 确保您的 Google Cloud 项目已启用结算功能。 了解如何确认您的项目已启用结算功能

执行这些步骤后,请安装以下软件:

  • Git
  • Xcode 7.2 或更高版本
  • Go

    确保 Go 安装目录位于 PATH 变量中,通常是 /usr/local/go/bin

    以您的用户帐号作为所有者安装 Go。如果以 root 方式安装,请在安装 Go 的目录中运行以下命令以更改所有权,将 <username> 替换为您的用户名。

    sudo chown -R <username> go
    
  • Cocoapods

    sudo gem install cocoapods
    
  • Homebrew

    /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    
  • 带 gRPC 插件的 protoc

    curl -fsSL https://goo.gl/getgrpc | bash -
    

克隆示例代码

git clone https://github.com/GoogleCloudPlatform/ios-docs-samples.git

然后导航到 /solutions/stickynoteapi/gRPC 查找此解决方案的示例代码。

在本地运行服务器

/stickynoteapi/gRPC/Go 目录中,运行以下命令:

sh SETUP

您会看到以下输出内容:

0. Ensure that protoc is installed.
/usr/local/bin/protoc
OK
1. Set gopath and search path
2. Get the Go plugin for protoc
3. Run protoc to generate the service API code
4. Get the server and client dependencies
5. Build the server and client
6. Stop any previously-running instances of the server
No matching processes belonging to you were found
7. Start the server
8. Run the client
2016/03/03 15:53:21 OK: message.png
9. Open the image in message.png

此设置还运行本地客户端以使用 “Remember the milk.” 测试服务器,并生成包含该消息的图片。

Remember the Milk.

如需使用命令行客户端根据您自己的消息生成图片,请运行以下命令。

./client "This is a test..."

文件 /solutions/stickynoteapi/gRPC/Go/go/src/server/server.go 包含运行 gRPC 服务器的代码。该代码还规定了一个 StickyNoteServer 结构,其中包含两个元素,一个代表请求,另一个代表响应。

type StickyNoteServer struct{}

var stickyNoteServer StickyNoteServer

main 函数为根级目录规定 gRPC 服务器,该服务器侦听端口 8080 上的流量。由于服务器未指定 IP 地址或网域,因此可以在 Compute Engine 上运行此代码而无需作出任何修改。

func main() {
	var err error
	var lis net.Listener
	var grpcServer *grpc.Server
	if !useSSL {
		lis, err = net.Listen("tcp", ":8080")
		if err != nil {
			log.Fatalf("failed to listen: %v", err)
		}
		grpcServer = grpc.NewServer()
	} else {
		certFile := "ssl.crt"
		keyFile := "ssl.key"
		creds, err := credentials.NewServerTLSFromFile(certFile, keyFile)
		lis, err = net.Listen("tcp", ":443")
		if err != nil {
			log.Fatalf("failed to listen: %v", err)
		}
		grpcServer = grpc.NewServer(grpc.Creds(creds))
	}
	pb.RegisterStickyNoteServer(grpcServer, &stickyNoteServer)
	grpcServer.Serve(lis)
}

Get 函数接收 gRPC 请求中的消息,使用 sticky.go 中定义的函数基于该消息构建图像,然后在 gRPC 响应中返回图像。

func (s *StickyNoteServer) Get(ctx context.Context, r *pb.StickyNoteRequest) (*pb.StickyNoteResponse, error) {
	var sticky Sticky
	sticky.Message = r.Message
	sticky.Centered = false

	resp := &pb.StickyNoteResponse{}
	stickyBytes, err := sticky.DrawPNG(512, 512)
	resp.Image = *stickyBytes

	return resp, err
}

让本地服务器保持运行,以便您可以用它来测试客户端应用。

使用本地服务器运行 iOS 客户端

  1. /stickynoteapi/gRPC/Objective-C 目录中,运行以下命令以安装 BoringSSL、Protobuf 和 gRPC 依赖项。安装过程可能需要几分钟。

    pod install
    

    您会看到以下输出内容:

    Analyzing dependencies
    Fetching podspec for `stickynote` from `stickyapi`
    Downloading dependencies
    Installing BoringSSL (2.0)
    Installing Protobuf (3.0.0-beta-2)
    Installing gRPC (0.12.0)
    Installing stickynote (0.0.1)
    Generating Pods project
    Integrating client project
    
    [!] Please close any current Xcode sessions and use
    `stickynotes.xcworkspace` for this project from now on.
    Sending stats
    Pod installation complete! There is 1 dependency from the Podfile and 4
    total pods installed.
    
  2. 在 Xcode 中打开由 Cocoapods 构建的工作区 stickynotes.xcworkspace

  3. 依次点击产品 > 架构 > stickynotes 来选择正确的方案。

  4. 选择产品 > 运行以构建并启动客户端应用。忽略 Protobuf 和 gRPC 中的警告。

  5. 在文本字段中输入消息,然后点击返回

此时,带有您的消息的黄色便笺图像便显示在文本字段下方。

This is a test...

客户端应用在 StickyNotesViewController.m 文件中设置后端服务的位置。出于测试目的,位置初始设置为 localhost。

static NSString * const kHostAddress = @"localhost";

在文本字段中输入消息后点击返回,将触发以下操作。该操作将消息编码为查询字符串。然后将查询传递给开放的流连接。

- (IBAction)textDidChange:(UITextField *) sender {
  if ([_streamSwitch isOn]) {
    StickyNoteRequest *request = [StickyNoteRequest message];
    request.message = sender.text;
    [_writer writeValue:request];
  }
}

流连接由函数 openStreamingConnection 开启。

- (void) openStreamingConnection {
  _writer = [[GRXBufferedPipe alloc] init];
  _updateCall = [_client RPCToUpdateWithRequestsWriter:_writer
                                          eventHandler:^(BOOL done, StickyNoteResponse *response, NSError *error) {
                                            [self handleStickynoteResponse:response andError:error];
                                          }];
  [_updateCall start];
}

在 Compute Engine 上运行服务器

  1. 转到 Google Cloud Platform Console 中的创建实例页面。

    转到“创建实例”页面

    1. 名称设置为 sticky-grpc
    2. 选择创建

    创建实例

  2. 转到 GCP Console 中的创建防火墙规则页面。

    转到“创建防火墙规则”页面

    1. 名称中,输入 default-allow-grpc
    2. 来源过滤条件中,选择允许来自任意来源的流量 (0.0.0.0./0)
    3. 允许的协议和端口中,输入 tcp:8080
    4. 选择创建

    选择 SSH

  3. 转到 GCP Console 中的查看虚拟机实例页面。

    转到“查看虚拟机实例”页面

    1. 请注意 sticky-grpc 旁边的外部 IP 地址。
    2. 选择 SSH

    选择 SSH

  4. 将 Git 安装到实例。

    sudo apt-get update
    sudo apt-get install git
    
  5. 克隆 Stickynotes 服务器代码。

    git clone https://github.com/GoogleCloudPlatform/ios-docs-samples.git
    
  6. 安装 Go 和 protoc。在 /solutions/stickynoteapi/gRPC/Go/ 目录中,运行以下命令。

    sh INSTALL
    
  7. 加载由 INSTALL 脚本设置的新环境变量。

    source $HOME/.bash_profile
    
  8. 启动实例上的 Stickynotes 服务器。在 /solutions/stickynoteapi/gRPC/Go/ 目录中,运行以下命令。

    sh SETUP
    
  9. 在 Xcode 中,修改 StickyNotesViewController.m 以将 localhost 更改为步骤 2 中 Compute Engine 实例的外部 IP 地址。

    // static NSString \* const kHostAddress = @"localhost";
    static NSString \* const kHostAddress = @"198.51.100.0";
    
  10. 选择文件 > 保存以保存更改。

  11. 依次点击产品 > 架构 > stickynotes 来选择正确的方案。

  12. 选择产品 > 运行以构建并启动客户端应用。

  13. 在文本字段中输入消息,然后点击返回

此时,带有您的消息的黄色便笺图像将取代灰色背景。

Testing on remote server...

清理

为避免因本教程中使用的资源而导致您的 Google Cloud Platform 帐号产生费用,请执行以下操作:

删除项目

若要避免产生费用,最简单的方法是删除您为本教程创建的项目。

如需删除项目,请执行以下操作:

  1. 在 Cloud Console 中,转到管理资源页面。

    转到“管理资源”页面

  2. 在项目列表中,选择要删除的项目,然后点击删除
  3. 在对话框中输入项目 ID,然后点击关闭以删除项目。

删除实例

如需删除 Compute Engine 实例,请运行以下命令:

  1. 在 Cloud Console 中,转到虚拟机实例页面。

    转到“虚拟机实例”页面

  2. 点击您要删除的实例。
  3. 点击删除 以删除实例。

删除默认网络的防火墙规则

如需删除防火墙规则,请执行以下操作:

  1. 在 Cloud Console 中,转到防火墙规则页面。

    转到“防火墙规则”页面

  2. 点击要删除的防火墙规则。
  3. 点击删除 以删除防火墙规则。

后续步骤

此示例演示了通过 gRPC 将移动应用连接到 Compute Engine 上运行的代码的基本过程。为了将此示例扩展到真实应用,请考虑添加以下增强功能:

  • 向服务器添加静态 IP 地址 - 默认情况下,与 Compute Engine 实例关联的外部地址是瞬态的。在正式版应用中,应该为实例附加一个静态 IP 地址。如需了解详情,请参阅配置实例的 IP 地址

  • 添加负载平衡和自动调节功能 - 通过设置负载平衡器和自动调节程序,在需求增长时启动更多实例,并在这些实例之间均匀地路由流量,从而妥善处理流量峰值。如需了解详情,请参阅设置 HTTP(s) 负载平衡自动扩缩实例组

  • 使用其他方案托管后端服务 - Compute Engine 可提供对虚拟机最大限度的控制,但如果采用这种方案,则您需要手动更新和管理实例。如需查看有关在 Cloud Platform 上托管移动后端服务的其他方式的讨论,请参阅使用 Google Cloud Platform 构建移动应用