云引擎 FAQ
综合
云引擎都支持哪些语言
目前支持 Node.js、Python、Java、PHP、.NET、Go 运行环境,未来可能还会引入其他语言。
云引擎支持托管纯静态网站吗
支持。命令行工具初始化项目选择语言环境时,依次选择 Others > Static Site 即可。
云引擎支持 HTTPS 吗
- 自定义域名在绑定时启用 SSL 即可支持 HTTPS。
- 如需配置自动跳转,请看云引擎下如何重定向到 HTTPS?。
云引擎采用什么样的休眠策略?
标准实例不会休眠。
体验实例会执行休眠策略:
- 如果应用最近一段时间(半小时)没有任何外部请求,则 休眠。
- 休眠后如果有新的外部请求实例则马上启动。访问者的体验是第一个请求响应时间是 5 ~ 30 秒(视实例启动时间而定),后续访问响应速度恢复正常。
- 强制休眠:如果最近 24 小时内累计运行超过 18 小时,则强制休眠。此时新的请求会收到 503 的错误响应码,该错误可在 云服务控制台 > 云引擎 > 云引擎分组 > 统计 中查看。
云引擎的请求有哪些限制?
云引擎的负载均衡组件限制了请求不能超过 100 MB(包括直接上传文件到云引擎)、请求处理不得超过 60 秒,WebSocket 60 秒无数据会被断开连接。
国内节点未绑定独立 IP 的云引擎默认为纯静态站点优化。请求会先经过边缘节点,再视缓存命中情况回源到负载均衡组件,最后到达你的应用。 边缘节点额外限制了请求不能超过 60 MB、请求处理不得超过 10 秒,另外边缘节点不支持 WebSocket 请求和 HTTP PATCH 方法,也不支持获取客户端 IP。 因此,如果您在国内节点云引擎托管动态网站,我们建议您绑定独立 IP,使用独立入口,不经过边缘节点,自然也就没有上述限制。
云引擎运行日志大小有限制吗?
日志单行最大 4096 个字符,多余部分会被丢弃;日志输出频率大于 600 行/分钟,多余的部分会被丢弃。
云引擎使用什么 时区?
国内版使用北京时间(东八区),国际版使用 UTC+0 时区。
如何查看云引擎的出入口 IP 地址?
如果开发者希望在第三方服务平台(如微信开放平台)上配置 IP 白名单而需要获取云引擎的入口或出口 IP 地址,请进入 云服务控制台 > 云引擎 > 设置 > 出入口 IP 来自助查询。
我们会尽可能减少出入口 IP 的变化频率,但 IP 突然变换的可能性仍然存在。因此在遇到与出入口 IP 相关的问题,我们建议先进入控制台来核实一下 IP 列表是否有变化。
如需保持入口 IP 不变,建议为云引擎绑定独立 IP。
如何访问云引擎预备环境中托管的网站?
需要在控制台手动绑定一个 stg- 开头的域名。stg- 开头的自定义域名(例如 stg-web.example.com)会被自动地绑定到预备环境。
如何判断当前云引擎是预备环境还是生产环境?
默认情况,云引擎只有一个「生产环境」,对应的域名是 web.example.com。在生产环境中有一个「体验实例」来运行应用。
当生产环境的体验实例升级到「标准实例」后会有一个额外的「预备环境」,对应域名 stg-web.example.com,两个环境所访问的都是同样的数据,你可以用预备环境测试你的云引擎代码,每次修改先部署到预备环境,测试通过后再发布到生产环境;如果你希望有一个独立数据源的测试环境,建议单独创建一个应用。
另外,stg-web.example.com 域名是需要在控制台自行绑定的。
Application not found 错误
访问云引擎服务时,服务端返回错误「Application not found」或在云引擎日志中出现这个错误,可能有以下原因:
- 调用错了环境。最常见的情况是,免费的体验实例是没有预备环境,开发者却主动设置去调用预备环境。
- 云引擎自定义域名填错了,比如微信回调地址。
- 因为免费版(体验版)的云引擎是有休眠的,休眠期间被调用会出现这个错误。建议升级到标准实例以保证实例一直运行。
云引擎会重复提交请求吗?
云引擎的负载均衡对于幂等的请求(GET、PUT),在 HTTP 层面出错或超时的情况下是会重试的。 可以使用正确的谓词(例如 POST)避免此类重试。
云引擎中如何处理用户登录和 Cookie?
如果你的页面主要由服务端渲染,可以使用我们在部分 SDK 中提供的管理 Cookie 和 Session 的中间件或模块,也可以其他第三方的中间件或模块,在 Cookie 中维护用户状态。
使用 Cookie 作为鉴权方式需要注意防范 CSRF 攻击(其他站点伪造带有正确 Cookie 的恶意请求)。 业界通常使用 CSRF Token 来防御 CSRF 攻击,你需要传递给客户端一个随机字符串(即 CSRF Token,可通过 Cookie 传递),客户端在每个有副作用的请求中都要将 CSRF 包含在请求正文或 Header 中,服务器端需要校验这个 CSRF Token 是否正确。
如果你的页面主要是由浏览器端渲染,那么建议在前端使用 SDK 登录用户,调用 SDK 的接口获取 session token,通过 HTTP Header 等方式将 session token 发送给后端。
例如,在前端登录用户并通过 user.getSessionToken() 获取 sessionToken 并发送给后端:
AV.User.login(user, pass).then(user => {
return fetch('/profile', {
headers: {
'X-LC-Session': user.getSessionToken()
}
});
});
相应的后端 Node.js 代码:
app.get('/profile', function (req, res) {
AV.User.become(req.headers['x-lc-session']).then(user => {
res.send(user);
}).catch(err => {
res.send({ error: err.message });
});
});
app.post('/todos', function (req, res) {
var todo = new Todo();
todo.save(req.body, { sessionToken: req.headers['x-lc-session'] }).then(() => {
res.send(todo);
}).catch(err => {
res.send({ error: err.message });
});
});
云引擎下如何管理用户会话?
使用各框架自带的组件或第三方模块即可。
例如:
- Node.js 的 Express 框架可以使用 cookie-session 组件。它和
AV.Cloud.CookieSession组件可以并存。注意,Express 框架的express.session.MemoryStore在云引擎中是无法正常工作的,因为云引擎是多主机、多进程运行,因此内存型 session 是无法共享的。 - Python 的 Flask 框架和 Django 框架都自带 session 组件。
- PHP 可以使用 SDK 提供的
CookieStorage保存会话属性。注意,PHP 默认的$_SESSION在云引擎中是无法正常工作的,因为云引擎是多主机、多进程运行,因此内存型 session 是无法共享的。
云引擎下如何发送 HTTP 请求?
使用各语言的标准库或社区提供的模块即可。
例如:
- Node.js 项目可以使用 superagent 等社区提供的模块。
- Python 项目可以使用标准库中的
urllib.request模块或社区的 requests 模块。 - PHP 项目可以使用 PHP 内置的
curl模块或 guzzle 等第三方库。 - Java 项目可以使用
URL或者是HttpClient等基础类或 OkHttp 等第三方库。
云引擎下如何获取客户端 IP?
如果你想获取客户端的 IP,可以直接从用户请求的 HTTP 头的 x-real-ip 字段获取。
下面给出各语言的示例代码。
Node.js(Express):
app.get('/', function (req, res) {
var ipAddress = req.headers['x-real-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
console.log(ipAddress);
res.send(ipAddress);
});
Python(Flask):
from flask import Flask
from flask import request
app = Flask(__name__)
@app.route('/')
def index():
print(request.headers['x-real-ip'])
return 'ok'
Python(Django):
def index(request):
print(request.META['HTTP_X_REAL_IP'])
return render(request, 'index.html', {})
PHP:
$app->get('/', function($req, $res) {
error_log($_SERVER['HTTP_X_REAL_IP]);
return $res;
});
Java:
EngineRequestContext.getRemoteAddress();
Go(Echo):
func fetchRealIP(c echo.Context) error {
realIP = c.RealIP()
//...
}
注意,国内节点的云引擎应用,如果启用了边缘节点加速功能,由于边缘节点的限制,可能无法获取客户端 IP。 如需获取客户端 IP,建议绑定独立 IP。
云引擎如何上传文件?
托管在云引擎的网站可以使用相应 SDK 提供的接口上传文件。 不过,一般情况下建议在客户端 SDK 上传文件,而不是通过云引擎中转,以免增加不必要的云引擎流量。
云引擎下如何重定向到 HTTPS?
大部分 SDK 提供了重定向至 HTTPS 的中间件。 部署并发布到生产环境之后,访问你的 LeanEngine 网站都会强制通过 HTTPS 访问。
Node.js(Express):
app.enable('trust proxy');
app.use(AV.Cloud.HttpsRedirect());
Node.js(Koa):
app.proxy = true;
app.use(AV.Cloud.HttpsRedirect({ framework: 'koa' }));
Python:
import leancloud
application = get_your_wsgi_func()
application = leancloud.HttpsRedirectMiddleware(application)
PHP(Slim):
SlimEngine::enableHttpsRedirect();
$app->add(new SlimEngine());
Java:
LeanEngine.setHttpsRedirectEnabled(true);
Go SDK 暂未提供跳转至 HTTPS 的中间件。
.NET:
app.UseHttpsRedirection();
如何判断请求是通过 HTTPS 还是 HTTP 访问的?
因为 HTTPS 加密是在负载均衡层面处理的,所以通常部署在云引擎上的 web 框架获取的请求 URL 总是使用 HTTP 协议,建议通过 X-Forwarded-Proto HTTP 头来判断原请求是通过 HTTP 还是 HTTPS 访问的。
每个应用最多有几个实例?
每个应用最多拥有 12 个实例,如果需要更多资源请通过工单联系我们的技术支持。
在线上无法读取到项目中的文件怎么办?
建议先检查文件大小写是否正确,线上的文件系统是区分大小写的,而 Windows 和 macOS 通常不区分大小写。
云引擎响应时间增加怎么办
响应时间的增加有很多种原因:可能因为只是单纯的请求处理的数据更加复杂导致耗时变长;也有可能是因为请求量过高实例的处理能力不足从而导致响应时间增加。 建议分析当前的代码并参考 CPU、内存占用量找出瓶颈,确定是否需要调高实例规 格或增加实例数量。 如果需要定位具体是哪些 API 或云函数响应较慢,可以下载访问日志分析。
如何下载云引擎的应用日志和访问日志
云引擎的应用日志(程序的标准输出和标准错误输出)可以在 云服务控制台 > 云引擎 > 云引擎分组 > 日志 查看;并且可以使用命令行工具导出最长 7 天的日志。
云引擎的访问日志(Access Log)同样可以在云服务控制台 > 云引擎 > 访问日志导出。
部署
云引擎下如何自定义系统级依赖?
在云引擎的线上环境中,你可以通过 leanengine.yaml 文件的 systemDependencies 部分来自定义系统级依赖:
systemDependencies:
- imagemagick
目前支持的选项包括:
ffmpeg一个音视频处理工具库。imagemagick一个图片处理工具库。fonts-wqy文泉驿点阵宋体、文泉驿微米黑,通常和phantomjs或chrome-headless配合来显示中文。fonts-noto思源黑体(体积较大)。phantomjs一个无 UI 的 WebKit 浏览器(该项目已停止维护)。chrome-headless一个无 UI 的 Chrome 浏览器(体积很大,会显著增加部署耗时,运行时也会消耗大量 CPU 和内存;如果使用puppeter的话,需要给puppeteer.launch传递这些参数:{executablePath: '/usr/bin/google-chrome', args: ['--no-sandbox', '--disable-setuid-sandbox']};暂不支持 Java)。node-canvas安装node-canvas所需要的系统级依赖(你仍需要安装node-canvas)。python-talib金融市场数据分析库。
注意添加系统依赖将会拖慢部署速度,因此请不要添加未用到的依赖。
云引擎中设置的环境变量无效?
默认情况下,应用在运行阶段才能够读取到内置环境变量和自定义环境变量。
如果希望在安装依赖或编译阶段就能读取到这些环境变量,需要在 leanengine.yaml 里设置:
exposeEnvironmentsOnBuild: true
云引擎运行环境默认提供的环境变量(以及 Node.js 环境变量 NODE_ENV)无法被自定义环境变量覆盖(覆盖无效)。
部署更新云引擎会导致 服务中断吗?
服务不会中断。在代码部署时,系统会优先启动使用新版本代码的实例,待新实例通过了健康检查,系统修改路由将请求转发至新实例后,再关闭旧版本的实例,让服务保持零中断。
部署时长时间卡在「正在下载和安装依赖」怎么办?
这个步骤对应在云端调用各个语言的包管理器(npm、pip、composer、maven)安装依赖的过程,我们有一个依赖缓存机制来加速这个安装过程,但缓存可能会因为很多原因失效(比如修改了依赖列表),在缓存失效时会比平时慢很多,请耐心等待。如果你在 leanengine.yaml 中指定了系统依赖也会在这个步骤中安装,因此请不要添加未用到的依赖。
对于 Node.js 建议检查是否在 package-lock.json 或 yarn.lock 中指定了较慢的源。
部署到多个实例时,部分实例失败需要重新部署吗?
同一环境(预备/生产)下有多个实例时,云引擎会同时在所有实例上部署项目。如因偶然因素部分实例部署不成功,会在几分钟后自动尝试再次部署,无需手动重新部署。
云引擎实例部署后控制台多次显示「部署中」是怎么回事?
控制台显示的「部署中」状态泛指所有运维操作,例如唤醒休眠实例、服务器偶发故障引起的重新部署,不只是用户主动进行的部署。
云引擎的健康检查是什么?
云引擎的管理系统会每隔几分钟检查所有实例的工作状态(通过 HTTP 检查,详见云引擎网站托管指南的《健康监测》一节。 如果实例无法正确响应的话,管理系统会触发一次重新部署,并在控制台上打印类似下面的日志:
健康检查失败:web1 检测到 Error connect ECONNREFUSED 10.19.30.220:51797
如果一周内发生一两次属正常现象(有可能是我们的服务器出现偶发的故障,因为会立刻重新部署,对服务影响很小),如果频繁发生可能是你的程序资源不足,或存在其他问题(运行一段时间后不再响应 HTTP 请求),需结合具体情况来分析。
不使用 SDK 的情况下,该如何实现健康监测和云函数元信息路由?
不使用 SDK 的情况下,需要自行实现相关路由。 下面给出 Java 和 PHP 的例子供参考。
健康监测:
// 健康监测 router
@WebServlet(name = "LeanEngineHealthServlet", urlPatterns = {"/__engine/1/ping"})
public class LeanEngineHealthCheckServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
resp.setHeader("content-type", "application/json; charset=UTF-8");
JSONObject result = new JSONObject();
result.put("runtime", System.getProperty("java.version"));
result.put("version", "custom");
resp.getWriter().write(result.toJSONString());
}
}
$app->get('/__engine/1/ping', function($req, $res) {
// PSR-7 response is immutable
$response = $res->withHeader("Content-Type", "application/json");
$response->getBody()->write(json_encode(array(
"runtime" => "php-" . phpversion(),
"version" => "custom"
)));
return $response;
});
云函数元信息:
@WebServlet(name = "LeanEngineMetadataServlet", urlPatterns = {"/1.1/functions/_ops/metadatas"})
public class LeanEngineMetadataServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
resp.setContentType("application/json; charset=UTF-8");
resp.getWriter().write("{\"result\":[]}");
}
}
app.get('/1.1/_ops/functions/metadatas', function(req, res) {
$response = $res->withHeader("Content-Type", "application/json");
$response->getBody()->write(json_encode(array(
"result" => array()
)));
return $response;
});
云引擎的启动限制时间是多久?
你的应用在启动时,云引擎的管理程序会每秒去检查你的应用是否启动成功,如果超过启动时间限制仍未启动成功,即认为启动失败。
启动时间限制默认为 30 秒,如需延长或缩短,可以在 leanengine.yaml文件中指定startupTimeout`,可设置范围为 15 – 120 秒。
多次部署同一个项目时镜像大小为什么差别那么大?
云引擎底层有一套缓存机制以加速构建过程,所以部署时显示的「存储镜像到仓库」后面的大小表示本次构建新产生的数据,可用于评估是否利用到了缓存,不代表整个项目的大小。
Gitlab 部署常见问题
很多用户自己使用 Gitlab 搭建了自己的源码仓库,有时可能会遇到无法部署到 LeanCloud 的问题,即使设置了 Deploy Key,却仍然要求输入密码。
可能的原因和解决办法如下:
- 确保你 Gitlab 运行所在服务器的 /etc/shadow 文件里的 git(或者 gitlab)用户 一行的
!修改为*,原因参考 Stackoverflow - SSH Key asks for password,并重启 SSH 服务:sudo service ssh restart。 - 在拷贝 Deploy Key 时,确保没有多余的换行符号。
- Gitlab 目前不支持有注释的 Deploy Key。早期 LeanCloud 用户生成的 Deploy Key 末尾可能带有注释(类似于
App dxzag3zdjuxbbfufuy58x1mvjq93udpblx7qoq0g27z51cx3's cloud code deploy key),需要删除掉这部分再保存到 Gitlab。
命令行工具
使用 Homebrew 安装命令行工具失败
有些地区 Homebrew 访问网络可能很慢,可以通过设置环境变量 http_proxy、https_proxy、all_proxy 加速访问(详见 man brew),或者也可以配置 Homebrew 索引和二进制预编译包的镜像。
或者也可以在 GitHub releases 页面下载适用于 macOS 的二进制文件,重命名为 lean 后移动到 $PATH 下的路径,并添加可执行权限(chmod a+x /path/to/lean)。
如果运行 lean 时 macOS 报错「来自身份不明的开发者」,那么需要在 macOS 系统设置「隐私与安全」下配置一下,详见 Apple 官方文档。
之前使用 npm 装过旧版的命令行工具,如果升级到新版?
如果之前使用 npm 安装过旧版本的命令行工具,为了避免与新版本产生冲突,建议使用 npm uninstall -g leancloud-cli 卸载旧版本命令行工具。或者直接按照 homebrew 的提示,执行 brew link --overwrite lean-cli 覆盖掉之前的 lean 命令来解决。
命令行工具初始化项目时报错 please login first,可是之前明明已经通过 lean login 成功登录了?
如果通过 lean login 登录的账号名下没有 LeanCloud 应用,会碰到这一问题。
需要创建一个应用再重新运行一下 lean login,之后就可以正常使用了。