Serverless 工程实践 | Serverless 应用开发观念的转变
Serverless
共 7467字,需浏览 15分钟
·
2021-09-18 00:30
作者 | 刘宇(江昱)
Serverless 应用开发观念的转变
f = request.files['file']
f.save('my_file_path')
一般情况下,一些云平台的API网关触发器会将二进制文件转换成字符串,不便直接获取和存储; 一般情况下,API 网关与 FaaS 平台之间传递的数据包有大小限制,很多平台限制数据包大小为 6MB 以内;
FaaS 平台大多是无状态的,即使存储到当前实例中,也会随着实例释放而使文件丢失。
在 Serverless 架构下文件上传文件示例
AccessKey = {
"id": '',
"secret": ''
}
OSSConf = {
'endPoint': 'oss-cn-hangzhou.aliyuncs.com',
'bucketName': 'bucketName',
'objectSignUrlTimeOut': 60
}
#获取/上传文件到OSS的临时地址
auth = oss2.Auth(AccessKey['id'], AccessKey['secret'])
bucket = oss2.Bucket(auth, OSSConf['endPoint'], OSSConf['bucketName'])
#对象存储操作
getUrl = lambda object, method: bucket.sign_url(method, object, OSSConf['object
SignUrlTimeOut'])
getSignUrl = lambda object: getUrl(object, "GET")
putSignUrl = lambda object: getUrl(object, "PUT")
#获取随机字符串
randomStr = lambda len: "".join(random.sample('abcdefghijklqrstuvwxyz123456789
ABCDEFGZSA' * 100, len))
#文件上传
# URI: /file/upload
# Method: POST
'/file/upload', "POST") .route(
def postFileUpload():
try:
pictureBase64 = bottle.request.GET.get('picture', '').split("base64,")[1]
object = randomStr(100)
with open('/tmp/%s' % object, 'wb') as f:
f.write(base64.b64decode(pictureBase64))
bucket.put_object_from_file(object, '/tmp/%s' % object)
return response({
"status": 'ok',
})
except Exception as e:
print("Error: ", e)
return response(ERROR['SystemError'], 'SystemError')
@bottle.route('/file/upload/url', "GET")
def getFileUploadUrl():
try:
object = randomStr(100)
return response({
"upload": putSignUrl(object),
"download": 'https://download.xshu.cn/%s' % (object)
})
except Exception as e:
print("Error: ", e)
return response(ERROR['SystemError'], 'SystemError')
<div style="width: 70%">
<div style="text-align: center">
<h3>Web端上传文件</h3>
</div>
<hr>
<div>
<p>
方案1:上传到函数计算进行处理再转存到对象存储,这种方法比较直观,问题是 FaaS 平
台与 API 网关处有数据包大小上限,而且对二进制文件处理并不好。
</p>
<input type="file" name="file" id="fileFc"/>
<input type="button" onclick="UpladFileFC()" value="上传"/>
</div>
<hr>
<div>
<p>
方案2:直接上传到对象存储。流程是先从函数计算获得临时地址并进行数据存储(例如将
文件信息存到 Redis 等),然后再从客户端将文件上传到对象存储,之后通过对象
存储触发器触发函数,从存储系统(例如已经存储到 Redis)读取到信息,再对图
像进行处理。
</p>
<input type="file" name="file" id="fileOss"/>
<input type="button" onclick="UpladFileOSS()" value="上传"/>
</div>
</div>
function UpladFileFC() {
const oFReader = new FileReader();
oFReader.readAsDataURL(document.getElementById("fileFc").files[0]);
oFReader.onload = function (oFREvent) {
const xmlhttp = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new
ActiveXObject("Microsoft.XMLHTTP"))
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
alert(xmlhttp.responseText)
}
}
const url = "https://domain.com/file/upload"
xmlhttp.open("POST", url, true);
xmlhttp.setRequestHeader("Content-type", "application/json");
xmlhttp.send(JSON.stringify({
picture: oFREvent.target.result
}));
}
}
function doUpload(bodyUrl) {
const xmlhttp = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new Active
XObject("Microsoft.XMLHTTP"));
xmlhttp.open("PUT", bodyUrl, true);
xmlhttp.onload = function () {
alert(xmlhttp.responseText)
};
xmlhttp.send(document.getElementById("fileOss").files[0]);
}
function UpladFileOSS() {
const xmlhttp = window.XMLHttpRequest ? (new XMLHttpRequest()) : (new Active
XObject("Microsoft.XMLHTTP"))
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
const body = JSON.parse(xmlhttp.responseText)
if (body['url']) {
doUpload(body['url'])
}
}
}
const getUploadUrl = 'https://domain.com/file/upload/url'
xmlhttp.open("POST", getUploadUrl, true);
xmlhttp.setRequestHeader("Content-type", "application/json");
xmlhttp.send();
}
通过上表可以明确看出合理、适当地拆分业务会在一定程度上节约成本。上面例子的成本节约近 50%。
新书推荐
Serverless 工程实践系列
评论