通过预热 Amazon WorkSpaces 提升用户操作体验

阅读数:2 2020 年 4 月 19 日 17:16

通过预热 Amazon WorkSpaces 提升用户操作体验

1. 前言

Amazon WorkSpaces 提供了灵活的付费方式,使得用户可以按月或按小时付费。按月计费适合需要全天使用 Amazon WorkSpaces 或将其用作主要桌面的工作人员。对于并非需要长时间运行的工作场景,比如兼职工作人员、临时性工作分担、频繁出差的人员、短期项目、在线培训和教育等,使用按小时付费是一种能够很好节约成本的方式。Amazon WorkSpaces 计费模式能够非常灵活的进行选择和切换,只需要通过配置相应实例的运行模式(Running Mode)即可。Amazon WorkSpaces 提供两种运行模式以适配不同的计价模式:

  • AlwaysOn — 按月计费,WorkSpace 将始终处于运行状态,用户可随时访问。
  • AutoStop — 按小时计费,WorkSpace 将在指定的不活动时间(小时,最少为 1 最大为 48) 之后自动停止,并在用户下次登录时恢复。

Amazon WorkSpaces 在自动停止后,当用户重新连接到已停止的 WorkSpace 时,它会恢复到其上次停止时的状态,这个恢复过程通常在 90 秒内。对于大多数用户来说,WorkSpace 客户端等待 90 秒时间才能进入是难以接受的,因此我们可以考虑通过“预热”方式提前为用户启动恢复过程,让等待时间变得更短或直接能“立即访问”,这样将会大大提高用户的操作体验。

本文按照用户的操作需要将“预热”操作分为两种模式,即按需预热和定时预热。以下将分别介绍两种预热模式的实现方式。

2. 按需预热

2.1 架构说明

按需预热模式,即终端用户对于 WorkSpaces 可访问时间有比较明确的预期,可以通过自助提交请求来实现预热,适用于如出差、定时会议或启动培训计划等场景。

按需预热的本质是接收到用户请求后,生成一个定时任务,此任务可在用户请求的时间点之前完成 WorkSpace 的恢复启动操作。定时任务通常可以使用 CloudWatch 来实现,但默认情况下 CloudWatch 规则上限为 100 条,虽然该上限限制可以通过提交后台申请来进行调整,但为所有请求各自创建一个 CloudWatch 定时规则来执行业务逻辑并不是一个非常合适的方式。因此,我们可以通过使用一个固定频率执行的 CloudWatch 规则执行 Lambda 来读取持久化保存的按需请求数据来触发预热操作。

本文使用 DynamoDB 保存按需预热请求,整体架构如下:

通过预热 Amazon WorkSpaces 提升用户操作体验

2.2 配置 IAM 及 DynamoDB

2.2.1 DynamoDB 配置

在 DynamoDB 里中创建一个表为 Jobs 的表,用于保存按需预热请求。Jobs 表使用 id 作为主键,并使用 on_at 字段作为二级索引。DynamoDB 将保存来自用户的按需预热请求,完整字段定义如下:

col 1 col 2
字段名 用途
id 任务唯一编号(自动生成),主键
username WorkSpaces 用户名
spaceid WorkSpaces ID(可选)
on_at 计划使用时间,DynamoDB 将以 ISO 格式保存,形如 2020-03-03T12:12:12

通过预热 Amazon WorkSpaces 提升用户操作体验

2.2.2 IAM 策略配置

在 IAM 中为按需预热 Lambda 函数配置相应角色 OnDemandRequestRole,角色对应的策略定义如下:

Java

复制代码
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "state1",
"Effect": "Allow",
"Action": [
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Resource": "arn:<partition>:dynamodb:<region>:<account-id>:table/Jobs"
},
{
"Sid": "state2",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:<partition>:logs:<region>:<account-id>:log-group:/aws/lambda/OnDemandRequest:*"
},
{
"Sid": "state3",
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:<partition>:logs:<region>:<account-id>:*"
}
]
}

通过预热 Amazon WorkSpaces 提升用户操作体验

2.3 创建按需请求 Lambda

接收请求并创建定时任务的 Lambda 代码(OnDemandRequest)如下:

Java

复制代码
from datetime import datetime
import json
import uuid
import boto3
def lambda_handler(event, context):
"""
Lambda function export to API Gateway to recieve a json formatted post job.
JSON parameters description:
'username': The username of WorkSpace. Required.
'spaceid': The WorkSpace ID request to warm-up.
Optional. If not assign, will warm up all WorkSpace of the user.
'on_at': The will to be used time of the WorkSpace. Required.
For example:
{
"username": "xxxxx",
"spaceid": "ws-1234abcd",
"on_at": "2020-03-03 12:12:12"
}
"""
print('Recieved on demand warm-up request - [%s].' % json.dumps(event))
jobID = str(uuid.uuid1())
on_at = datetime.strptime(event['on_at'], '%Y-%m-%d %H:%M:%S').isoformat()
try:
dynamodb = boto3.resource('dynamodb', region_name='cn-northwest-1')
table = dynamodb.Table('Jobs')
table.put_item(
Item={
'id': jobID,
'username': event['username'],
'spaceid': event.get('spaceid', '-'),
'on_at': on_at
}
)
print('On demand warm-up request has created with jobID [%s].' % jobID)
return {
'statusCode': 200,
'body': {
'id': jobID
}
}
except Exception as ex:
return {
'statusCode': 500,
'body': {
'error': ex
}
}

在 Lambda 控制台中使用 OnDemandRequestRole 角色将 OnDemandRequest 部署为基于 Python3.7 的 Lambda 函数。

通过预热 Amazon WorkSpaces 提升用户操作体验

2.4 配置 API Gateway

配置 API Gateway,新建 REST API 以用于接收 HTTP Post 请求并调用 OnDemandRequest Lambda。

通过预热 Amazon WorkSpaces 提升用户操作体验

创建 POST 操作方法调用之前部署的 OnDemandRequest Lambda 函数

通过预热 Amazon WorkSpaces 提升用户操作体验

注意:若使用宁夏或北京区域的 API Gateway,需要提供 ISP 备案或配置方法请求的身份验证为 AWS_IAM。

通过预热 Amazon WorkSpaces 提升用户操作体验

部署 API,并记录相应 Endpoint。

通过预热 Amazon WorkSpaces 提升用户操作体验

2.5 配置 CloudWatch 定时任务

配置 CloudWatch,创建固定频率规则用于执行定时任务检查 DynamoDB 是否有需要执行的任务。

通过预热 Amazon WorkSpaces 提升用户操作体验

2.6 使用 awscurl 测试

现在我们可以通过 Endpoint 提交按需预热请求。使用基于 AWS_IAM 方式进行授权的 Endpoint,需要在对调用请求进行预签名。我们可以使用 awscurl 工具来执行预签名的 URL 的调用。

awscurl 工具可以通过以下命令来安装和使用。

Java

复制代码
pip install awscurl
export AWS_ACCESS_KEY_ID="<your-account-access-key-id>"
export AWS_SECRET_ACCESS_KEY="<your-account-secret-access-key>"
awscurl --region <your-api-region> "<your-api-endpoint>" -X POST -d "{\"username\": \"<workspace-username>\", \"spaceid\": \"<workspace-id> \", \"on_at\": \"<request-on-datetime, format as: 2020-03-03 12:12:12>\"}"

通过预热 Amazon WorkSpaces 提升用户操作体验

按需操作接收的 Post 格式如下:

Java

复制代码
{
"username": "xxxxx",
"spaceid": "ws-1234abcd",
"on_at": "2020-03-03 12:12:12"
}

通过预热 Amazon WorkSpaces 提升用户操作体验
打开 WorkSpaces 控制台,可以看到该用户所对应的 WorkSpaces 在指定时间前 180 秒时已将状态从 STOPPED 切换为 STARTING。

3. 定时预热

3.1 架构说明

定时预热相对与按需预热的实现相对简单,可以通过配置 CloudWatch 规则执行定时 Lambda 任务来启动 WorkSpaces 实例,本文中的定时任务未对待启动的 Workspaces 进行过滤,实际使用过程中可以通过额外的配置(如 S3 文件、RDS、DynamoDB 等持久化服务)来自定义具体任务执行的条件。

通过预热 Amazon WorkSpaces 提升用户操作体验

定时预热整体架构如下:

3.2 配置 IAM

在 IAM 中为定时预热 Lambda 函数配置相应角色 OnScheduleScannerRole,角色对应的策略定义如下:

Java

复制代码
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "state1",
"Effect": "Allow",
"Action": [
"workspaces:StartWorkspaces",
"workspaces:DescribeWorkspaces"
],
"Resource": "arn:<aws-partitionname>:workspaces:<region>:<account-id>:workspace/*"
},
{
"Sid": "state2",
"Effect": "Allow",
"Action": [
"workspaces:DescribeWorkspaceDirectories"
],
"Resource": " arn:<aws-partitionname>:workspaces:<region>:<account-id>:*"
}
]
}

通过预热 Amazon WorkSpaces 提升用户操作体验

3.3 创建定时预热 Lambda

定时预热 Lambda 代码(OnScheduleScanner) 如下:

Java

复制代码
from datetime import datetime
import boto3
def lambda_handler(event, context):
"""
Lambda function used with CloudWatch Rule Event to execute scheduled WorkSpaces warm-up job.
Can pass in a DirectoryId as parameter, for example:
event['directory'] = 'd-123456'
if no DirectoryId specified, the job will scan all available Directoies and warm-up WorkSpaces.
"""
print('Start scheduled warm-up at %s.' % datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
directory = event.get('directory', None)
try:
directories = []
workspaces = []
client = boto3.client('workspaces')
check = {} if directory is None else {'DirectoryIds': [directory]}
resp = client.describe_workspace_directories(**check)
while resp:
directories += resp['Directories']
resp = client.describe_workspace_directories(
**check,
NextToken=resp['NextToken']
) if 'NextToken' in resp else None
for dir in directories:
dir_id = dir['DirectoryId']
resp = client.describe_workspaces(DirectoryId=dir_id)
while resp:
workspaces += resp['Workspaces']
resp = client.describe_workspaces(
DirectoryId=dir_id, NextToken=resp['NextToken']
) if 'NextToken' in resp else None
for workspace in workspaces:
if workspace['State'] == 'STOPPED':
client.start_workspaces(
StartWorkspaceRequests=[{
'WorkspaceId': workspace['WorkspaceId']
}]
)
print('Starting WorkSpace for id - [%s].' % workspace['WorkspaceId'])
except Exception as ex:
print('Error to run scheduled warm-up job - [%s].' % ex)

在 Lambda 控制台中使用 OnScheduleScannerRole 角色将 OnScheduleScanner 部署为基于 Python3.7 的 Lambda 函数。

通过预热 Amazon WorkSpaces 提升用户操作体验
在 Lambda 控制台中使用 OnScheduleScannerRole 角色将 OnScheduleScanner 部署为基于 Python3.7 的 Lambda 函数。

3.4 配置 CloudWatch 定时规则

在 CloudWatch 中配置一个定时任务并选择 OnScheduleScanner 为目标。

通过预热 Amazon WorkSpaces 提升用户操作体验

打开 WorkSpaces 控制台,可以看到在定时任务指定的时间点之后,所有状态为 STOPPED 的实例状态已改变。

通过预热 Amazon WorkSpaces 提升用户操作体验

附录

本文中代码及 IAM 策略配置参数如下:

  • :资源所处分区。对于标准 AWS 区域,分区是 aws。如果资源位于其他分区,则分区是 aws-partitionname。例如,位于 中国(北京) 区域的资源的分区为 aws-cn。
  • :区域标识。如 cn-northwest-1。
  • :资源的 AWS 账户 ID(不含连字符)。如 123456789012。

作者介绍:陈昊,AWS 合作伙伴解决方案架构师,有将近 20 年的 IT 从业经验,在企业应用开发、架构设计及建设方面具有丰富的实践经验。目前主要负责 AWS (中国) 合作伙伴的方案架构咨询和设计工作,致力于 AWS 云服务在国内的应用推广以及帮助合作伙伴构建更高效的 AWS 云服务解决方案。

本文转载自 AWS 技术博客。

原文链接: https://amazonaws-china.com/cn/blogs/china/enhance-user-experience-by-preheating-amazon-workspaces/

评论

发布