云引擎 Java 运行环境
这篇文档是针对 Java 运行环境的深入介绍,如希望快速地开始使用云引擎,请查看 快速开始部署云引擎应用。
云引擎目前支持使用 Maven 或 Gradle 构建出的 WAR 或 JAR 项目。也支持直接上传 WAR 包。
如果要开始一个新的项目,建议从我们的示例项目开始:
Java 对内存的需求较高,体验版实例的 256M 内存可能会导致 Java 进程启动时内存不足而崩溃(OOM)导致部署失败,或运行时内存不足而频繁重启。
我们建议 Java 项目至少选用 512 MB 以上的内存,Spring Boot 项目至少选用 1024 MB 以上的内存,并在之后的运行过程中根据内存用量统计随时调整。调整内存规格的方法详见 云引擎平台功能 § 调整实例规格和数量。
启动命令
在完成构建后,云引擎会在 target
和 build
目录下查找 .war
或者 .jar
文件:
- 如果找到
.war
会将其放入 Servlet 容器(Jetty 9.x)来运行 - 如果找到
.jar
会通过java -jar
来运行
配置 JVM 参数
云引擎运行 Java 应用时,会自动将 -Xmx
参数设置为实例规格的 70%,剩下的 30% 留给堆外内存和其他开销。如果你的应用比较特殊(比如大量使用堆外内存)可以自己定制 -Xmx
参数。假设使用 2 GB 内存规格的实例运行,则可以在云引擎的设置页面增加「自定义环境变量」,名称为 JAVA_OPTS
,值为 -Xmx1500m
,这样会限制 JVM 堆最大为 1.5 GB,剩下 500 MB 留给持久代、堆外内存或者其他一些杂项使用。注意:-Xmx
参数如果设置得过小可能会导致大量 CPU 消耗在反复的 GC 任务上。
配置 Java 版本
在项目根目录创建一个 system.properties
即可配置 Java 的版本:
java.runtime.version=11
目前云引擎支持的版本有 AdoptOpenJDK 8
、11
、12
、13
、14
。
直接上传 WAR 包
在本地构建(如使用 mvn package
)出 WAR 包后,可以在使用命令行工具部署时添加 --war
选项表示上传 WAR 包而不是源代码:
tds deploy --war
这种情况下在云端不会有安装依赖和构建的过程,WAR 包会被直接放入 Servlet 容器运行。
安装依赖和构建
如果上传了源代码,云引擎会自动安装依赖并构建。
云引擎会根据项目根目录是否存在 pom.xml
或 gradlew
文件来判断所使用的包管理器,然后使用对应的 Maven 或 Gradle 命令来安装依赖并构建。
自定义构建过程
除了默认的构建过程和运行命令外,开发者还可以在 leanengine.yaml
中进一步地调整运行命令(run
)、依赖安装命令(install
)和构建命令(build
),覆盖默认的行为:
run: echo 'run another command'
install:
- {use: 'default'}
- echo 'install additional dependencies here'
build:
- echo 'overwrite default build command here'
详细的说明见 Reference: leanengine.yaml,下面是一些具体的例子:
只上传 jar 包而不在线上进行构建
runtime: java
install: []
build: []
run: java -jar your-package.jar
在这里我们指定了使用 Java 运行时、将依赖安装和构建步骤覆盖为空,然后直接指定了运行命令(运行项目根目录下的 your-package.jar
)。
系统级依赖
在云引擎的线上环境中,开发者可以在 leanengine.yaml
中定义额外的系统级依赖:
systemDependencies:
- imagemagick
支持的完整列表见 Reference: leanengine.yaml。
构建日志
默认情况下构建过程中产生的日志不会显示到控制台,只有构建失败时,最后一个步骤的日志才会被显示在控制台上。
如需打印完整的构建日志以便调试,可以在部署时勾选「打印构建日志」或命令行工具添加参数 --options 'printBuildLogs=true'
。
健康检查
云引擎目前主要为 Web 应用优化,应用在启动后需要在环境变量 LEANCLOUD_APP_PORT
中指定的端口上提供 HTTP 服务,注意需要监听在 0.0.0.0
地址(所有接口)上,而不是一些框架默认的 127.0.0.1
。
在应用部署时,云引擎的管理程序会每隔一秒去检查应用是否启动成功,如果超过启动时间限制(默认 30 秒)仍未启动成功,即认为启动失败,部署会中止。在之后的运行过程中,也会有定期的健康检查来确保应用正常运行,如果健康检查失败,云引擎管理程序会自动重启你的应用。
健康检查会通过 HTTP 检查应用的首页(/
),如果返回 HTTP 2xx 的响应,就视作成功。
点击展开健康检查与云引擎 SDK 的关联
云引擎还会尝试检查由 SDK 处理的 /__engine/1/ping
,如果 SDK 接入正确,便不再要求首页(/
)返回 HTTP 2xx。
如果 开发者中心 > 你的游戏 > 游戏服务 > 云服务 > 云引擎 > 管理部署 > 你的分组 > 设置 > 云函数模式 设置为「开启」或 leanengine.yaml
中 functionsMode
设置为 strict
,云引擎会检查 SDK 是否被正确地接入,否则会视作启动失败。
点击展开自定义启动时长(startupTimeout
)
启动时间限制默认为 30 秒,可设置范围为 15–120 秒,如需延长或缩短,可以在 leanengine.yaml
文件中设置:
startupTimeout: 60
云端环境
绑定自定义域名
云引擎需要设置域名才能访问。在 开发者中心 > 你的游戏 > 游戏服务 > 云服务 > 云引擎 > 管理部署 > 你的分组 > 设置 > 访问域名 处可以绑定域名。
如果你绑定的域名以 stg-
开头(如 stg-api.example.com
),会自动关联到预备环境。
对于测试阶段的应用,我们提供了共享域名,你可以自定义共享域名的前缀部分。
负载均衡和加速节点
所有对云引擎的 HTTP 或 HTTPS 请求都会经过负载均衡,负载均衡组件会处理 HTTPS 加密、重定向到 HTTPS、对响应进行压缩等一般性工作,因此云引擎上的程序不需要自己实现这些功能。同时负载均衡带来的一些限制,在云引擎程序内进行修改也无法越过,如:
/.well-known/acme-challenge/
开头的路径被用于自动管理证书,不会转发到云引擎程序。- 请求头(URL 和 header)每行最大 8K,总计最大 64K。
- 请求体积(上传文件体积)最大 100M。
- 连接或等待响应的超时时间为 60 秒。
获取客户端 IP 等信息
云引擎的负载均衡会在 HTTP header 中传递一些有关原始请求的信息:
X-Real-IP
: 请求的来源 IP。X-Forwarded-Proto
: 请求的来源协议(http
或https
)。Forwarded
: RFC 7239 规定的用于传递代理信息的头,包含 IP 和 协议。
EngineRequestContext.getRemoteAddress();
重定向到 HTTPS
在绑定云引擎自定义域名时,可以选择「强制 HTTPS」,勾选后负载均衡组件会将 HTTP 的请求重定向到 HTTPS 的同一路径。
环境变量
云引擎平台默认提供下列环境变量供应用使用:
变量名 | 说明 |
---|---|
LEANCLOUD_APP_ID | 当前应用的 App ID 。 |
LEANCLOUD_APP_KEY | 当前应用的 App Key 。 |
LEANCLOUD_APP_MASTER_KEY | 当前应用的 Master Key 。 |
LEANCLOUD_APP_ENV | 当前的应用环境:开发环境没有该环境变量,或值为 development (通过命令行工具启动)。预备环境值为 stage 。生产环境值为 production 。 |
LEANCLOUD_APP_PORT | 当前应用开放给外网的端口,只有监听此端口,用户才可以访问到你的服务。 |
LEANCLOUD_API_SERVER | 访问存储服务时使用的地址。该值会因为所在数据中心等原因导致不一样,所以使用 REST API 请求存储服务或其他云服务时请使用此环境变量的值。 |
LEANCLOUD_APP_GROUP | 云引擎实例所在的组。当使用云引擎组管理功能时,该值为组的名称。 |
LEANCLOUD_REGION | 云引擎服务所在区域,值为 CN 或 US ,分别表示国内版和国际版。 |
LEANCLOUD_VERSION_TAG | 云引擎实例部署的版本号。 |
你还可以在控制台上设置自定义的环境变量来存储配置信息。
日志
关于如何在控制台上查看日志,以及访问日志等更多内容,请看 云引擎平台功能 § 查看日志。
云引擎会收集应用打印到标准输出(stdout)和标准错误输出(stderr)的日志:
日志单行最大 4096 个字符,多余部分会被丢弃;日志收集速率最大 600 行每分钟,多余的部分会也被丢弃。
时区
云引擎使用 UTC+0 时区。
文件系统
你可以向 /home/leanengine
或 /tmp
目录写入临时文件,最多不能超过 1 GB。
云引擎每次部署都会产生一个新的容器,即使不部署系统偶尔也会进行一些自动调度,这意味着你 不能将本地文件系统当作持久的存储,只能用作临时存储。
如果你写入的文件体积较大,建议在使用后自动删除他们,否则如果占用磁盘空间超过 1 GB,继续写入文件可能会收到类似 Disk quota exceeded
的错误,这种情况下你可以重新部署一下,这样文件就会被清空了。
出入口 IP 地址
如果开发者希望在第三方服务平台(如微信开放平台)上配置 IP 白名单而需要获取云引擎的入口或出口 IP 地址,请进入 开发者中心 > 你的游戏 > 游戏服务 > 云服务 > 云引擎 > 管理部署 > 云引擎分组 > 设置 > 出入口 IP 来自助查询。
我们会尽可能减少出入口 IP 的变化频率,但 IP 突然变换的可能性仍然存在。因此在遇到与出入口 IP 相关的问题,我们建议先进入控制台来核实一下 IP 列表是否有变化。
如需保持入口 IP 不变,建议为云引擎绑定独立 IP。
疑难问题
如何脱离命令行工具本地启动云引擎 Java 项目?
设置云引擎运行需要的环境变量后,可以通过脱离命令行工具,直接运行相应命令或使用 IDE 本地启动 Java 项目。
通过命令行启动 Jetty 项目或 JAR 项目,先设置环境变量:
eval "$(lean env)"
提示:命令 lean env
可以输出当前应用所需环境变量的设置语句,外层的 eval
是直接执行这些语句。
Windows 系统下需要手动设置 lean env
输出的环境变量。
如果是 Jetty 项目,运行:
mvn jetty:run
如果是 JAR 项目,使用 Maven 打包项目并运行:
mvn package
java -jar target/{zipped jar file}
使用 Eclipse 启动应用:
首先确保 Eclipse 已经安装 Maven 插件,并将项目以 Maven Project 方式导入 Eclipse 中。
在 Package Explorer 视图右键点击项目:
- 如果是 Jetty 项目,选择 Run As > Maven build…,将 Main 标签页的 Goals 设置为
jetty:run
。 - 如果是 JAR 项目,选择 Run As > Run Configurations…,选择
Application
,设置Main class:
(示例项目为cn.leancloud.demo.todo.Application
)。
最后在 Environment 标签页增加以下环境变量和相应的值:
名称 | 值 |
---|---|
LEANCLOUD_APP_ENV | development |
LEANCLOUD_APP_ID | {{appid}} |
LEANCLOUD_APP_KEY | {{appkey}} |
LEANCLOUD_APP_MASTER_KEY | {{masterkey}} |
LEANCLOUD_APP_PORT | 3000 |
配置完成后,以后只需点击 run 按钮即可启动应用。
如何在云引擎中依赖内部 library(也称为「二方库」)?
云引擎构建环境只能访问公开的程序库(library),如果你项目中使用了一些公司内部的依赖库,可以按照如下方式进行引用:
- 首先在项目根目录下新建 libs 目录,把所有依赖的 jar 文件拷贝进来;
- 然后在项目根目录下新建 leanengine.yaml 文件,并自定义 install 环节(详见下文示例);
- 最后修改 pom.xml 中依赖项和
spring-boot-maven-plugin
配置,增加includeSystemScope
设置项(详见下文示例);
最终的工程目录结构如下:
{root}
|---libs
| |- yourdependency.jar etc.
|---leanengine.yaml
\---pom.xml
leanengine.yaml 内容如下:
install:
- require:
- libs
- { use: "default" }
pom.xml 中增加依赖项目:
<dependency>
<groupId>com.sample</groupId>
<artifactId>sample</artifactId>
<version>1.0</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/yourdependency.jar</systemPath>
</dependency>
pom.xml 中对 spring-boot-maven-plugin
改动如下:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>