Serverless在游戏、电商行业的一个运用场景示例

本文涉及的产品
函数计算FC,每月15万CU 3个月
Serverless 应用引擎免费试用套餐包,4320000 CU,有效期3个月
简介: Serverless 是一种架构理念,具有自己的独特的优势和适用场景。本文以使用阿里云函数计算为例,构建一个简单具体的microservice为例,看看这种架构是如何达到快速开发和节约运维成本的。

Serverless 是一种架构理念,具有自己的独特的优势和适用场景。本文以使用阿里云函数计算为例,构建一个简单具体的microservice为例,看看这种架构是如何达到快速开发和节约运维成本的。

应用场景1

某游戏公司刚开发完一个新的游戏,想要进行一些封闭测试,他们需要一个管理激活码的service来邀请有激活码的玩家来参与封闭测试,同时可能对积极参与封闭测试的玩家,等正式开服后,给予一定的礼包券码

应用场景2

某垂直领域的电商,刚刚起步,流量不是特别大,但发展势头不错。他们需要一个管理优惠码的service

针对上面所说的两个场景,无论是优惠码,激活码等相关码的管理,一般有如下四个:

  • 生成码
  • 使用码
  • 验证码
  • 删除码

传统方案

用户自己去架设服务器,配置数据库,再编写对应的服务,再配备相应的运维人员,总之,不管是硬件成本还是人力成本都不少。

serverless 方案

在本文中,我们运用阿里云API Gateway + 函数计算 + 表格存储(OTS),就能快速搭建这个服务,API Gateway 会自动 scale 去应对请求流量,同样函数计算也会根据流量自动 scale。开发方面,只需要实现好对应的逻辑函数即可。运维方面,省去了管理密匙、打安全补丁等工作,因为用户根本没有需要维护的机器。整个解决方案如下图:

image

从上图我们可以看出,主要有两个步骤:

  1. 函数计算作为 API 网关后端服务, 具体的教程可以参考官方教程函数计算获取临时token
  2. 函数计算结合ots实现具体的逻辑,本文主要讲解这个过程, 并给出具体的代码。

具体步骤

1, 创建一个ots实例,并在实例中创建一张表;在本例中,是在华东2 region创建了code-ots实例,并在该实例中创建了一张表code, 主键是STRING类型

image
image

2, 创建对应的service,service下面创建4个函数,分别为gen_code, del_code, query_code, use_code, 具体的代码可以在本文最后附件下载,由于函数要访问ots,这边需要配置service可以读写ots的权限,相关授权教程可以参考函数计算实现流式处理大文件中的具体步骤第2步, 本文最后配置如下图,从下图可知,我们创建的service的服务角色是fc-ots-rw,该角色拥有对ots读写的权限。

image
image

具体function

1 生成码
  • 配置event
{
    "num":1000,
    "start period":"2017-12-22 00:00:00",
    "end period":"2017-12-28 00:00:00",
}

通过这个配置的event,设置的目标是产生1000个码, 码的有效期在2017-12-22 00:00:002017-12-28 00:00:00,默认产生的状态都是UNACTIVED,未激活的

  • code
# -*- coding: utf-8 -*-
import uuid
import json
import time
from tablestore import *
from tablestore.retry import WriteRetryPolicy
  
table_name = 'code'  # 具体的table
ots_name = 'code-ots'  # ots 实例
BATCH_NUM =  200

def batch_write_row(client, start, end, num):
    put_row_items = []
    for i in range(0, num):
        uid_str = str(uuid.uuid1())
        primary_key = [('uuid', uid_str)]
        attribute_columns = [('start', start), ('end', end), ('status', 'UNACTIVED')]
        row = Row(primary_key, attribute_columns)
        condition = Condition(RowExistenceExpectation.EXPECT_NOT_EXIST)
        item = PutRowItem(row, condition)
        put_row_items.append(item)

    request = BatchWriteRowRequest()
    request.add(TableInBatchWriteRowItem(table_name, put_row_items))
    result = client.batch_write_row(request)

    succ, fail = result.get_put()
    print ('check input table\'s put results: is_all_succeed={0}; succ_num={1}; \
            fail_um={2}'.format(result.is_all_succeed(), len(succ), len(fail)))
    
    for item in fail:
        print ('Put failed, error code: %s, error message: %s' % (item.error_code, item.error_message))
             
def upload_ots(context, num, start, end):
    endpoint = 'https://{}.cn-shanghai.ots-internal.aliyuncs.com'.format(ots_name)
    creds = context.credentials
    client = OTSClient(endpoint, creds.accessKeyId,  creds.accessKeySecret, ots_name, 
            sts_token = creds.securityToken, retry_policy = WriteRetryPolicy())
    
    while num > 0:
        w_num = num
        if num > BATCH_NUM:
            w_num = BATCH_NUM
        batch_write_row(client, start, end, w_num)
        num = num - w_num
            
def handler(event, context):
    evt = json.loads(event)
    num = int(evt['num'])
    start = evt['start period']
    end = evt['end period']
    start_t = time.mktime(time.strptime(start, "%Y-%m-%d %H:%M:%S"))
    end_t = time.mktime(time.strptime(end, "%Y-%m-%d %H:%M:%S"))
    print uuid.uuid1(), type(uuid.uuid1())
    upload_ots(context, num, start_t, end_t)
    return "ok"
2 使用码
  • 配置event
{
   "uuid":"254804e8-e707-11e7-9c21-0242ac110004"
}

假设使用码254804e8-e707-11e7-9c21-0242ac110004,只有表中存在这个码并且这个码是UNACTIVED才返回SUCCESS,并且把该码的状态设置为ACTIVED。其他情况,比如不存在这个码,或者是存在这个码但是已经被激活使用过,都返回FAIL

  • code
# -*- coding: utf-8 -*-
from tablestore import *
from tablestore.retry import WriteRetryPolicy
import json

table_name = 'code'
ots_name = 'code-ots'

def update_row(client, uuid):
    primary_key = [('uuid',uuid)]
    update_of_attribute_columns = {
        'PUT' : [('status','ACTIVED')],
    }
    row = Row(primary_key, update_of_attribute_columns)
    condition = Condition(RowExistenceExpectation.EXPECT_EXIST, SingleColumnCondition("status", "UNACTIVED", ComparatorType.EQUAL)) 
    try:
        consumed, return_row = client.update_row(table_name, row, condition) 
        print ('Update succeed, consume %s write cu.' % consumed.write)
    except Exception as e:
        return 'FAILED'
    return 'SUCCEED'
      
def handler(event, context):
    endpoint = 'https://{}.cn-shanghai.ots-internal.aliyuncs.com'.format(ots_name)
    creds = context.credentials
    client = OTSClient(endpoint, creds.accessKeyId,  creds.accessKeySecret, ots_name, 
            sts_token = creds.securityToken, retry_policy = WriteRetryPolicy())
    evt = json.loads(event)
    uuid = str(evt['uuid'])
    return update_row(client, uuid)
3 查询码
  • 配置event
{
   "uuid":"254804e8-e707-11e7-9c21-0242ac110004"
}

假设查询码254804e8-e707-11e7-9c21-0242ac110004,只有表中不存在这个码返回NO EXISTED, 存在的话,则返回表中记录的状态

  • code
# -*- coding: utf-8 -*-
from tablestore import *
from tablestore.retry import WriteRetryPolicy
import time,json

table_name = 'code'
ots_name = 'code-ots'

def get_row(client, uuid):
    primary_key = [('uuid', uuid)]
    columns_to_get = []

    cond = CompositeColumnCondition(LogicalOperator.OR)
    cond.add_sub_condition(SingleColumnCondition("status", "UNACTIVED", ComparatorType.NOT_EQUAL))
    cond.add_sub_condition(SingleColumnCondition("status", "UNACTIVED", ComparatorType.EQUAL))

    consumed, return_row, next_token = client.get_row(table_name, primary_key, columns_to_get, cond, 1)
    print ('Read succeed, consume %s read cu.' % consumed.read)

    if return_row is None:
        return "NO EXISTED"

    
    status = "UNKNOWN"
    for att in return_row.attribute_columns:
        print ('name:%s\tvalue:%s\ttimestamp:%d' % (att[0], att[1], att[2]))
        if att[0] == "status":
            status = att[1]
        if att[0] == "start":
            start = att[1]
        if att[0] == "end":
            end = att[1]

    current_time = time.time()
    if current_time > end or current_time < start:
        status = "TIMEINVALID"
    return status   

def handler(event, context):
    endpoint = 'https://{}.cn-shanghai.ots-internal.aliyuncs.com'.format(ots_name)
    creds = context.credentials
    client = OTSClient(endpoint, creds.accessKeyId,  creds.accessKeySecret, ots_name, 
            sts_token = creds.securityToken, retry_policy = WriteRetryPolicy())
    evt = json.loads(event)
    uuid = str(evt['uuid'])
    return get_row(client, uuid)
4 删除码
  • 配置event
{
   "uuid":"254804e8-e707-11e7-9c21-0242ac110004"
}

假设删除码254804e8-e707-11e7-9c21-0242ac110004,不管表中是否存在这个码,只要表中没有这个码了就是成功删除,除非ots sdk delete_row抛出异常

  • code
# -*- coding: utf-8 -*-
from tablestore import *
from tablestore.retry import WriteRetryPolicy
import json

table_name = 'code'
ots_name = 'code-ots'

def delete_row(client, uuid):
    primary_key = [('uuid',uuid)]
    row = Row(primary_key)
    condition = Condition(RowExistenceExpectation.IGNORE, SingleColumnCondition("status", "", ComparatorType.NOT_EQUAL))
    try:
        consumed, return_row = client.delete_row(table_name, row, condition) 
        print ('Delete succeed, consume %s write cu.' % consumed.write)
    except:
        return 'FAILED'
    
    return 'SUCCEED'
      
def handler(event, context):
    endpoint = 'https://{}.cn-shanghai.ots-internal.aliyuncs.com'.format(ots_name)
    creds = context.credentials
    client = OTSClient(endpoint, creds.accessKeyId,  creds.accessKeySecret, ots_name, 
            sts_token = creds.securityToken, retry_policy = WriteRetryPolicy())
    evt = json.loads(event)
    uuid = str(evt['uuid'])
    return delete_row(client, uuid)
相关实践学习
【文生图】一键部署Stable Diffusion基于函数计算
本实验教你如何在函数计算FC上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。函数计算提供一定的免费额度供用户使用。本实验答疑钉钉群:29290019867
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
4月前
|
机器学习/深度学习 机器人 Serverless
FaaS 的应用场景
FaaS 的应用场景
|
22天前
|
消息中间件 运维 安全
C5GAME 游戏饰品交易平台借助 RocketMQ Serverless 保障千万级玩家流畅体验
游戏行业蓬勃发展,作为国内领先的 STEAM 游戏饰品交易的服务平台,看 C5GAME 如何利用 RocketMQ Serverless 技术,为千万级玩家提供流畅的游戏体验,同时降低成本并提升运维效率。
C5GAME 游戏饰品交易平台借助 RocketMQ Serverless 保障千万级玩家流畅体验
|
4月前
|
消息中间件 存储 监控
函数计算产品使用问题之“低频介质型”适用哪些场景
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
2月前
|
机器学习/深度学习 机器人 Serverless
【10月更文挑战第1天】FaaS 的应用场景
【10月更文挑战第1天】FaaS 的应用场景
|
4月前
|
存储 缓存 监控
函数计算产品使用问题之调用sd生图时,怎么保证高并发场景正常运行
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
4月前
|
弹性计算 监控 Serverless
函数计算产品使用问题之如何处理银行转账场景遇到的高并发问题
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
4月前
|
前端开发 小程序 Serverless
异步任务处理系统问题之阿里云函数计算FC的应用场景有哪些
异步任务处理系统问题之阿里云函数计算FC的应用场景有哪些
|
4月前
|
关系型数据库 MySQL Serverless
PolarDB MySQL Serverless:灵活弹性场景深度评测
本文深入评测了阿里云PolarDB MySQL Serverless的灵活弹性场景。作为阿里云专业运维工程师,笔者从多个角度对产品进行了全面分析: 产品特性:介绍了PolarDB MySQL Serverless的核心优势,包括动态弹性、高可用性和按量付费模式。 操作体验:详细描述了集群创建过程和控制台监控功能,突出了其简化运维的特点。 弹性能力:通过三个测试场景验证了产品在不同负载下的自动扩缩容能力,展示了其快速响应和性能稳定性。 API与文档:评估了API的易用性和文档的完整性,并提出了改进建议。 优劣分析:总结了产品的主要优势,如极致弹性和成本效益,同时指出了一些潜在的改进空间。 整体
|
4月前
|
人工智能 Serverless API
Serverless 架构实现弹幕场景问题之用SAT进行双主键的插入操作如何解决
Serverless 架构实现弹幕场景问题之用SAT进行双主键的插入操作如何解决
43 0
|
4月前
|
运维 Kubernetes 大数据
Kubernetes 的架构问题之在Serverless Container场景下尚不支持资源超售如何解决
Kubernetes 的架构问题之在Serverless Container场景下尚不支持资源超售如何解决
68 0

热门文章

最新文章

相关产品

  • 函数计算