# aws lambda使用_使用AWS Lambda，无服务器框架和Go的按需WebSockets

aws lambda使用

Lambda functions and WebSockets can be seen as concepts difficult to reconcile. Lambdas are ephemeral by nature. They appear when invoked and then disappear sometime after they have finished working. WebSockets, on the contrary, maintain stable, long-living connections between one server and many clients.

Lambda函数WebSockets可以视为难以协调的概念。 Lambdas是短暂的。 它们在被调用时出现，然后在完成工作后的某个时间消失。 相反，WebSocket可以在一台服务器和许多客户端之间维持稳定的长期连接。

The AWS APIGateway offers the possibility to bring these two things together, combining the advantages of the Lambda on-demand model with the power of WebSockets’ real-time bidirectional communication.

AWS APIGateway提供了将这两件事结合在一起的可能性，将Lambda按需模型的优势与WebSockets实时双向通信的强大功能相结合。

In this article, we describe how to implement a WebSocket server using AWS API Gateway and Lambda functions. We will use the Serveless framework to set up the infrastructure and deploy the solution and Go as the programming language.

Serverless has been chosen because it is an easy and well-documented way to define infrastructure as code. Go has been chosen because it guarantees it has the potential to optimise Lambda costs and provide low cold-start latency, an important feature for the implementation of such a model.

# 一个简单的WebSocket服务器以及客户端可以做什么 (A Simple WebSocket Server and What Clients Can Do)

To make things concrete, we are going to implement a simple WebSocket server. The goal of this server is to broadcast, as an echo, each message received from one client to all connected clients.

As we can see from the diagram, each client connects to the server, sends messages to be broadcast by the server to all connected clients, and, in the end, disconnects from the server.

In other words, a client can trigger three types of events:

• connect to the server

连接到服务器

• disconnect from the server

服务器断开连接

• send a message to the server

服务器发送消息

The server, on the other side, has to react appropriately to these events. The way it reacts is codified using Lambda function(s).

# 在云中设置组件 (Setup of the Components in the Cloud)

Now that we understand what the clients can do and what the server is called to do, we can start building the infrastructure in the cloud. As we said, we are going to use the Serverless framework to do this.

The configuration of the API Gateway and the Lambda function(s) is pretty simple. We start linking the Lambda function(s) to the types of event they are asked to manage. This is the Serveless yaml configuration that defines such links.

API网关和Lambda函数的配置非常简单。 我们开始将Lambda函数链接到要求它们管理的事件类型。 这是Serveless yaml配置，它定义了此类链接。

In the above snippet, we define a service, a provider, and a Lambda function to be executed when the WebSocket events reach the server. The route property links an event to its function, meaning that when the event occurs, the function is triggered. The handler property points to the code that the Lambda function will execute, which in this case is bin/handleRequest, a Go compiled executable.

In this example, the same function (implemented by bin/handleRequest) manages the connect, disconnect, and default events. We could have defined different functions to manage different events, but we opted for a single function for the sake of simplicity and to allow some forms of optimisation which we will discuss later.

Let’s go back to the events. We know what connect and disconnect are. But what is default?

When a client sends a message to the server, the meaning (i.e., the semantic) of the message is embedded in the content of its payload. For instance, if the message carries a JSON payload, then the JSON could have a property action to identify the logic the message is supposed to trigger. We could then configure AWS API Gateway to react with different Lambda functions to messages with different semantics. In other words, we could attach different Lambda functions to the different values of the action field (if we follow the example above). If no match is found, then the system reverts back to the default event and the Lambda function linked to it.

In our case we use the same Lambda function for all types of events, so no custom event is defined and only the $default event is configured. 在我们的案例中，我们对所有类型的事件使用相同的Lambda函数，因此未定义custom事件，仅配置了$default事件。

# 执行结构 (Go Implementation Structure)

The structure of the Go implementation of a Lambda function used by an API Gateway WebSocket service is also pretty simple.

API网关WebSocket服务使用的Lambda函数Go实现的结构也非常简单。

We need to define a main function in the main package. The main function simply calls lambda.Start(handleRequest).

Since in our case one single Lambda function manages all types of events, we need to find the way to recognise the type of event and implement some switch logic based on it. handleRequest knows which type of event it is dealing with by querying the RouteKey field of the RequestContext of the event struct passed in as a parameter, which is of type APIGatewayWebsocketProxyRequest. Based on the type of event, the appropriate logic is executed.

# $connect，$ disconnect和connectionID ($connect,$disconnect and connectionIDs)

A WebSocket server is able to send targeted messages to specific clients. This means that each connected client needs to have a unique connectionID and that the server needs to keep track of such connectionIDs.

WebSocket服务器能够将目标消息发送到特定客户端。 这意味着每个连接的客户端都需要具有唯一的connectionID ，并且服务器需要跟踪此类connectionID

The API Gateway is responsible to assign a unique connectionID to each client when they connect to the server. That connectionID is passed as a parameter in each invocation of the handleRequest function.

The WebSocket server needs to have some form of store for the active connectionIDs. When a $connect event is received, the connectionID is added to the store. When a $disconnect event occurs, the connectionID is removed from the store.

# 相同的Lambda函数可以满足多少个请求 (How Many Requests Can Be Served by the Same Lambda Function)

A Lambda function is ephemeral but not too ephemeral. The same instantiation of a Lambda function can serve more than one request. Let’s examine few different cases.

Lambda函数是短暂的，但不是短暂的。 Lambda函数的相同实例可以服务多个请求。 让我们研究几种不同的情况。

## 相同Lambda函数处理的顺序请求 (Sequential requests served by the same Lambda function)

Some requests are sent sequentially to the same Lambda endpoint. The Lambda function is fast and completes the execution of a request before the next one comes in. In this case, we can expect only one instance of Lambda function serving all the requests. (This can be checked simply logging when the global variables are set and verifying that this happens only once.)

## 两个后续请求之间的空闲时间长 (Long idle time between two subsequent requests)

On the other hand, if we leave the Lambda function idle for a too long period, then the Lambda function is eventually terminated. When the next request arrives, a new Lambda function is created to execute the new request. Again, this can be checked by logging the creation of the global variables.

## 并发请求 (Concurrent requests)

The last case is that of concurrent requests. A request is still being processed by a Lambda function instance when the next one comes in. In this case, another instance of Lambda function is spun off since, as per AWS Lambda documentation, “a single instance of your Lambda function will never handle multiple events simultaneously”. This can be tested using the Sleep capability of the echo function.

It is important to be aware of such behaviours since this gives us the possibility to implement some optimisations, like the caching of database connections. On the other hand, we need to be cautious when using such techniques since many details are not documented, e.g., the time a Lambda function can remain idle before being terminated, and we cannot blindly count on them in our logic.

# 为什么去？ (Why Go?)

We have seen that one Lambda function can serve only one request at a time. So we cannot use the power of goroutines to process more requests concurrently. Managing the concurrency among different requests is the job of API Gateway and Lambda.

Nonetheless, we can still leverage Go concurrency within the process of a single request, if this makes sense. And in many cases it can make sense.

Let’s consider the above example, where the process of a single request requires different I/O operations, e.g., call a REST API, access a DB, do something with storage. In this case, we can make good use of Go by executing concurrently all I/O operations, reducing thus the total time of Lambda processing, minimising the response time, and potentially optimising costs, considering that Lambda are priced also by processing time.

Go, being a compiled language, is also a good choice if we want to have efficient use of memory. And memory is the other factor that influences the cost of executing Lambda functions.

Finally, Go seems also a good choice if we want to have a low cold-start latency, i.e., the time required to start a Lambda function which does not yet have an execution context, even if benchmarks for this aspect vary.

# 构建，部署和测试 (Build, Deploy, and Test)

Finally, we need to build, deploy, and test our WebSocket server. The Serverless framework template guides us in these steps, which anyways are pretty straightforward.

For build we need to run the following command:

env GOOS=linux go build -ldflags="-s-w" -o ./bin/handleRequest ./handleRequest

env GOOS=linux go build -ldflags="-sw" -o ./bin/handleRequest ./handleRequest

Once the build is complete, we can deploy with the following command:

sls deploy

sls deploy

In the deploy command, we can specify environment variable values in case we use them in the implementation, e.g., to pass db connection strings.

To manually test the server functionalities, we use wscat to launch an interactive command line base session via the following command:

wscat -c wss://urlOfTheServer

wscat -c wss://urlOfTheServer

From the prompt, we can type any message and press enter to send a message to the server.

# 结论 (Conclusions)

We have gone through the steps required to build a WebSocket server based on AWS API Gateway and AWS Lambda functions. We have used Serverless for the setup of the cloud configuration and the deployment, and Go to program the logic.

The good news is that this is a relatively easy way to build a WebSocket server available on demand, as per Serverless philosophy.

We have now a powerful additional tool to address use cases where we want to provide rich, interactive, many-to-many platforms without incurring the complexity and costs involved in setting up and manage dedicated servers or containerised solutions.

You can find all the code of the example on GitHub.

aws lambda使用

• 0
点赞
• 0
评论
• 1
收藏
• 一键三连
• 扫一扫，分享海报

02-28

04-02 1万+
05-01 2万+
10-16 2859
04-24 133
04-14 624
01-13 2338
02-05 8525
11-10