从传统的服务器到近年风生水起的云服务器微服务架构,再到无服务器(Serverless)架构,开发者们的探索之路永不停歇!
虽然各家的名称都不一样,但总体来说都是基于FaaS(Function as a Service),所有的事情都是基于函数去做。
它可以结合API网关来调用,进而达到传统服务器的功能。
优点
- 不需要管理,优化服务器,什么弹性伸缩,负载均衡都不用自己去做。
- 相对安全,可靠,因为这些事情都由产商来完成。
- 可用度高,触发执行,有需要的时候才会执行,空闲0成本。
- 开发者可以只关注业务逻辑,其它的一概不管。
由于买了腾讯的云服务器,顺带就试了一下如何创建腾讯分无服务器云函数。
支持的语言有:Python2.7
, Python3.6
, Nodejs6.10
, Nodejs8.9
, Java8
, Php5.6
, Php7.2
, Golang1
开发步骤:
- 在
无服务器云函数
控制台新建函数服务。 - 上传自己的代码(jar或zip)。
- 测试
注意事项:
- Java版本是8.0
- Java执行方法格式为:
[package].[class]::[method]
,注意包名只能是一级,还不支持多级包名(好像有坑,😁)。 - 日志:
System.out.print
就可以,或者使用java.util.logging
,由于无法联调,日志信息很重要。
Demo
public class Function {
public String handle(Input input) {
System.out.println("-----------------");
System.out.println("Input: " + input);
if (input == null || input.getName() == null) {
return "发生错误";
}
String result = input.getName().toUpperCase();
System.out.println("Result: " + result);
return result;
}
}
public class Input {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试模板:
{"name":"abcd"}
日志:
START RequestId: f389b1c9-edff-11e8-b97c-525400c7c826
Event RequestId: f389b1c9-edff-11e8-b97c-525400c7c826Event:{
"name": "abcd"
}
-----------------
Input: demo.Input@4de8b406
Result: ABCD
END RequestId: f389b1c9-edff-11e8-b97c-525400c7c826
Report RequestId: f389b1c9-edff-11e8-b97c-525400c7c826 Duration:854.408ms Memory:128MB MaxMemoryUsed:31.168MB
说实话腾讯云的bug还真不少,网页控制台里面居然没有String类型的模板,非得用JSON,😁。 不过也好,像这样简单的例子实际中也不存在。
编写函数代码总结
一,事件入参(函数中的第一个变量)
- Java基础类型包括String
- POJO类型,必须有公有getter和setter方法。
二,Context入参(函数中的第二个变量为Context类型)
import com.qcloud.scf.runtime.Context
...
public String handle(Input input, Context context) {
//
}
Context是什么?每家的函数服务都会传一个Context参数进去,一般是这个函数相关的一些变量,如名称,内存配置等,有些也会直接传一个logger对象进去, 腾讯云的Context现在还比较鸡肋:
package com.qcloud.scf.runtime;
public abstract interface Context {
public abstract String getRequestId();
public abstract int getTimeLimitInMs();
public abstract int getMemoryLimitInMb();
// public abstract String getFunctionName();
// public abstract String getFunctionVersion();
// public abstract String getMemoryLimitInMb();
// public abstract String getTimeLimitInMs();
// public abstract String getLogGroupName();
// public abstract String getLogStreamName();
}
三,返回结果可以是Java基础类,String和POJO。
四, Maven打包,需要用shade插件将所有jar包打到一起
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
SDK的使用
腾讯云SDK在Github上有源码开发,是已经封装好了的API,也可以通过Maven来引用:
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.0.29</version>
</dependency>
首先:实例化认证对象,需要腾讯云账户secretId
和secretKey
// 实例化一个认证对象,入参需要传入腾讯云账户secretId,secretKey
Credential credential = new Credential(secretId, secretKey);
ClientProfile profile = new ClientProfile(ClientProfile.SIGN_SHA256);
ScfClient scfClient = new ScfClient(credential, region, profile);
然后通过:CreateFunctionRequest
,DeleteFunctionRequest
,ListFunctionsRequest
等进行函数的创建,删除等操作。
CreateFunctionRequest createRequest = new CreateFunctionRequest();
if (uploaded) {
Code code = new Code();
code.setCosBucketName(function.getBucket().getName());
code.setCosBucketRegion(function.getBucket().getRegion());
code.setCosObjectName(functionName);
createRequest.setCode(code);
}
createRequest.setDescription(function.getDescription());
createRequest.setRuntime(RUNTIME);
createRequest.setFunctionName(functionName);
createRequest.setHandler(handler);
try {
scfClient.CreateFunction(createRequest);
} catch (TencentCloudSDKException e) {
throw e;
}
源码上传
源码上传有2中方式:
- 直接将打好的jar包或zip包通过网页控制台上传。
- 通过COS(腾讯云对象存储)上传。 通过COS上传,首先要把你的jar包或zip包上传到对象存储,然后在控制台中进行关联就可以了
注意的一点: 通过SDK+COS上传代码的时候,COS的bucketName
不要带后面的appid
,一般情况下载对象存储中名称是有[name]-[appid]
组成的。
上传的代码如下:
COSCredentials cred = new BasicCOSCredentials(function.getSecretId(), function.getSecretKey());
ClientConfig clientConfig = new ClientConfig(new Region(bucketRegion));
COSClient cosClient = new COSClient(cred, clientConfig);
if (!cosClient.doesBucketExist(bucketName)) {
CreateBucketRequest request = new CreateBucketRequest(bucketSimpleName);
cosClient.createBucket(request);
cosClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
} else {
cosClient.putObject(bucketName, function.getName(), mavenProject.getArtifact().getFile());
}
cosClient.shutdown();
注意:这里的bucketName一定要是全名:([name]-[appid]
)。
但是如果用SDK更新云函数:一定记得不要带[appid]
,只使用前面的[name]
作为bucketName
。
Credential credential = new Credential(secretId, secretKey);
ClientProfile profile = new ClientProfile(ClientProfile.SIGN_SHA256);
ScfClient scfClient = new ScfClient(credential, region, profile);
UpdateFunctionCodeRequest updateCodeRequest = new UpdateFunctionCodeRequest();
updateCodeRequest.setFunctionName(functionName);
updateCodeRequest.setHandler(handler);
updateCodeRequest.setCosBucketName(bucketName);
updateCodeRequest.setCosBucketRegion(bucketRegion);
updateCodeRequest.setCosObjectName(objectName);
scfClient.UpdateFunctionCode(updateCodeRequest);
曾经因为这个问题,提了工单进行了好多次的重试。切记!