作为一个解决方案架构师,我每天的工作几乎都会用到函数计算,用其来自动检测Web应用的一些页面数据、定时任务、视频转换等等。那么说到函数计算,大家是否能够清晰的说出函数计算是什么,用其来做什么呢?
首先让我们首先来明确一下函数计算的概念,按照阿里云官方网站对于函数计算3.0的一个个产品简介:
“函数计算是事件驱动的全托管计算服务。使用函数计算,您无需采购与管理服务器等基础设施,只需编写并上传代码或镜像。函数计算为您准备好计算资源,弹性地、可靠地运行任务,并提供日志查询、性能监控和报警等功能。”
这里我们提取关键点:无需管理基础设施,专注于代码、业务
那么,在阿里云官网也提供了这样一个步骤图例用以说明,这5个步骤很清晰的描述出了,开发者使用函数计算的一个流程。
图片援引于阿里云函数计算帮助文档
解说视频(更精彩更细致更丰富)
从新出发,特性一览
特性研究(关键点)
一级实体不套娃
因为作者本人是亚马逊云科技合作伙伴的SA,那么在工作和日常生活中会经常用到函数计算,在亚马逊云科技的Lambda服务(函数计算),函数就直接是一个实体。反观阿里云方面,在函数计算3.0以前,咱们使用函数计算是需要先创建服务,然后再去服务中创建函数,一个服务中可容纳多个函数,函数并非一级实体。那么本次函数计算3.0的一个更新,可以说是在一定程度上真正的达到了函数计算的一个点。
全村希望:FAAS-->角色和工作负载绑定
还记得我第一次使用阿里云函数计算的时候,因为自己的云技术栈主要是在亚马逊云科技,对于函数计算的授权这块习惯了直接将函数和相关权限的角色绑定,在使用阿里云函数计算的时候,查阅了文档比较惊讶的就是并不支持,于是就直接在函数计算的代码中定义AK、SK,那么这样我觉得在云上来做这种操作是有点难受了,从另一个角度来分析,就是云平台的服务并没有很好的一个整合。那么现如今函数计算3.0终究是弥补上这个缺点,函数计算3.0现已支持SLR(服务关联角色),让开发者可以在使用函数计算服务的时候更好的去调用阿里云的其他服务。
说到这里,也是在无意间看到一篇文章《云厂商眼中的客户:又穷又闲又缺爱》,个人感觉得到似乎作者是将国内的云厂商骂了各遍,当然重点不在于此,重要的是文中提到的【阿里云不支持角色和工作负载绑定】,我发现文章这里有写错,在观察到阿里云函数计算3.0的帮助文档更新时间为2023年10月7日,而这里提到的文章发布时间为2023年11月6日,其间一个月的时间,还出现这样的错误,确实是有点。。。。
截图来自文章【云厂商眼中的客户:又穷又闲又缺爱】
案例分享
多线程解压OSS大文件
当发布网页游戏、静态资源时,通常会使用OSS来存放游戏中的静态资源。这些静态资源数量可达成千上万,如果直接从本地同步这么多文件到OSS,势必会花费较长的时间。
为了优化这个过程,我们可以考虑先将所有静态资源打包成一个 ZIP 文件,然后上传到OSS。ZIP 文件体积较小,上传速度会快很多。上传完成后,我们可以触发函数计算服务,自动解压该 ZIP 文件,并将文件上传回指定的 OSS。这种方式可以大大缩短整体的一个业务流程。
在阿里云官方案例提供的一个《使用函数计算实现自动解压上传到OSS的ZIP文件》,我觉得这个可以拿出来讲讲,官方提供的一个案例,我感觉是有一点缺陷的
下面分别为阿里云和亚马逊云提供的一个方案,两者的差异就在于,函数计算解压后,对加压后的数据是否利用了函数多线程的一个形式传递给存储桶。
阿里云方案
亚马逊云科技方案
加入多线程后代码(也许有瑕疵)
# -*- coding: utf-8 -*- ''' 声明: 这个函数针对文件和文件夹命名编码是如下格式: 1. mac/linux 系统, 默认是utf-8 2. windows 系统, 默认是gb2312, 也可以是utf-8 对于其他编码,我们这里尝试使用chardet这个库进行编码判断,但是这个并不能保证100% 正确, 建议用户先调试函数,如果有必要再改写函数,并保证调试通过。 Statement: This function names and encodes files and folders as follows: 1. MAC/Linux system, default is utf-8 2. For Windows, the default is gb2312 or utf-8 For other encodings, we try to use the chardet library for coding judgment here, but this is not guaranteed to be 100% correct. If necessary to rewrite this function, and ensure that the debugging pass ''' import helper import oss2 import json import os import time import logging import chardet import concurrent.futures """ When a source/ prefix object is placed in an OSS, it is hoped that the object will be decompressed and then stored in the OSS as processed/ prefixed. For example, source/a.zip will be processed as processed/a/... "Source /", "processed/" can be changed according to the user's requirements. """ # Close the info log printed by the oss SDK logging.getLogger("oss2.api").setLevel(logging.ERROR) logging.getLogger("oss2.auth").setLevel(logging.ERROR) LOGGER = logging.getLogger() # a decorator for print the excute time of a function def print_excute_time(func): def wrapper(*args, **kwargs): local_time = time.time() ret = func(*args, **kwargs) LOGGER.info('current Function [%s] excute time is %.2f' % (func.__name__, time.time() - local_time)) return ret return wrapper def get_zipfile_name(origin_name): # 解决中文乱码问题 name = origin_name try: name_bytes = origin_name.encode(encoding="cp437") except: name_bytes = origin_name.encode(encoding="utf-8") # the string to be detect is long enough, the detection result accuracy is higher detect = chardet.detect(name_bytes) confidence = detect["confidence"] detect_encoding = detect["encoding"] if confidence > 0.75 and (detect_encoding.lower() in ["gb2312", "gbk", "gb18030", "ascii", "utf-8"]): try: if detect_encoding.lower() in ["gb2312", "gbk", "gb18030"]: detect_encoding = "gb18030" name = name_bytes.decode(detect_encoding) except: name = name_bytes.decode(encoding="gb18030") else: try: name = name_bytes.decode(encoding="gb18030") except: name = name_bytes.decode(encoding="utf-8") # fix windows \\ as dir segment name = name.replace("\\", "/") return name @print_excute_time def handler(event, context): """ The object from OSS will be decompressed automatically . param: event: The OSS event json string. Including oss object uri and other information. For detail info, please refer https://help.aliyun.com/document_detail/70140.html?spm=a2c4g.11186623.6.578.5eb8cc74AJCA9p#OSS param: context: The function context, including credential and runtime info. For detail info, please refer to https://help.aliyun.com/document_detail/56316.html#using-context """ evt_lst = json.loads(event) creds = context.credentials auth = oss2.StsAuth( creds.access_key_id, creds.access_key_secret, creds.security_token) evt = evt_lst['events'][0] bucket_name = evt['oss']['bucket']['name'] endpoint = 'oss-' + evt['region'] + '-internal.aliyuncs.com' bucket = oss2.Bucket(auth, endpoint, bucket_name) object_name = evt['oss']['object']['key'] if "ObjectCreated:PutSymlink" == evt['eventName']: object_name = bucket.get_symlink(object_name).target_key if object_name == "": raise RuntimeError('{} is invalid symlink file'.format( evt['oss']['object']['key'])) file_type = os.path.splitext(object_name)[1] if file_type != ".zip": raise RuntimeError('{} filetype is not zip'.format(object_name)) LOGGER.info("start to decompress zip file = {}".format(object_name)) lst = object_name.split("/") zip_name = lst[-1] PROCESSED_DIR = os.environ.get("PROCESSED_DIR", "") RETAIN_FILE_NAME = os.environ.get("RETAIN_FILE_NAME", "") if PROCESSED_DIR and PROCESSED_DIR[-1] != "/": PROCESSED_DIR += "/" if RETAIN_FILE_NAME == "false": newKey = PROCESSED_DIR else: newKey = PROCESSED_DIR + zip_name zip_fp = helper.OssStreamFileLikeObject(bucket, object_name) newKey = newKey.replace(".zip", "/") with helper.zipfile_support_oss.ZipFile(zip_fp) as zip_file: with concurrent.futures.ThreadPoolExecutor() as executor: futures = [] for name in zip_file.namelist(): with zip_file.open(name) as file_obj: name = get_zipfile_name(name) new_object_key = newKey + name futures.append(executor.submit(bucket.put_object, new_object_key, file_obj)) # 等待所有任务完成 concurrent.futures.wait(futures)
总结
先说优点,自古以来都说伸手不打笑脸人
- 有实例的概念,我认为萝卜白菜各有所爱,利好--方便调试
- IDE有Terminal提供,在调试的时候不用层就可以很方便的调试代码
- 函数运行资源更大。环比友商亚马逊云科技的Lambda服务,那么阿里云函数计算3.0能提供最大32GB单个函数的内存量,亚马逊云科技的lambda服务单个函数最大10GB,三倍还多的一个差距,没得说的完胜
建议
在试用函数计算3.0的过程中,我的确感受到了函数计算3.0的一些便捷之处,但是从个人角度和使用习惯上来看,存在一些问题,也是可以在对比友商方面来讲,咱们阿里云是否可以基于以下提出的建议来改进?
- 云平台服务的配套时效性。就拿负载均衡器来讲,是有函数计算可以作为目标组,但是在实际使用中仍旧保持使用函数计算2.0。(亦或者是因为函数计算3.0在测试中?)
- 实例可见性。对于函数计算-Serverless,不再关心底层基础设施,应该是不可见实例,也应该淡化实例的概念。
- 函数域名。这块应该在3.0中单独呈现出来,在每个函数中设置一个类似于“函数URL”的一个样子。当然也许函数域名在高级功能中统一设置是为了便捷性。
- 成本方面。我相信有一部分客户是对于成本较为敏感的,亦或者是就是为了成本才选择使用函数计算服务,那么我们如何去把控成本,或者是说我们如何去从业务方面选择/计算最佳的一个CPU、内存,以达到性价比最高的一个状态,在友商亚马逊云科技方面,有一个叫做“Lambda power tuning”的方案,可以帮助客户找到运行函数最佳性价比。那么阿里云方面是否也可以对标亚马逊云科技为客户推出同类或者更优质的功能/方案?
- 函数并发。跟阿里云函数计算的工程师了解后,函数计算3.0对于并发量是针对于单个函数按量和预留合并,这点和2.0不同,但是地域总量仍旧是300。如果客户的一个场景是小规格大并发呢?是否默认的300其实并不合理?
- 日志调试。是否也可以参照友商给日志这块较大的一个麻烦额度,在调试函数计算3.0的时候更加的方便?