玩转阿里云函数计算(一)----Java Http 触发器极速迁移传统 Spring 应用

本文涉及的产品
简介: 前言 阿里云函数计算 Function Compute(FC),旨在帮助用户采用弹性伸缩、动态分配资源的方式,来执行业务函数。让用户无需购买部署服务器,无需考虑业务负载,就能快速搭建可处理高并发的后台服务。

前言

阿里云函数计算 Function Compute(FC),旨在帮助用户采用弹性伸缩、动态分配资源的方式,来执行业务函数。让用户无需购买部署服务器,无需考虑业务负载,就能快速搭建可处理高并发的后台服务。
函数计算平台针对 Java 语言推出的 Java HTTP 触发器功能,能够无缝迁移传统的 Java Web 应用。支持基于 Servlet 协议的 Web 框架所开发的应用,比如常用的 Spring、SpringBoot、Struts2等。
本文介绍如何使用 Java HTTP 触发器来快速迁移 Spring 提供的开源 Web 项目 GreenHouse

相关链接

开始迁移

Java HTTP 触发器使用示例代码

一、打包需要迁移的 Web 工程为 war 包

可以使用已编译好的 greenhouse.war,本步骤可直接跳过

  1. GreenHouse github 上下载 Web 工程源码。
  2. 在源码根目录执行 maven 打包命令 maven clean package -DskipTests

注意 GreenHouse 使用的 JDK 版本是1.6,比较老。这里打包前需要修改下 pom.xml 为你使用的 JDK 版本。
image

打包成功后,在 target 目录下能看到 greenhouse-1.0.0.BUILD-SNAPSHOT.war 这个文件。最后为了方便将该 war 包重命名为 greenhouse.war

二、在函数计算平台创建 Java 函数

将要运行的应用 war 包可以和函数代码一起打包上传,也可以放在网络存储中比如 阿里云对象存储(OSS),或者任何其它的网络存储。以下示例将应用 war 包放在函数代码工程中和存储到 OSS 中两种方式。

方式一:应用 war 包放在函数代码工程

  1. 在本地创建 maven 工程,并创建一个 package 比如 com.aliyun.fc.example,在 package 中添加 Java 类 HelloWebLocal.java:

    public class HelloWebLocal implements FunctionInitializer, HttpRequestHandler {
        private FcAppLoader fcAppLoader = new FcAppLoader();
    
        private String key = "greenhouse.war";
        private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
      
        @Override
        public void initialize(Context context) throws IOException {
            FunctionComputeLogger fcLogger = context.getLogger();
          
            fcAppLoader.setFCContext(context);
          
            // Set war file path
            fcAppLoader.loadCodeFromLocalProject(key);
          
            // Init webapp from code
            long timeBegin = System.currentTimeMillis();
            fcLogger.info("Loading webapp: " + key);
            boolean initSuccess = fcAppLoader.initApp(userContextPath, HelloWebOSS.class.getClassLoader());
            if(! initSuccess) {
                throw new IOException("Init web app failed");
            }
            fcLogger.info("Loaded webapp, elapsed: " + (System.currentTimeMillis() - timeBegin) + "ms");
        }
      
        @Override
        public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context)
                throws IOException, ServletException {
            try {
                fcAppLoader.forward(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    其中引用的 maven 库:

    <dependency>
       <groupId>com.aliyun.fc.runtime</groupId>
       <artifactId>fc-java-core</artifactId>
       <version>1.3.0</version>
      </dependency>
    
    <dependency>
       <groupId>com.aliyun.fc.runtime</groupId>
       <artifactId>fc-java-common</artifactId>
       <version>1.0.0</version>
      </dependency>
  2. 将 greenhouse.war 拷贝到 Java 工程中,上述代码中 loadCodeFromLocalProject 方法参数为 greenhouse.war 文件在工程中的相对路径。比如放在 src/main/resources 目录,那就和上述代码保持一样,否则改成对应的相对路径。

方式二:应用 war 包存储到 OSS 中

如果将 war 包放在创建函数的 Java 工程中,会增加创建函数时上传的代码包大小。对于代码包大小函数计算有限制最大为 50M ,请参考函数计算使用限制。往往 Java 的 web 应用 war 包会比较大,因而更好的方式是将 war 包放在 OSS 中,然后通过初始化函数 initializer 来下载 war 包到执行环境中。同样可以调用 fc-java-common 库中的 loadCodeFromOSS 方法即可,该方法会将对应的 war 包下载到执行环境的临时磁盘目录 /tmp 中。

  1. 将 greenhouse.war 上传到 OSS 中
  2. 方式一创建 maven 工程以及 Java package,并创建 HelloWebOSS.java:

    public class HelloWebOSS implements FunctionInitializer, HttpRequestHandler {
        private FcAppLoader fcAppLoader = new FcAppLoader();
    
        private String ossEndPoint = "${YourOSSEndpoint}";
        private String bucket = "${YourOSSBucket}";
        private String key = "greenhouse.war";
        private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
      
        @Override
        public void initialize(Context context) throws IOException {
            FunctionComputeLogger fcLogger = context.getLogger();
          
            fcAppLoader.setFCContext(context);
          
            // Load code from OSS
            fcLogger.info("Begin load code: " + key);
            boolean codeSuccess = fcAppLoader.loadCodeFromOSS(ossEndPoint, bucket, key);
            if (! codeSuccess) {
                throw new IOException("Download code failed");
            }
            fcLogger.info("End load code");
          
            // Init webapp from code
            long timeBegin = System.currentTimeMillis();
            fcLogger.info("Begin load webapp");
            boolean initSuccess = fcAppLoader.initApp(userContextPath, HelloWebOSS.class.getClassLoader());
            if(! initSuccess) {
                throw new IOException("Init web app failed");
            }
            fcLogger.info("End load webapp, elapsed: " + (System.currentTimeMillis() - timeBegin) + "ms");
        }
      
        @Override
        public void handleRequest(HttpServletRequest request, HttpServletResponse response, Context context)
                throws IOException, ServletException {
            try {
                fcAppLoader.forward(request, response);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

函数计算平台创建函数

关于怎么在函数计算平台创建函数请参考: Hello World 示例
关于怎么使用 Java 语言请参考:Java 运行环境

将上述的 maven 工程打包,并在函数计算平台创建服务和函数,这里需要注意的点:

  1. 需要将您创建的服务名和函数名,填充到上述 HelloWebLocal.java 中:

    private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
  2. 如果您使用的是 OSS 存储方式,需要填充 OSS 相关信息到 HelloWebOSS.java 中:

      private String ossEndPoint = "${YourOSSEndpoint}";
      private String bucket = "${YourOSSBucket}";
      private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";
  3. 创建函数时除了需要设置函数入口外,还需要设置初始化入口指向上述代码的 initialize 函数。
  4. Web 应用使用的内存较多,请注意函数内存大小设置,比如我这里设置的是 512M

示例配置如下:
image

为函数创建 HTTP 触发器

关于怎么创建 HTTP 触发器请参考:HTTP 触发器

测试函数运行

在函数计算控制台执行 HTTP 触发器,看到如下返回:
image

可以看到成功返回了 greenhouse 的 web 页面。
但是如果在浏览器中执行 HTTP 触发器的请求地址,web 页面将会已文件的形式下载。这是因为函数计算为了安全强制设置了请求返回的 header 为 Content-Disposition: attachment,所以返回结果会以附件形式下载。

为 HTTP 触发器绑定自定义域名

为了解决这个问题,需要用户申请自定义域名,并绑定域名解析到函数计算中,请参考函数计算绑定自定义域名
使用自定义域名访问,需要将最初的 Java 代码中 userContextPath 改为自定义域名的 contextPath 比如/ /greenhouse 等,这样才能保证页面中的超链接是相对于当前请求的域名:

// Not use custom domain
//private String userContextPath = "/2016-08-15/proxy/${YourServiceName}/${YourFunctionName}";

// Use custom domain
private String userContextPath = "/greenhouse";

自定义域名绑定到 HTTP 触发的示例配置:
image

自定义域名路径前缀必须和代码中 userContextPath 保持一致,比如这里都是 /greenhouse。当然可以选择其它的路径名,也可以使用根路径,即路径配置为 /* 对应的 userContextPath 为 /
通过修改配置路径和对应的 userContextPath,可映射到不同的 HTTP 触发器函数,从而映射到不同的 web 应用中。这样就能同一个域名同时复用到不同的 web 应用。

浏览器中访问自定义域名:
shop

大功告成!

后语

函数计算是 serverless 服务,对于传统的 Web 应用支持目前还是存在一些瑕疵。

  1. 无状态性,每次函数执行都是无状态的。对于 Web 应用往往有很多状态需要保持,比如 session,用户需要在自己的 Web 应用中去处理。当然很多 web 框架已经提供了很方便的分布式 session 方案,只需简单的配置即可,可以参考Spring Session Redis
  2. 冷启动,新的执行环境中第一次请求 web 应用会比较耗时,这是由于执行环境需要启动 JVM 以及加载 web 应用,针对这个可通过定时预热的方式来解决。

但这些相对于 serverless 提供的弹性伸缩和按需付费的优点不值一提,个人认为 serverless 必定会取代传统物理机或虚拟机的服务器方式,从而让有限的资源得到更高效的利用。

相关实践学习
基于函数计算一键部署掌上游戏机
本场景介绍如何使用阿里云计算服务命令快速搭建一个掌上游戏机。
建立 Serverless 思维
本课程包括: Serverless 应用引擎的概念, 为开发者带来的实际价值, 以及让您了解常见的 Serverless 架构模式
目录
相关文章
|
4天前
|
存储 弹性计算 监控
【阿里云弹性计算】阿里云 ECS 性能优化秘籍:提升应用响应速度与资源利用率
【5月更文挑战第22天】阿里云ECS优化涉及实例规格选择、OS与应用配置、网络配置、存储优化及数据库连接池管理。合理挑选CPU和内存,关闭无关服务,利用EIP和负载均衡优化网络,选择合适存储类型,并通过监控工具进行性能分析和压力测试,以提升响应速度,优化资源利用率,降低成本,增强企业竞争力。示例展示了Java数据库连接池配置优化。通过持续探索和实践,可最大化发挥ECS潜力。
68 7
|
1天前
|
弹性计算 监控 数据库
【阿里云弹性计算】企业级应用上云实战:基于阿里云 ECS 的 ERP 系统迁移案例
【5月更文挑战第25天】制造企业将面临资源不足、维护成本高和数据安全问题的ERP系统迁移到阿里云ECS,实现业务上云。通过数据迁移、应用部署、网络配置和性能优化等步骤,企业享受到弹性计算资源、高可靠性和数据安全优势,降低维护成本。阿里云提供24小时支持,助力企业数字化转型。此案例展示企业级应用上云的可行性,鼓励更多企业借助云计算实现创新发展。
6 0
|
2天前
|
人工智能 弹性计算 监控
【阿里云云原生专栏】阿里云云原生与AI结合:智能应用的快速构建与部署
【5月更文挑战第24天】阿里云融合云原生和AI技术,助力快速构建智能应用。弹性伸缩、CI/CD、微服务和自动化运维带来优势。通过需求分析、环境准备、数据处理、模型开发到服务部署,阿里云提供容器服务、函数计算、服务网格等工具,支持自动化测试和监控,实现一站式智能应用开发。示例代码展示创建ACK集群和部署AI模型服务过程。
226 1
|
2天前
|
运维 Cloud Native 持续交付
【阿里云云原生专栏】从零到一搭建云原生应用:阿里云云原生应用平台实战教程
【5月更文挑战第24天】本文档是一份阿里云云原生应用平台的实战教程,介绍了如何从零开始搭建云原生应用。内容涵盖云原生应用的特点(容器化、微服务、CI/CD和自动化运维)以及阿里云提供的服务,如容器服务、服务网格和CI/CD工具。教程详细讲解了创建容器集群、编写Dockerfile、构建镜像、部署应用、配置服务网格和设置CI/CD的步骤。通过本文,读者将学会利用阿里云平台开发和管理云原生应用。
220 0
|
3天前
|
运维 关系型数据库 分布式数据库
在数据库应用中遇到的问题及阿里云数据库解决方案
企业在面临数据库性能瓶颈、可扩展性问题、高可用性不足及运维复杂等挑战时,选择了阿里云数据库解决方案。阿里云RDS和PolarDB通过读写分离、自动化索引优化、多副本架构等提升性能和扩展性;多可用区部署、数据复制等增强高可用性和容灾能力;自动化运维工具简化管理,降低运维成本。实施后,性能大幅提升,可扩展性增强,高可用性提升,运维工作简化,为业务稳定和未来发展奠定基础。
29 0
|
3天前
|
存储 弹性计算 大数据
【阿里云弹性计算】阿里云ECS在大数据处理中的应用:高效存储与计算实践
【5月更文挑战第23天】阿里云ECS在大数据处理中发挥关键作用,提供多样化实例规格适应不同需求,尤其大数据型实例适合离线计算。通过集成分布式文件系统如OSS,实现大规模存储,而本地存储优化提升I/O性能。弹性扩容和计算优化实例确保高效运行,案例显示使用ECS能提升处理速度并降低成本。结合阿里云服务,ECS构建起强大的数据处理生态,推动企业创新和数字化转型。
12 0
|
5天前
|
运维 监控 JavaScript
【阿里云云原生专栏】Serverless架构下的应用部署与运维:阿里云Function Compute深度探索
【5月更文挑战第21天】阿里云Function Compute是事件驱动的无服务器计算服务,让用户无需关注基础设施,专注业务逻辑。本文详述了在FC上部署应用的步骤,包括创建函数、编写代码和部署,并介绍了运维功能:监控告警、日志管理、版本管理和授权管理,提供高效低成本的计算服务。
133 6
|
5天前
|
Cloud Native Java 关系型数据库
【阿里云云原生专栏】构建云原生应用:基于Spring Boot与阿里云服务的全栈指南
【5月更文挑战第21天】构建云原生应用是企业数字化转型的关键,本文提供了一份基于Spring Boot和阿里云的全栈指南。涵盖从阿里云账号注册、ECS与Docker搭建,到Spring Boot项目创建、业务代码编写和部署。此外,还介绍了如何集成阿里云OSS存储、RDS数据库服务以及ACK容器服务,助力打造高效、可扩展和易管理的云原生应用。
115 3
|
6天前
|
监控 负载均衡 Java
【阿里云云原生专栏】微服务架构在阿里云云原生平台上的应用实例与优化策略
【5月更文挑战第20天】本文介绍了在阿里云云原生平台实现微服务架构的步骤,包括基于Spring Cloud的Docker化部署、使用ACK部署微服务,以及优化策略:服务发现与负载均衡(借助Istio)和监控日志管理。通过这种方式,企业能提升应用的可扩展性、可维护性和敏捷性。
189 5
|
7天前
|
SQL 分布式计算 数据挖掘
阿里云MaxCompute携手华大基因打造精准医疗应用云平台,十万基因组计算成本降低至1000美金以内
华大基因是中国最领先的基因科技公司,华大基因为消除人类病痛、经济危机、国家灾难、濒危动物保护、缩小贫富差距等方面提供分子遗传层面的技术支持。让我们结合maxcompute的技术特点,看看如何助力华大基因。
809 9

热门文章

最新文章

相关产品

  • 函数计算