• 5分钟Serverless实践|构建无服务器的图片分类系统
    内容速览:---前言---Serverless优势---构建无服务器的图片分类Web应用---构建事件触发的实时图片分类系统前  言在过去“5分钟Serverless实践”系列文章中,我们介绍了如何构建无服务器API和Web应用,从本质上来说,它们都属于基于APIG触发器对外提供一个无服务器API的场景。现在本文将介绍一种新的设计模式:基于事件的实时数据处理。为了更形象地描述,我们以图片分类为例,先介绍通过APIG触发器如何构建一个图片分类的Web应用,再介绍通过OBS触发器如何构造一个实时的图片分类系统。 Serverless优势相比于传统的架构,无服务器架构具有如下优点:1. 无需关注任何服务器,只需关注核心业务逻辑,提高开发和运维效率;2.  事件触发,灵活扩展;3. 函数运行随业务量弹性伸缩,按需付费,执行才计费,对于负载波峰波谷非常明显的场景可以减少大量成本;4. 通过简单的配置即可连通函数工作流和其它各云服务,甚至云服务和云服务; 构建无服务器的图片分类Web应用像以往的文章介绍的那样,serverless很擅长构建一个Web应用,如下图,该系统会将用户上传的图片进行分类,并打上类别标签。  我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:创建函数,在函数中调用华为云图片分析服务的图片标签接口,给图片打标签分类。再为该函数配置一个APIG触发器,这样便可以对外提供一个图片分类的API,最后部署前端页面到OBS,托管为静态网站,从而构建出一个完整的图片分类的无服务器Web应用。页面调用API,他会自动触发函数执行,而开发者编写的函数只需实现接收到图片之后如何处理图片的逻辑即可,最后将结果返回给页面。 接下来,我们将介绍如何完整地将此无服务器Web应用构建出来。 1. 准备工作进入华为云图片检测服务,申请开通图片检测服务的图片标签功能,成功申请后便可以调用图片标签接口了。 2. 构建后端程序进入函数工作流服务,选择模板“图片打标签Web后端”,创建函数。函数创建完成之后,为其配置具有IAM访问权限的委托,因为本函数代码中获取用户的ak、sk需要拥有访问IAM的权限。 创建成功后,API的URL可以在函数详情页面的“触发器”栏看到:至此,我们就成功地构建了一个无服务器的图片分类API。 3. 搭建前端页面为了更方便地搭建前端页面,我们提供了对应的函数模板实现快速构建前端页面。选择模板“图片打标签Web前端”,创建函数,其中自定义数据REST_API中设置上一步创建的API URL,创建完成后,函数详情页面的“触发器”栏中的URL就是页面的浏览器访问地址。至此,我们就成功地构建了一个无服务器的图片分类Web应用。接下来,我们将介绍另一种场景。 构建事件触发的实时图片分类系统本文接下来将具体介绍事件触发的实时数据处理场景,考虑下面场景,用户上传图片到OBS桶中,需要自动执行图片分类,并按照类别转储到另一个桶的不同目录下。比如下面这个例子,上传一张企鹅图片到一个桶,图片就会自动转储到另一个桶对应的penguins、seabird、bird目录下。 我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:创建函数,在函数中调用华为云图片分析服务的图片标签接口,给图片打标签分类。再为该函数配置一个OBS触发器,监控桶的POST事件,当向该桶上传一个文件时,便会自动触发函数执行,从而实现一个基于事件触发的无服务器系统。用户向桶中上传一张图片,它会自动触发函数执行,而开发者编写的函数只需实现从桶中下载图片并分类转储的逻辑即可。 接下来,我们将介绍如何完整地将此事件触发的图片分类系统构建出来。准备工作1. 申请开通图像识别服务“图像标签”功能2. 进入对象存储服务(OBS)服务,创建两个桶,一个用于接收待分类的图片(source),一个用于存储分类后的图片(result),并将桶的“桶策略”设为公共读写。 创建函数1. 进入函数工作流服务创建函数页面,选择“图片实时分类(按图片类型)”函数模板,该模板已为您提供本案例的代码。 2. 设置环境变量result_bucket为存储分类后图片的桶的名称(result)3. 配置OBS触发器,桶选择接受待分类图片的桶(source),事件选择post。当向桶中上传新图片时,会触发函数执行。4. 点击创建,创建函数和触发器。 配置函数1. 进入函数详情页面,进入“配置”标签,给函数设置一个具有访问IAM和OBS权限的委托,使函数能够获取到用户的AK、SK,并访问OBS桶资源。2. 保存配置 测试函数1. 向接收待分类图片的桶(source)中上传一张图片2. 查看存储分类结果的桶(result)中的文件,会发现图片存储到了对应类别的目录下。 更多精彩:函数工作流,0负担享受编程的乐趣
  • 三分钟迁移Spring boot工程到Serverless
    前言Spring Boot已成为当今最流行的Java后端开发框架,典型的应用方式是在云上购买一台虚拟机,每天24小时在上面运行Java程序,在这种情况下,用户必须维护自己的虚拟机环境,而且按照包月包年等方式进行付费。华为云FunctionGraph(函数工作流服务)有着零运维、低成本计算的特点,FunctionGraph按需运行代码,无需配置和管理主机,您仅需为代码执行的每100ms和次数付费,如果代码没有运行的话,不会产生任何费用,而且每个月还有较多的免费额度。FunctionGraph有明显的成本和维护优势,但是怎样才能把标准的Spring Boot应用程序当做函数在FunctionGraph上运行起来呢?现在以我本地的一个SpringBoot工程(链接https://functionstage-examples.obs.cn-north-1.myhwclouds.com/ServerlessSpringBootDemo.zip)为例展示快速迁移到华为云FunctionGraph的流程。准备工作下载ServerlessSpringBoot2-1.0.0.jar(链接https://functionstage-examples.obs.cn-north-1.myhwclouds.com/ServerlessSpringBoot2-1.0.0.jar);迁移流程1、  制作函数zip包:按照上面的动图添加fgs.properties配置文件,增加两个配置项fgs.component-scan和fgs.mapper-scan,然后导包。 所得的ServerlessSpringBootDemo.zip就是最终的函数代码包。 2、  创建函数:在华为云入口找到FunctionGraph服务,进去后选择创建函数,函数名称建议设置为Controller中的根路径,例如本例的webtest,选择语言为Java8,另外设置函数执行入口为com.huawei.fgs.ext.handler.Main.handler,选择zip包方式上传代码(或者可以将代码先传入OBS桶,使用OBS上传方式创建),创建成功。3、  创建APIG触发器函数创建完成后修改内存为1024,修改超时时间为30(首次启动时间较长)并保存。接下来切换到触发器选项卡,点击创建触发器,选择APIG,将安全认证改成NONE,后端超时设置为30000,和函数超时保持一致,点击确定完成创建。检验结果直接在浏览器中访问APIG生成的URL,因为demo中的Controller中并没有匹配/webtest路径的RequestMapping,因此一开始提示找不到路径,稍加修改后可以看到效果:总结综上所述,整个迁移过程非常简单,用户无需改造自己的业务代码,只需在资源目录下新增fgs.properties文件即可,导包过程和常规情况稍有不同,按照上面的步骤也可以在数秒内完成,最后创建好函数和触发器之后,整个流程就完成了。注意事项1、  使用SpringBoot的AOP特性时,请不要将切面定义到Controller层,否则会导致无法使用;2、  目前Controller都会视作RestController,所有的接口均会以ResponseBody形式返回,暂时不支持返回html页面;3、  在application.properties中去掉server.port配置,加入spring.main.web-environment=false配置项可以小幅提升首次启动速度;4、  如果代码需要经常改动,请将所有的依赖包打包成一个zip,上传到OBS,创建函数时填入依赖代码包的地址,后续更新代码时,只需要上传一个小的jar包即可;5、  如果业务代码中使用了filter,需要对代码进行修改,具体方式后续会提供(本demo中有简单使用例子,依赖FunctionGraph的Java SDK(链接https://functionstage-sdk.obs.myhwclouds.com/java-sdk/fss-java-sdk-1.1.0.zip)中的Runtime-1.1.0.jar和ServerlessSpringBoot2-1.0.0.jar);6、  如果需要使用本demo的代码,请先把application.properties中的mysql信息改为自己的公网访问配置:另外在数据库中创建users表和books表。users表结构如下:books表结构如下:
  • 三分钟迁移Spring boot工程到Serverless
    前言Spring Boot已成为当今最流行的Java后端开发框架,典型的应用方式是在云上购买一台虚拟机,每天24小时在上面运行Java程序,在这种情况下,用户必须维护自己的虚拟机环境,而且按照包月包年等方式进行付费。华为云FunctionGraph(函数工作流服务)有着零运维、低成本计算的特点,FunctionGraph按需运行代码,无需配置和管理主机,您仅需为代码执行的每100ms和次数付费,如果代码没有运行的话,不会产生任何费用,而且每个月还有较多的免费额度。FunctionGraph有明显的成本和维护优势,但是怎样才能把标准的Spring Boot应用程序当做函数在FunctionGraph上运行起来呢?现在以我本地的一个SpringBoot工程(链接https://functionstage-examples.obs.cn-north-1.myhwclouds.com/ServerlessSpringBootDemo.zip)为例展示快速迁移到华为云FunctionGraph的流程。准备工作下载ServerlessSpringBoot2-1.0.0.jar(链接https://functionstage-examples.obs.cn-north-1.myhwclouds.com/ServerlessSpringBoot2-1.0.0.jar);迁移流程1、  制作函数zip包:按照上面的动图添加fgs.properties配置文件,增加两个配置项fgs.component-scan和fgs.mapper-scan,然后导包。 所得的ServerlessSpringBootDemo.zip就是最终的函数代码包。 2、  创建函数:在华为云入口找到FunctionGraph服务,进去后选择创建函数,函数名称建议设置为Controller中的根路径,例如本例的webtest,选择语言为Java8,另外设置函数执行入口为com.huawei.fgs.ext.handler.Main.handler,选择zip包方式上传代码(或者可以将代码先传入OBS桶,使用OBS上传方式创建),创建成功。3、  创建APIG触发器函数创建完成后修改内存为1024,修改超时时间为30(首次启动时间较长)并保存。接下来切换到触发器选项卡,点击创建触发器,选择APIG,将安全认证改成NONE,后端超时设置为30000,和函数超时保持一致,点击确定完成创建。检验结果直接在浏览器中访问APIG生成的URL,因为demo中的Controller中并没有匹配/webtest路径的RequestMapping,因此一开始提示找不到路径,稍加修改后可以看到效果:总结综上所述,整个迁移过程非常简单,用户无需改造自己的业务代码,只需在资源目录下新增fgs.properties文件即可,导包过程和常规情况稍有不同,按照上面的步骤也可以在数秒内完成,最后创建好函数和触发器之后,整个流程就完成了。注意事项1、  使用SpringBoot的AOP特性时,请不要将切面定义到Controller层,否则会导致无法使用;2、  目前Controller都会视作RestController,所有的接口均会以ResponseBody形式返回,暂时不支持返回html页面;3、  在application.properties中去掉server.port配置,加入spring.main.web-environment=false配置项可以小幅提升首次启动速度;4、  如果代码需要经常改动,请将所有的依赖包打包成一个zip,上传到OBS,创建函数时填入依赖代码包的地址,后续更新代码时,只需要上传一个小的jar包即可;5、  如果业务代码中使用了filter,需要对代码进行修改,具体方式后续会提供(本demo中有简单使用例子,依赖FunctionGraph的Java SDK(链接https://functionstage-sdk.obs.myhwclouds.com/java-sdk/fss-java-sdk-1.1.0.zip)中的Runtime-1.1.0.jar和ServerlessSpringBoot2-1.0.0.jar);6、  如果需要使用本demo的代码,请先把application.properties中的mysql信息改为自己的公网访问配置:另外在数据库中创建users表和books表。users表结构如下:books表结构如下:
  • 一种冲击Pass服务的玩法正悄然来袭
    其实,广义的Serverless覆盖范围很大,很多云服务产品可以被视作Serverless化的。以存储服务的发展历程为例:最初常见是云服务器,此种情况对用户熟悉的原有开发方式的模拟,但是需要自行处理云服务器宕机带来的数据不可用问题,云磁盘上的数据也不便于分享;后来,对象存储(OSS),文件存储(NAS),表格存储(TableStore),消息通知服务(SMN)等都属于Serverless服务。这些服务不再有机器的概念,用户能够享受自动的扩容和负载平衡,性能水平扩展,通过API方便的读写数据,易于共享,并且按实际存储的数据量以及访问次数付费。此外,类似大数据计算服务(MaxCompute) 也是Serverless的,提供了MapReduce,和Streaming等多种计算框架,用户不需要管理计算资源。Serverless是一个宽泛的概念,很多存储、计算和中间件服务都是Serverless的。而FaaSServerless的子集,也是实现整个应用Serverless化的核心服务。FaaS的关键特征是:事件驱动、细粒度调用、实时弹性伸缩,无需管理服务器等底层资源。FaaS兴起是对现有技术很好的补充,配合使用已有的云服务产品,即可以真正构建Serverless的应用。之所以研发FaaS产品-函数计算,也是观察到在存储和计算业务中,从server-base到Serverless的演变趋势和用户的需求。 目前,SMN(消息通知服务)已经正式集成Functionstage,函数计算的影响力正在被放大。 视频处理的后端系统,常见功能需求如下:视频转码、抽取数据、人脸识别等,这些均为通用计算任务,可由函数计算执行。使用SMN服务发送函数计算后,您在不关心扩容、错峰填谷等问题的同时,还能够享受到SMN服务订阅模式的便利。 随着函数服务的快速发展,运维以及运算等问题正在被弱化,当前已经被广泛认知的Devops在未来可能面临变革。未来用户将更加的关心实现逻辑,如果Serverless平台可以解决通用问题,并且有吸引力,那确实会对传统的云计算有冲击;但是,这是个渐进的过程。
  • [技术干货] 5分钟Serverless实践|构建无服务器的敏感词过滤后端系统
    5分钟Serverless实践|构建无服务器的敏感词过滤后端系统 1      前  言在上一篇“5分钟Serverless实践”系列文章中,我们介绍了什么是Serverless,以及如何构建一个无服务器的图片鉴黄Web应用,本文将延续这个话题,以敏感词过滤为例,介绍如何构建一个无服务器API,即无服务器的后端系统。 2      函数工作流函数工作流(FunctionGraph,FGS)是一项基于事件驱动的函数托管计算服务,托管函数具备以毫秒级弹性伸缩、免运维、高可靠的方式运行。通过函数工作流,开发者无需配置和管理服务器,只需关注业务逻辑,编写函数代码,以无服务器的方式构建应用,便能开发出一个弹性高可用的后端系统,并按实际运行消耗的资源计费。极大地提高了开发和运维效率,减小了运作成本。 相比于传统的架构,函数工作流构建的无服务器架构具有如下优点:1. 无需关注任何服务器,只需关注核心业务逻辑,提高开发和运维效率;2. 函数运行随业务量弹性伸缩,按需付费,执行才计费,对于负载波峰波谷非常明显的场景可以减少大量成本;3. 通过简单的配置即可连通函数工作流和其它各云服务,甚至云服务和云服务; 3      构建无服务器的敏感词过滤后端系统为了进一步让大家感受函数工作流的优势,我们将介绍如何通过函数工作流快速构建一个无服务器的敏感词过滤系统,本文我们主要关注后端系统,前端的表现形式很多,大家可以自行构建。如下图,该系统会识别用户上传的文本内容是否包含敏感信息(如**、政治等),并对这些词语进行过滤。 试想,如果我们通过传统的模式开发此应用,需要如何开发?即使是基于现在的云平台,我们也仍需要购买云服务器,关注其规格、镜像、网络等各指标的选型和运维,然后在开发过程中可能还需要考虑与其他云服务的集成使用问题,使代码中耦合大量非业务代码,并且服务器等资源也并非是按需的,特别是对于访问量波峰波谷非常明显的场景,会造成大量多余的费用。 现在我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:创建函数,在函数中调用华为云内容检测服务提供的文本检测接口,实现文本的敏感词检测,并为该函数配置一个APIG触发器,这样便可以对外提供一个敏感词过滤的API,从而构建出一个完整的敏感词过滤的无服务器后端系统。客户端调用API,他会自动触发函数执行,而开发者编写的函数只需实现接收到文本之后如何处理文本的逻辑即可,最后将结果返回给客户端。至此,我们就构建了一个完整的无服务器敏感词过滤后端系统。 接下来,我们将介绍如何完整地将此无服务器后端系统构建出来。1. 准备工作进入华为云内容检测服务,申请开通文本内容检测,成功申请后便可以调用内容检测服务提供的文本检测接口了。 2. 创建函数进入函数工作流服务页面,创建函数,实现文本检测的接口调用和敏感词过滤,代码如下(Python):# -*- coding:utf-8 -*-import jsonimport base64import urllibimport urllib2import sslimport sys reload(sys)sys.setdefaultencoding('utf-8') def do_filter(msg,str_list):    result = ''    try:        if len(str_list) <=0:            return msg        for str in str_list:            str_tmp = msg.replace(str,'')            msg = str_tmp        result = msg    except:        print("_do_filter catch an exception!")    return result def filter(context, msg):    result = ''    try:        ssl._create_default_https_context = ssl._create_unverified_context                token = context.getToken();        headers = {'Content-Type':'application/json;charset=utf8','X-Auth-Token':token}                url = "https://ais.cn-north-1.myhwclouds.com/v1.0/moderation/text"                values = {}        values['categories'] = ['**','ad','politics','abuse','contraband']        #msg = base64.b64encode(msg)        item = {'type':'content','text':msg}        values['items'] =                 data = json.dumps(values)        print("data: %s"%data)                request = urllib2.Request(url,data,headers)        rsp = urllib2.urlopen(request)        http_rsp = rsp.read()        print("http response: %s" %http_rsp)                json_rsp = json.loads(http_rsp)        result = json_rsp['result']                suggestion = result['suggestion']                if suggestion == 'pass':            print("input msg have passed the checking!")            result = msg        else:            detail = result['detail']                    if detail.has_key('**'):                list_** = detail['**']                msg = do_filter(msg,list_**)            if detail.has_key('ad'):                list_ad = detail['ad']                msg = do_filter(msg,list_ad)            if detail.has_key('politics'):                list_politics = detail['politics']                msg = do_filter(msg,list_politics)            if detail.has_key('abuse'):                list_abuse = detail['abuse']                msg = do_filter(msg,list_abuse)            if detail.has_key('contraband'):                list_contraband = detail['contraband']                msg = do_filter(msg,list_contraband)            result = msg    except Exception, e:        print e        print("filter catch an exception!")    return result def handler (event, context):    print("message filter begin!")    result = ""    response = {}    http_method = event.get('httpMethod')        if http_method == 'OPTIONS':        response = {            'statusCode': 200,            'isBase64Encoded': True,            'headers': {                "Content-Type": "application/json; charset=utf-8",                "Access-Control-Allow-Origin": "*",                "Access-Control-Allow-Headers": "Content-Type,Accept",                "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE"            },            'body': base64.b64encode('{"result":'+ '"' + result +'"}'),        }        return response    body = event.get('body')    body_decode = base64.b64decode(body)    json_object = json.loads(body_decode)    msg = json_object['msg']        print('msg : %s'%msg)        try:        result = filter(context, msg)        response = {            'statusCode': 200,            'isBase64Encoded': True,            'headers': {                "Content-Type": "application/json; charset=utf-8",                "Access-Control-Allow-Origin": "*",                "Access-Control-Allow-Headers": "Content-Type,Accept",                "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE"            },            'body': base64.b64encode('{"result":'+ '"' + result +'"}'),        }    except:        print("function catch an exception!")        return response函数创建完成之后,为其配置具有IAM访问权限的委托,因为本函数代码中获取用户的ak、sk需要拥有访问IAM的权限。 3. 创建APIG触发器为函数配置一个APIG触发器,这样便得到一个调用该函数的HTTP(S) API,供外部调用。 创建成功后,API的URL可以在函数详情页面的“触发器”栏看到:  4. 测试使用postman等工具向上一步中创建的APIG触发器的接口发送post请求,body体为:{“msg”: “过滤检测的文本”},查看返回信息。比如发送 {"msg": "just ** ..."}, 返回体为 {"result": "just  ..."} 至此,我们就完整地构建了一个无服务器的敏感词过滤后端系统。 欢迎扫码查看更多精彩:
  • 5分钟Serverless实践|构建无服务器的敏感词过滤后端系统
    1      前  言在上一篇“5分钟Serverless实践”系列文章中,我们介绍了什么是Serverless,以及如何构建一个无服务器的图片鉴黄Web应用,本文将延续这个话题,以敏感词过滤为例,介绍如何构建一个无服务器API,即无服务器的后端系统。 2      函数工作流函数工作流(FunctionGraph,FGS)是一项基于事件驱动的函数托管计算服务,托管函数具备以毫秒级弹性伸缩、免运维、高可靠的方式运行。通过函数工作流,开发者无需配置和管理服务器,只需关注业务逻辑,编写函数代码,以无服务器的方式构建应用,便能开发出一个弹性高可用的后端系统,并按实际运行消耗的资源计费。极大地提高了开发和运维效率,减小了运作成本。 相比于传统的架构,函数工作流构建的无服务器架构具有如下优点:1. 无需关注任何服务器,只需关注核心业务逻辑,提高开发和运维效率;2. 函数运行随业务量弹性伸缩,按需付费,执行才计费,对于负载波峰波谷非常明显的场景可以减少大量成本;3. 通过简单的配置即可连通函数工作流和其它各云服务,甚至云服务和云服务; 3      构建无服务器的敏感词过滤后端系统为了进一步让大家感受函数工作流的优势,我们将介绍如何通过函数工作流快速构建一个无服务器的敏感词过滤系统,本文我们主要关注后端系统,前端的表现形式很多,大家可以自行构建。如下图,该系统会识别用户上传的文本内容是否包含敏感信息(如**、政治等),并对这些词语进行过滤。 试想,如果我们通过传统的模式开发此应用,需要如何开发?即使是基于现在的云平台,我们也仍需要购买云服务器,关注其规格、镜像、网络等各指标的选型和运维,然后在开发过程中可能还需要考虑与其他云服务的集成使用问题,使代码中耦合大量非业务代码,并且服务器等资源也并非是按需的,特别是对于访问量波峰波谷非常明显的场景,会造成大量多余的费用。 现在我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:创建函数,在函数中调用华为云内容检测服务提供的文本检测接口,实现文本的敏感词检测,并为该函数配置一个APIG触发器,这样便可以对外提供一个敏感词过滤的API,从而构建出一个完整的敏感词过滤的无服务器后端系统。客户端调用API,他会自动触发函数执行,而开发者编写的函数只需实现接收到文本之后如何处理文本的逻辑即可,最后将结果返回给客户端。至此,我们就构建了一个完整的无服务器敏感词过滤后端系统。 接下来,我们将介绍如何完整地将此无服务器后端系统构建出来。1. 准备工作进入华为云内容检测服务,申请开通文本内容检测,成功申请后便可以调用内容检测服务提供的文本检测接口了。 2. 创建函数进入函数工作流服务页面,创建函数,实现文本检测的接口调用和敏感词过滤,代码如下(Python):# -*- coding:utf-8 -*-import jsonimport base64import urllibimport urllib2import sslimport sys reload(sys)sys.setdefaultencoding('utf-8') def do_filter(msg,str_list):    result = ''    try:        if len(str_list) <=0:            return msg        for str in str_list:            str_tmp = msg.replace(str,'')            msg = str_tmp        result = msg    except:        print("_do_filter catch an exception!")    return result def filter(context, msg):    result = ''    try:        ssl._create_default_https_context = ssl._create_unverified_context                token = context.getToken();        headers = {'Content-Type':'application/json;charset=utf8','X-Auth-Token':token}                url = "https://ais.cn-north-1.myhwclouds.com/v1.0/moderation/text"                values = {}        values['categories'] = ['**','ad','politics','abuse','contraband']        #msg = base64.b64encode(msg)        item = {'type':'content','text':msg}        values['items'] =                 data = json.dumps(values)        print("data: %s"%data)                request = urllib2.Request(url,data,headers)        rsp = urllib2.urlopen(request)        http_rsp = rsp.read()        print("http response: %s" %http_rsp)                json_rsp = json.loads(http_rsp)        result = json_rsp['result']                suggestion = result['suggestion']                if suggestion == 'pass':            print("input msg have passed the checking!")            result = msg        else:            detail = result['detail']                    if detail.has_key('**'):                list_** = detail['**']                msg = do_filter(msg,list_**)            if detail.has_key('ad'):                list_ad = detail['ad']                msg = do_filter(msg,list_ad)            if detail.has_key('politics'):                list_politics = detail['politics']                msg = do_filter(msg,list_politics)            if detail.has_key('abuse'):                list_abuse = detail['abuse']                msg = do_filter(msg,list_abuse)            if detail.has_key('contraband'):                list_contraband = detail['contraband']                msg = do_filter(msg,list_contraband)            result = msg    except Exception, e:        print e        print("filter catch an exception!")    return result def handler (event, context):    print("message filter begin!")    result = ""    response = {}    http_method = event.get('httpMethod')        if http_method == 'OPTIONS':        response = {            'statusCode': 200,            'isBase64Encoded': True,            'headers': {                "Content-Type": "application/json; charset=utf-8",                "Access-Control-Allow-Origin": "*",                "Access-Control-Allow-Headers": "Content-Type,Accept",                "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE"            },            'body': base64.b64encode('{"result":'+ '"' + result +'"}'),        }        return response    body = event.get('body')    body_decode = base64.b64decode(body)    json_object = json.loads(body_decode)    msg = json_object['msg']        print('msg : %s'%msg)        try:        result = filter(context, msg)        response = {            'statusCode': 200,            'isBase64Encoded': True,            'headers': {                "Content-Type": "application/json; charset=utf-8",                "Access-Control-Allow-Origin": "*",                "Access-Control-Allow-Headers": "Content-Type,Accept",                "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE"            },            'body': base64.b64encode('{"result":'+ '"' + result +'"}'),        }    except:        print("function catch an exception!")        return response函数创建完成之后,为其配置具有IAM访问权限的委托,因为本函数代码中获取用户的ak、sk需要拥有访问IAM的权限。 3. 创建APIG触发器为函数配置一个APIG触发器,这样便得到一个调用该函数的HTTP(S) API,供外部调用。 创建成功后,API的URL可以在函数详情页面的“触发器”栏看到:  4. 测试使用postman等工具向上一步中创建的APIG触发器的接口发送post请求,body体为:{“msg”: “过滤检测的文本”},查看返回信息。比如发送 {"msg": "just ** ..."}, 返回体为 {"result": "just  ..."} 至此,我们就完整地构建了一个无服务器的敏感词过滤后端系统。 欢迎扫码查看更多精彩:
  • 5分钟Serverless实践|构建无服务器的图片分类系统
    内容速览:---前言---Serverless优势---构建无服务器的图片分类Web应用---构建事件触发的实时图片分类系统前  言在过去“5分钟Serverless实践”系列文章中,我们介绍了如何构建无服务器API和Web应用,从本质上来说,它们都属于基于APIG触发器对外提供一个无服务器API的场景。现在本文将介绍一种新的设计模式:基于事件的实时数据处理。为了更形象地描述,我们以图片分类为例,先介绍通过APIG触发器如何构建一个图片分类的Web应用,再介绍通过OBS触发器如何构造一个实时的图片分类系统。 Serverless优势相比于传统的架构,无服务器架构具有如下优点:1. 无需关注任何服务器,只需关注核心业务逻辑,提高开发和运维效率;2.  事件触发,灵活扩展;3. 函数运行随业务量弹性伸缩,按需付费,执行才计费,对于负载波峰波谷非常明显的场景可以减少大量成本;4. 通过简单的配置即可连通函数工作流和其它各云服务,甚至云服务和云服务; 构建无服务器的图片分类Web应用像以往的文章介绍的那样,serverless很擅长构建一个Web应用,如下图,该系统会将用户上传的图片进行分类,并打上类别标签。  我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:创建函数,在函数中调用华为云图片分析服务的图片标签接口,给图片打标签分类。再为该函数配置一个APIG触发器,这样便可以对外提供一个图片分类的API,最后部署前端页面到OBS,托管为静态网站,从而构建出一个完整的图片分类的无服务器Web应用。页面调用API,他会自动触发函数执行,而开发者编写的函数只需实现接收到图片之后如何处理图片的逻辑即可,最后将结果返回给页面。 接下来,我们将介绍如何完整地将此无服务器Web应用构建出来。 1. 准备工作进入华为云图片检测服务,申请开通图片检测服务的图片标签功能,成功申请后便可以调用图片标签接口了。 2. 构建后端程序进入函数工作流服务,选择模板“图片打标签Web后端”,创建函数。函数创建完成之后,为其配置具有IAM访问权限的委托,因为本函数代码中获取用户的ak、sk需要拥有访问IAM的权限。 创建成功后,API的URL可以在函数详情页面的“触发器”栏看到:至此,我们就成功地构建了一个无服务器的图片分类API。 3. 搭建前端页面为了更方便地搭建前端页面,我们提供了对应的函数模板实现快速构建前端页面。选择模板“图片打标签Web前端”,创建函数,其中自定义数据REST_API中设置上一步创建的API URL,创建完成后,函数详情页面的“触发器”栏中的URL就是页面的浏览器访问地址。至此,我们就成功地构建了一个无服务器的图片分类Web应用。接下来,我们将介绍另一种场景。 构建事件触发的实时图片分类系统本文接下来将具体介绍事件触发的实时数据处理场景,考虑下面场景,用户上传图片到OBS桶中,需要自动执行图片分类,并按照类别转储到另一个桶的不同目录下。比如下面这个例子,上传一张企鹅图片到一个桶,图片就会自动转储到另一个桶对应的penguins、seabird、bird目录下。 我们可以通过函数工作流服务来快速构建这个系统,并且完全无需关注服务器,且弹性伸缩运行、按需计费,如图:创建函数,在函数中调用华为云图片分析服务的图片标签接口,给图片打标签分类。再为该函数配置一个OBS触发器,监控桶的POST事件,当向该桶上传一个文件时,便会自动触发函数执行,从而实现一个基于事件触发的无服务器系统。用户向桶中上传一张图片,它会自动触发函数执行,而开发者编写的函数只需实现从桶中下载图片并分类转储的逻辑即可。 接下来,我们将介绍如何完整地将此事件触发的图片分类系统构建出来。准备工作1. 申请开通图像识别服务“图像标签”功能2. 进入对象存储服务(OBS)服务,创建两个桶,一个用于接收待分类的图片(source),一个用于存储分类后的图片(result),并将桶的“桶策略”设为公共读写。 创建函数1. 进入函数工作流服务创建函数页面,选择“图片实时分类(按图片类型)”函数模板,该模板已为您提供本案例的代码。 2. 设置环境变量result_bucket为存储分类后图片的桶的名称(result)3. 配置OBS触发器,桶选择接受待分类图片的桶(source),事件选择post。当向桶中上传新图片时,会触发函数执行。4. 点击创建,创建函数和触发器。 配置函数1. 进入函数详情页面,进入“配置”标签,给函数设置一个具有访问IAM和OBS权限的委托,使函数能够获取到用户的AK、SK,并访问OBS桶资源。2. 保存配置 测试函数1. 向接收待分类图片的桶(source)中上传一张图片2. 查看存储分类结果的桶(result)中的文件,会发现图片存储到了对应类别的目录下。 更多精彩:函数工作流,0负担享受编程的乐趣
  • [体验馆] 用Serverless容器服务部署2048小游戏,so easy!
    准备工作1. 建议先 点击此处 下载.rar格式的压缩文件,只需经过一次解压即可得到 .tar 格式的镜像打包文件“docker-2048”哦。2. 建议先 点击此处 购买CCI 9元超值体验套餐包,游戏部署体验更佳哦!~下面来是完整操作步骤步骤一:创建命名空间命名空间(namespace)是kubernetes 的一个典型概念,是一种在多个用户之间划分资源的方法,适用于用户中存在多个团队或项目的情况。当前CCI服务提供两种类型的资源:“通用计算型”和“GPU型”。创建命名空间时需要选择资源类型,后续创建的负载中容器就运行在此类型的集群上。1. 登录云容器实例管理控制台,左侧导航栏中选择“命名空间”。2. 选择创建“通用计算型“命名空间。点击“一键创建”即可获得一个全新的命名空间(cci-auto-1548297057827),用于对即将部署的游戏应用进行管理。   步骤二 部署工作负载工作负载是对Pod的服务化封装,当前CCI服务中主要支持无状态负载、短任务负载、定时任务负载等。本例中游戏应用以无状态负载的方式作为一个长稳应用部署在CCI服务中。1.  在左侧导航栏中选择“工作负载”,在右侧选择上一个步骤创建的命名空间,单击“创建负载”。2. 配置无状态负载基本信息 a. 填写负载名称; b. 选择POD数量;当配置多个Pod时,云容器实例会自动在Pod间做负载均衡。此处建议POD数量不小于2,否则无法保证应用的HA能力。c. 填写负载描述信息。3. 容器设置a. 选择镜像。点击“上传镜像”、在容器镜像服务中选择“页面上传”,选择组织,选择镜像文件,上传已下载至本地的镜像文件“docker-2048”即可。上传完毕后,返回创建无状态工作负载页面刷新, 即可看到刚刚上传的镜像,点击“使用该镜像”b. 根据需要配置容器规格及高级设置(存储、环境变量、健康检查、生命周期、启动命令和ConfigMap)。本示例请保持默认值不变,然后单击“下一步”。4. 访问设置关于负载的访问设置,有如下3种选项:不启用:负载不提供外部访问方式,适合一些计算类场景,只需计算完存储结果即可,无需与外部通信。内网访问:负载之间通过“负载域名:负载端口”互相访问。公网访问:通过弹性负载均衡,从外部访问访问负载。本示例中我们的小游戏应用需要能够通过公网进行访问,此处选择公网访问。a. 参考界面提示在弹性负载均衡的界面购买增强型ELB。购买后点击界面的刷新即可选择对应的ELB实例使用。b. 选择“ELB协议”:TCP/UDP本例中,数字游戏应用的流量只需要做四层负载均衡,在TCP层进行流量转发到容器中的指定端口(80)即可。c. 选择“负载端口协议”:TCPd. 选择负载端口配置,此处ELB端口系统会根据当前选择的ELB实例的端口占用情况,自动推荐可用端口。容器端口和具体部署的应用开放端口有关,本例中该容器实例开放端口80。e. 点击下一步。5. 规格确认后,点击提交,单击“返回负载列表”。在负载列表中,待负载状态为“运行中”,负载创建成功,本游戏应用即部署完成。步骤三 获取游戏应用访问地址1. 单击负载名称,进入负载详情页面2. 选择“访问配置 > 公网访问”Tab页,拷贝公网访问地址(即“ELB IP地址:端口”),即可在浏览器中访问本游戏应用。
  • [技术交流] Serverless 架构就不要服务器了?
     摘要:Serverless 架构不是不要服务器了,而是依托第三方云服务平台,服务端逻辑运行在无状态的计算容器中,其业务层面的状态则被开发者使用的数据库和存储资源所记录。Serverless 是什么我们在题目提出了一个问题,Serverless 架构是不是就不要服务器了?回答这个问题,我们需要了解下 Serverless 是什么。Serverless 架构近几年频繁出现在一些技术架构大会的演讲标题中,很多人对于 Serverless,只是从字面意义上理解,无服务器架构,但是它真正的含义是开发者再也不用过多考虑服务器的问题,但是并不代表完全去除服务器,而是我们依靠第三方资源服务器后端,从 2014 年开始,经过这么多年的发展,各大云服务商基本都提供了 Serverless 服务。架构是如何演进到 Serverless ?看看过去几十年间,云计算领域的发展演进历程。总的来说,云计算的发展分为三个阶段:虚拟化的出现、虚拟化在云计算中的应用以及容器化的出现。云计算的高速发展,则集中在近十几年。总结来说有如下的里程碑事件:通过虚拟化技术将大型物理机虚拟成单个的VM资源。将虚拟化集群搬到云计算平台上,只做简单运维。把每一个VM按照运行空间最小化的原则切分成更细的Docker容器。基于Docker容器构建不用管理任何运行环境、仅需编写核心代码的Serverless架构。从裸金属机器的部署应用,到 Openstack 架构和虚拟机的划分,再到容器化部署,这其中典型的就是近些年 docker 和 Kubernates 的流行,进一步发展为使用一个微服务或微功能来响应一个客户端的请求 ,这种方式是云计算发展的自然过程。这个发展历程也是一场 IT 架构的演进,期间经历了一系列代际的技术变革,把资源切分得更细,让运行效率更高,让硬件软件维护更简单。IT架构的演进主要有以下几个特点:硬件资源使用颗粒度变小资源利用率越来越高运维工作逐步减少业务更聚焦在代码层面Serverless 架构的组成Serverless架构分为 Backend as a Service(BaaS) 和 Functions as a Service(FaaS) 两种技术,Serverless 它是由开发者实现的服务端逻辑运行在无状态的计算容器中,它是由事件触发,完全被第三方管理的。什么是 BaaS?Baas 的英文翻译成中文的含义:后端即服务,它的应用架构由大量第三方云服务器和API组成的,使应用中关于服务器的逻辑和状态都由服务提供方来管理的。比如我们的典型的单页应用SPA和移动APP富客户端应用,前后端交互主要是以RestAPI调用为主。只需要调用服务提供方的API即可完成相应的功能,比如常见的身份验证,云端数据/文件存储,消息推送,应用数据分析等。什么是 FaaS?FaaS可以被叫做:函数即服务。开发者可以直接将服务业务逻辑代码部署,运行在第三方提供的无状态计算容器中,开发者只需要编写业务代码即可,无需关注服务器,并且代码的执行它是由事件触发的。Serverless的应用架构是将 BaaS 和 FaaS 组合在一起的应用,用户只需要关注应用的业务逻辑代码,编写函数为粒度将其运行在FaaS平台上,并且和BaaS第三方服务整合在一起,最后就搭建了一个完整的系统。整个系统过程中完全无需关注服务器。Serverless 架构的特点总得来说,Serverless 架构主要有以下特点:实现了细粒度的计算资源分配。不需要预先分配资源。具备真正意义上的高度扩容和弹性。按需使用,按需计费。由于 Serverless 应用与服务器的解耦,购买的是云服务商的资源,使得 Serverless 架构降低了运维的压力,也无需进行服务器硬件等预估和购买。Serverless 架构使得开发人员更加专注于业务服务的实现,中间件和硬件服务器资源都托管给了云服务商。这同时降低了开发成本,按需扩展和计费,无需考虑基础设施。Serverless 架构给前端也带来了便利,大前端深入到业务端的成本降低,开发者只需要关注业务逻辑,前端工程师轻松转为全栈工程师。Serverless 有哪些应用场景?应用场景与 Serverless 架构的特点密切相关,根据 Serverless 的这些通用特点,我们归纳出下面几种典型使用场景:弹性伸缩、大数据分析、事件触发等。弹性伸缩由于云函数事件驱动及单事件处理的特性,云函数通过自动的伸缩来支持业务的高并发。针对业务的实际事件或请求数,云函数自动弹性合适的处理实例来承载实际业务量。在没有事件或请求时,无运行实例,不占用资源。如视频直播服务,直播观众不固定,需要考虑适度的并发和弹性。直播不可能 24 小时在线,有较为明显的业务访问高峰期和低谷期。直播是事件或者公众点爆的场景,更新速度较快,版本迭代较快,需要快速完成对新热点的技术升级。大数据分析数据统计本身只需要很少的计算量,离线计算生成图表。在空闲的时候对数据进行处理,或者不需要考虑任何延时的情况下。开发者编写代码,目前支持的语言Java、NodeJS、Python等语言。把代码上传到函数计算上,上传的方式有通过 API 或者 SDK 上传,也可以通过控制台页面上传上传,还可以通过命令行工具Fcli上传。通过API&SDK来触发函数计算执行,同样也可以通过云产品的事件源来触发函数计算执行。函数计算在执行过程中,会根据用户请请求量动态扩容函数计算来保证请求峰值的执行,这个过程对用户是透明无感知的。函数执行结束。事件触发事件触发即云函数由事件驱动,事件的定义可以是指定的 http 请求,或者数据库的 binlog 日志、消息推送等。通过 Serverless 架构,在控制台上配置事件源通知,编写业务代码。业务逻辑添加到到函数计算里,业务高峰期函数计算会动态伸缩,这个过程不需要管理软硬件环境。常见的场景如视频、OSS 图片,当上传之后,通过进行后续的过滤、转换和分析,触发一系列的后续处理,如内容不合法、容量告警等。小结回到我们文章的题目,Serverless 架构不是不要服务器了,而是依托第三方云服务平台,服务端逻辑运行在无状态的计算容器中,其业务层面的状态则被开发者使用的数据库和存储资源所记录。Serverless 无服务器架构有其适合应用的场景,但是也存在局限性。总得来说,Serverless 架构还不够成熟,很多地方存在不完善。Serverless 依赖云服务商提供的基础设施,目前来说云服务商还做不到真正的平台高可用。Serverless 资源虽然便宜,但是构建一个生产环境的应用系统却比较复杂。云计算还在不断发展,基础设施发服务日趋完善,开发者将会更加专注于业务逻辑的实现。云计算将平台、中间件、运维部署的责任进行了转移,同时也降低了中小企业上云的成本。让我们一起期待 Serverless 架构的未来。 本文分享自《【华为云专家原创】Serverless 架构就不要服务器了?》,原文作者:aoho。
  • [技术干货] Pagic + Vercel 极速搭建个人博客
    Pagic + Vercel 极速搭建个人博客❝在中国功夫中,“天下武功,无坚不摧,唯快不破”,在编程的世界里,如何快速搭建一个属于自己的博客呢?那么 Pagic + Vercel 应该是个不错的选择!❞PagicPagic 是一个由 Deno + React 驱动的静态网站生成器。它配置简单,支持将 md/tsx 文件渲染成静态页面,而且还有大量的官方或第三方主题和插件可供扩展,也就意味着您可以自由地开发定制您喜欢的主题风格或者功能插件。相比其他静态网站生成器, Pagic有哪些优势呢?PagicVuePressHexoJekyllHugoSupport md✓✓✓✓✓React/Vue✓✓SPA✓✓Allow tsx in config✓...如此优秀的 Pagic 应该如何使用呢?首先,安装 Deno :# Shell (Mac, Linux):curl -fsSL https://deno.land/x/install/install.sh | sh然后,安装最新版本的 Pagic :deno install --unstable --allow-read --allow-write --allow-net --allow-run --name=pagic https://deno.land/x/pagic/mod.ts初始化 Pagic 项目:mkdir site && cd site && echo "export default {};" > pagic.config.ts && echo "# Hello world" > README.md运行 pagic build:pagic build --watch --serve现在您访问 127.0.0.1:8000 就能看到 「Hello world」 的页面:VercelVercel是一个用于静态站点和 Serverless 功能的云平台,完全符合您的工作流。它使开发人员能够托管网站和web服务,这些网站和服务可以即时部署、自动扩展,并且不需要任何监督,所有这些都不需要配置。部署到 Vercel 需要我们先在项目根目录创建 deploy-vercel.sh 文件:!/bin/sh# Install denocurl -fsSL https://deno.land/x/install/install.sh | sh# Install pagic/vercel/.deno/bin/deno install --unstable --allow-read --allow-write --allow-net https://deno.land/x/pagic/mod.ts# Pagic build/vercel/.deno/bin/deno run --unstable --allow-read --allow-write --allow-net --allow-run https://deno.land/x/pagic/mod.ts build然后在项目根目录创建 package.json :{    "scripts": {        "deploy:vercel": "sh deploy-vercel.sh"    }}Vercel 支持 Github、GitLab、Bitbucket 等方式进行登录:我使用 Github 比较多,因此我在Github 上新建一个仓库 pagic_template :然后将本地的代码提交到 Github:接下来,在 Vercel 网站完成以下步骤:在首页点击导入项目 (Import Project)填写仓库地址,从 Github 导入要部署的仓库,点击继续配置项目信息填写项目名,框架预设默认 Other 即可打包与输出配置,构建命令: npm run deploy:vercel 输出目录: dist (也可以根据自己的配置填写)点击部署,等待部署完成即可访问 Blog目前, Pagic 支持三种主题: Default、DOC、Blog,我们尝试修改pagic.config.ts 文件开启 Pagic 的博客模式:export default {    theme: 'blog',    plugins: ['blog'],    title: 'pagic template',    description: 'Use this template to create a Pagic site with the blog theme.',    github: 'https://github.com/hu-qi/pagic_template',    blog: {        root: '/posts/',        social: {          github: 'hu-qi/pagic_template',          email: 'huqi@gpdi.com',          twitter: 'huqii',          v2ex: 'huqi',          zhihu: 'fashaoge'        }      }};在上边的代码中,我们为博客配置了 Title、description等参数,其中 social ,可配置我们的社交账号,默认支持 Github、Email、Twitter、V2ex、Zhihu,当然您也可以自己开发主题或者插件来自定义您想要的。接着我们开始完善博客中常用到的导航、分类、标签、外链等,这时我们需要添加一些目录,如about、archive、links等等,为了统一管理,我们将这些文件夹全部放置在 src目录下,我们的目录结构如下:site                          ├─ dist                       // output   ├─ src                        // input│  ├─ about                   │  │  └─ README.md            │  ├─ archives                │  │  └─ README.md            │  ├─ assets                  │  ├─ categories              │  │  └─ README.md            │  ├─ links                   │  │  └─ README.md            │  ├─ posts                   // maybe write somethings│  ├─ tags                    │  │  └─ README.md            │  └─ README.md               // homepage├─ README.md                  ├─ deploy-vercel.sh           ├─ package.json               └─ pagic.config.ts            配置方面,我们增加了 nav ,并把 srcDir 设置为 src :export default {+   srcDir: 'src',+   nav: [+       {+         text: 'Homepage',+         link: '/index.html',+         icon: 'czs-home-l',+       },+       {+         text: 'Categories',+         link: '/categories/index.html',+         icon: 'czs-category-l',+       },+       {+         text: 'Tags',+         link: '/tags/index.html',+         icon: 'czs-tag-l',+       },+       {+         text: 'About',+         link: '/about/index.html',+         icon: 'czs-about-l',+       },+       {+         text: 'Archives',+         link: '/archives/index.html',+         icon: 'czs-box-l',+       },+       {+         text: 'Friends',+         link: '/links/index.html',+         icon: 'czs-link-l',+       },+     ],}在移动端, Pagic 也有不错的体验:接着我们在 posts 目录下以markdown的形式写文章,我们可以在 .md 文件头加一些字段以便进行分类统计,如:---title: Pagic + Vercel 极速搭建个人博客author: huqidate: 2021/02/04cover: 'https://assets.vercel.com/image/upload/v1595320886/front/home/globe-texture.jpg'categories:- Blogtags:- Deno- React- Pagic- Vercel---编写一些文章之后,我们的博客看起来很丰富了!此时,我们将代码提交到远程仓库就会自动部署到 Vercal,以后,我们每写一篇文章提交到远程仓库就 Vercal 就能自动部署更新,简直太棒了!感谢多多指教: https://github/hu-qi/pagic_template公众号: 胡琦WeChat: Hugi66
  • Serverless在前端工程化的实践
    为什么要做 Serverless 平台触发这件事情的原因有两部分,第一是趋势,因为前端发展趋势使得前端工程师的工程化效率正在降低,作为基础软件团队,需要思考能否从基础软件层面解决前端的困扰,第二部分是当前前端工程师正面临服务端渲染的问题。首先说趋势,体现在整个前端发展过程中。从以前的 Web 工程师,到前端工程师的职位的出现,当时还只是逻辑分工。第三阶段是前端工程师时代,是一个前后端分离的时代。到我们目前正在处于的前后端(BFF)时代,前端工程师需要去负责部分后端的数据。甚至有些公司已经到了全栈工程师的时代,前端工程师需要负责后端所有的数据。第二阶段和第三阶段,前端人员不需要关心后端资源,只需要把自己的代码写好,由后端或者是运维帮他们去做发布。但是目前所处的阶段,前端人员是需要去关心后端数据的,将来的全栈工程师时代,他们还需要去直接从数据库里边获取 / 操作数据,这个时候我们会发现,他需要操心低层的资源,因为他需要把他的程序跑在服务端的后端,而前端工程师实际上不擅长操作和运维后端资源,因此会使得前端工程师的工程化效率降低。第二点是我们当前正在面临的问题,因为前端工程师目前在做服务端渲染(SSR),采用这个技术的时候他需要自己申请机器,自己部署,同时他还得关注机器的状态,并且他还得时常地翻阅基础设施提供一些运维指南去做运维,其实这个事情是他们很不擅长的,并且对他们来说是一个负担。同时从后端运维的视角来看,前端工程师是在浪费资源。这有两个原因,第一,很多业务属于活动类型的;第二,前端工程师在申请机器的时候,他往往按照上限来预留资源,这就导致了大量的浪费。因此这就产生了“前端工程师在浪费资源”的问题。但其实前端工程师不是故意的,因为他们不擅长运维服务器。因此我们需要解决前端工程师正在面临的痛点。从前端工程师的角度,他们的核心诉求就是只写代码,聚焦核心业务,去创造核心价值,把一些服务端后端运维的事情完全交付给基础设施去做,他们不需要去 care 这个事情。Serverless 的先进理念,其精华正是复杂度转移,使得业务人员能够聚焦他的核心场景,所以我们想打造一款 Serverless 产品,来解决前端工程师当前的困扰。如何打造 Serverless 平台 技术选型打造 Serverless 平台之前,首先要对这个目标做拆解,然后再去做产品选型、技术选型。首先看目标拆解,第一点业务层的需求是即用即上,也就是说前端他想上线一个业务,他不需要去关心太多,他想什么时候上线就可以什么时候上线;第二点就是前端工程师不想去做后端资源的运维;第三点实际上不是前端工程师的需求,而是基础设施层面的一个需求,就是尽量地能支撑好业务,同时也能够省机器省钱。这相对应的目标拆解为:即用即上——需要在技术上具备一键部署的能力;免运维——需要把具体的运维沉淀到基础设施层;节省开支——要求我们这个业务状态相对来说是无状态的,具备高弹性的能力。因此我们的 Serverless 平台要能够集成 CI/CD,同时也能够进行容器化,工作在 Kubernetes 上,具备自动扩缩容的能力。再看产品选型。既然公有云 Serverless 做得这么成熟,我们能否直接采用公有云产品来满足我们业务开发需求?我们的回答是 NO,因为我们需要去满足一些定制化的用户需求,而公有云的 Serverless 产品会受到很多资源包括使用的一些限制;第二个因素是我们的业务存在一些环境依赖,前端所依赖的一些数据库、中间件,都是运行在公司的私有云环境中,这些东西公有云环境上都没有;第三点也是追求技术自由,避免厂商锁定。 所以,我们需要在私有云平台中打造自己的 Serverless 平台。在技术选型上,我们基于三个原因选型了 Knative。底层要基于 Kubernetes: 因为数帆对 Kubernetes 的运维手段比较成熟,本身有大量的业务运行在 Kubernetes 上,我们有专业的团队来做相应的支撑。基于镜像去构建 Serverless: 因为本身的业务是比较灵活多变的,会存在一些程序启动时间比较长的业务,这种业务不是很适合 FaaS。因此我们考虑让它把整个启动过程压缩,通过镜像打包的一种方式来去解决。另外我们还要求易扩展成 FaaS。这些 Knative 都能满足。背景深厚:Knative 后面还有 Google、IBM、Redhat 这些大厂作为支撑。 平台构建轻舟 Serverless 平台设计全景图如下,从下往上有基础设施层、服务层、应用编排层和业务层。其中我们比较关注的是应用编排层和服务层。整个 Serverless 平台工作在已有的基础设施之上,并且我们通过这个 Serverless 平台后端,把它所需要的资源纳入平台组件能力,比如说 CI/CD、Knative API 网关,把这些资源结合起来,满足我们 Serverless 的具体需求。轻舟 Serverless 平台具体的构成,从下图可以看到,Serverless 的核心,我们可以理解成额外做的核心组件,包括一个 Serverless 前端控制台和一个 Serverless 后端。这个核心负责把现有的一些组件联合起来:通过 CI 去完成镜像构建的需求;通过 Knative 去做部署;通过 API 网关去做具体业务的数据链路打通;同时还需要 Gitlab 来存储代码;为了更高的开发效率,需要集成 Web IDE,这样前端开发人员可以只在一个浏览器上就完成他所有的需求;同时为了运维能力,需要去支持平台层面的日志平台,以及监控告警的平台;还需要一些预警,就是 Serverless 跑批和预警的一些组件。轻舟 Serverless 平台在这样的构成下,它具体的流程,我们从业务开发者的视角来看,业务开发者先通过 Web IDE,或者是其他的本地开发工具来完成编码,再把代码 Push 到 GitLab 上去,然后就会触发构建镜像,或者他可以选择手动触发,或者是通过命令行触发。当然这一步也可以把相关的一些资源,降级的静态资源,构建到放到对象存储里面去。Serverless 控制台构建完镜像以后,会通过 Knative 的 Service 去发布这个程序。整个发布过程它会主动地拉取刚才构建的镜像,去做应用的部署和数据链路的打通。这就完成了整个业务的一键部署。一键部署的业务流量模型,首先流量从外网打到外层的基于 Envoy 的 API 网关,API 网关会把流量发给内层的 Knative 网关。随着访问压力的增大,我们要求它能够扩容;而随着资源处在访问的低档期,为了能腾出更多的资源,我们要求它具备缩容的能力。同时这个 Serverless 平台还必须考虑,当这一部分产生了异常的情况下,是否具备降级的能力。我们通过外层的 API 网关去做降级和和静态资源的获取,通过这种方式,如果 Serverless 平台或者 Knative 这一层出了问题,用户可以一键切到已经准备好的静态资源中,不至于让业务产生异常。 产品形态的思考打造 Serverless 平台还有很多必要的考虑。首先平台构建形态方面,为了满足用户的效率需求,我们支持了 FaaS 层平台;为了满足业务复杂又多变的需求,我们支持了传统工程的形态。其中 FaaS 形态最主要的目的是让我们的业务方,特别是前端开发者,可以完全在 Web 浏览器上编码、发布,也就是说他只要身边有一台电脑,通过浏览器就可以随时随地完成他的业务目标,不需要安装一些开发环境。除了这种方式以外,考虑传统使用者的诉求,我们也支持集成到 VS Code 中,同时还支持最传统的通过命令行直接构建 FaaS 的方式,当前我们支持的还只是 Node.js,这个是属于我们用得比较多的技术栈。对于传统工程形态这种方式,Knative 当前是支持的,这种方式最主要的作用是,用户不需要学习新知识就可以直接使用 Serverless,可以像以前一样开发代码,同时它的运营实施比较灵活。一些启动过程很慢的业务,也完全可以采用传统工程形态去做,这样不至于说这类业务没有办法在这个平台上运行。所以说,我们做了这两种产品形态来满足业务方在不同状况下的使用需求。 数据路径的适配因为 Knative 网关只能通过子域名的方式去做业务区分,而我们传统业务,特别是现有的很多线上业务,往往是使用 Host+Path 这种方式去做区分的。为了满足用户的这种使用习惯,我们当然可以修改 Knative 层的开源实现,但是开源又是在不断迭代的,我们考虑再三,做了一些框架结构,通过外置的一层 API 网关去做具体的 Host+Path 的区分,然后转换成 Knative 所支持的子域名方式去做应用区分。同时,我们引入外层的 API 网关还有另一个好处,当 Knative 这一层出问题时,我们可以通过这一层网关去做灰度降级,来保证业务的稳定性。当然,加一层外置网关也会导致数据链路变长,它从外层 API 网关,到内层 Knative 网关,再到 Activator 组件,甚至到 QueueProxy,最后才到业务容器。这样会导致 QPS 比较低,这方面后文我们会给出轻舟团队具体的解决办法。 平台能力的集成平台需要的日志、监控告警、BaaS 等能力,由于轻舟平台已有现成的封装,Serverless 平台直接集成。此外,为了适应 Serverless 这种业务场景,我们额外开发了一个预警的组件,去模拟前端业务方发布一个业务,发布之后把它给部署到 Serverless 平台上,然后检查它能否很好地完成扩缩容。Knative 的实践踩坑和优化接下来分享在打造轻舟 Serverless 平台的过程中,我们对选型的 Knative 这个开源组件所做的事情,主要分为三个部分,第一部分是我们在数据面上做了哪些东西,第二部分是我们在控制面做了哪些优化,第三部分是说使用了 Knative 组件,我们遇到了哪些问题,又是如何解决的。 数据面的优化我们在数据面做的主要工作是数据链路调优。上文也提到 Knative 整个数据链路比较长,我们通过对 Knative 的压测,确定 Knative 的性能有很大的问题。我们通过以下的 5 个步骤来做优化:在整个的数据路径上,把 Activator 从数据路径上去除,因为我们是面向 Web 场景,去除之后不会产生任何业务问题。把 Knative 做升级,从以前的 0.9 升级到 0.14。通过 1 和 2,整个 QPS 提升了大概 50%。为了满足我们一些核心业务对延迟或者是对高性能的需求,我们采用 Fast HTTP 优化了 QueueProxy,把 QueueProxy 的 CPU 使用率降了 50%,同时在降低 CPU 使用率的情况下,它的延迟也降了 30% 左右,QPS 也提升了 30%,也就说使用更少的 CPU,反而带来更多的 QPS 和更低的延迟效果。同时我们做了一个 Revision Deployment 级别的灰度,来降低修改 QeueuProxy 带来的业务风险。在第 3 步优化完 QueueProxy 以后,我们引入了的 Sockops 组件来做框架优化,通过 eBPF 技术实现 QueueProxy 和业务容器之间的 Sidecar 方式的链路优化,QPS 可以在之前的基础上再额外提升 20%,同时延迟降低 8% 左右。针对一些特殊业务需求,我们选型更高性能的容器网络,叫 SR-IOV 网络,来满足它的需求。从我们的实测来看,SR-IOV 容器网络在延迟方面比普通的容器网络大概要降低 10%,同时它的 QPS 是接近物理机的。通过这 5 个步骤,我们满足了不同的业务方的需求。一般来讲,做完 1 和 2 能满足差不多满足一半的业务需求,做完 3 和 4 基本上能满足绝大部分需求,第 5 步是满足一些特殊的业务场景的需求。 控制面的优化控制面上我们主要解决了 Knative ksvc Ready 时间变长的问题。Knative ksvc Ready 时间变长有两个原因。第一个原因是 Serverless Knative 网关,我们采用的是轻舟的 API 网关,它的控制面是依赖于 Pilot,而我们的业务集群又是和服务网格在一起运行的,在默认情况下,Knative 的 Pilot 能感知到服务网格的 VS、DR、SE 这些资源,这就导致了它去做一些无关的资源运算,从而 Knative ksvc Ready 时间变长。第二原因,Knative 有一个组件叫做 network-istio,这个组件需要对整个数据路径去做健康检查,只有在健康检查成功以后它才把 ksvc 置成 Ready 状态。但健康检查有一个特点,它是指数级别回退的,这就导致了如果 5 秒内它没有检查通过,它就只能在 10 秒内才能发现这个东西是健康的;如果它在 10 秒内还没有解决这个问题,检查出来业务已经 Ready 了,它就只能在 20 秒内才能发现业务已经 Ready,这就导致 ksvc Ready 时间变得更长。我们解决的办法有两种,第一种是针对于第一个问题,Knative 网关它只 care 自己的 Namespace 级别的资源,去做一些资源隔离,它不 care 同一个集群内的服务网格的相关的其他资源。第二种就是我们调整了 network-istio 健康检查回退机制,调整成前 20 秒内每秒钟检查一次,20 秒以后才进行指数级回退,通过这种方法防止 ksvc Ready 时间慢的问题。 遇到的困难和解法Knative 层我们主要遇到了如下的困难:Knative 的一个 Autoscaler 组件,它是不支持 HA 的,但是 Knative Autoscaler 组件是扩缩容的核心组件,因此这是业务无法忍受的。一个老生常谈的冷启动问题,我们经过实测,整个的冷启动过程需要 5 秒以上,如果算上拉镜像的时间,甚至可能需要 6~7 秒。做 Knative 适配的时候,和我们内部的容器网络有些冲突,它会导致 Knative 的一些 Webhook 启动失败。适配轻舟 API 网关的时候出现 503 问题。net-isito 组件做完健康检查以后它的连接不会释放,这就导致它的连接大量的堆积,最终导致业务异常。我们的解法如下:针对 Autoscaler 不支持 HA 的问题,我们通过 Pick Knativ0.19 这个版本的一些代码去解决。针对冷启动,我们通过一些预留和一个默认实例来避免冷启动。Webhook 这个问题,最主要是和我们内部容器网络的冲突,我们通过调整网络方式为 hostNetwork 来规避。适配轻舟 API 网关出现 503,最主要也是 Knative 本身的一些问题,因为网关的控制面上存在一些特殊符号,它没有办法识别,这种情况下 0.14 版本的 Network-isito 就没有办法继续往下工作,不过这个问题在 Knative0.15 得到了修复。健康检查连接不释放,这也在 Knative 0.15 得到了解决。当然我们在一开始踩这个坑的时候,Knative 社区还没有解决这些问题,后面我们解决完问题以后,发现社区也已经解决了。所以说我们也是通过检验了,因为我们是尽量地少动 Knative 本身的代码,也是通过这种升级的方式来解决的。    收益    目前轻舟 Serverless 平台在内部已经上线了大概 200 多个前端应用,当然在 2020 年的 Q4 我们也 Release 了一个商业化版本满足对外的需求。我们做完这个事情以后,前端人员的体验是怎么样的呢?首先,我们从前端人员那边收集到的数据,他们以前去部署环境,新员工可能要两周左右,老员工也要三天左右,有了 Serverless 平台,整个部署时间统一降低到三分钟内搞定。其次,因为 Serverless 平台的一些封装使得了前端人员不再需要关注后端资源,所以说他们从业务选型上,可以考虑一些服务端渲染的技术来提升业务的首屏体验。再次,从趋势上来说,免去运维的困扰更加符合前端趋势,这让前端人员可以轻松地去开发 BFF 层的一些需求,甚至可以支撑他们往全栈工程师去过渡,通过这些支持给前端提供一个更大的灵活度。未来展望展望未来,我们需要在公司内部业务场景继续打磨轻舟 Serverless 平台,让它变得更加稳定,功能更加强大,主要聚焦三个方面:首先我们会提升 Serverless 平台的产品能力,考虑使用 Knative 的 Eventing 组件,去融合我们的轻舟中间件、对象存储这些底层设施的资源,来满足业务更加多变的需求。其次是我们 Serverless 平台上线以后,前段时间业务方反馈它整个的调试化过程的效率降低了,所以我们打算提供一些本地的调试套件去解决调试的困扰。最后,我们会紧跟着 Knative 社区,关注 Knative FaaS Kn 的实现,同时也考虑去对接公有云的一些 Serverless Framwork,一些 API 规范标准,这样将来如果业务方有需求,它完全可以无感地从私有云平台上迁到公有云平台上,所以我们打算做这么一层封装。