{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2021-03-24-scf-konajdk11-spring","result":{"data":{"currentBlog":{"id":"f0acbdfd-118b-58af-8a7b-21f4e09b9176","frontmatter":{"thumbnail":"https://main.qcloudimg.com/raw/fbb92fa50e4adc7f22e7e0babc61232e.png","authors":["臧琳"],"categories":["best-practice"],"date":"2021-03-24T00:00:00.000Z","title":"深度好文：云函数 SCF + KonaJDK11 + Spring + 提速降存一把梭","description":"KonaJDK11 如此优秀，我们能不能把它引入到 Serverless 呢？","authorslink":null,"translators":null,"translatorslink":null,"tags":["Serverless","KonaJDK"],"keywords":null,"outdated":null},"wordCount":{"words":383,"sentences":70,"paragraphs":69},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2021-03-24-scf-konajdk11-spring.md","fields":{"slug":"/best-practice/2021-03-24-scf-konajdk11-spring/","keywords":["java","云函数","云原生","函数","juejin","byteimg"]},"html":"<h2 id=\"一、背景\"><a href=\"#%E4%B8%80%E3%80%81%E8%83%8C%E6%99%AF\" aria-label=\"一、背景 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>一、背景</h2>\n<p>腾讯 KonaJDK 团队最近对外开源了KonaJDK11, 该版本 JDK 是经过内部超大规模生产环境验证的定制 JDK，该版本在启动性能、峰值性能以及事物处理能力方面，相对于前一版本 Kona JDK8 都有了综合性提升，沉淀了腾讯云与大数据团队在大数据/机器学习、云原生场景下的深度优化，并且通过了 JCK 验证，确保充分的 Java SE 标准兼容。通过工业标准 Benchmark 表明，Kona JDK11 对比 Kona JDK8 大多数场景在峰值性能上具有非常明显的提升，个别性能提升接近 50%。</p>\n<p>KonaJDK11 如此优秀，我们能不能把它引入到Serverless呢？ 另外，最近笔者也在考虑怎么样让 Java spring 框架在 SCF 中顺滑的跑起来，所以借着这个机会，索性来一把 KonaJDK + Spring 在 SCF 上的实践总结。</p>\n<p>多说无用，Show you my code!</p>\n<h2 id=\"二、scf使用jdk11\"><a href=\"#%E4%BA%8C%E3%80%81scf%E4%BD%BF%E7%94%A8jdk11\" aria-label=\"二、scf使用jdk11 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>二、SCF使用JDK11</h2>\n<p>腾讯云Serverless云函数SCF产品中内置Java8支持，但是并没有高版本JDK的环境支持，那么如何实现SCF的Java11云函数呢？ </p>\n<p>实际上，SCF云函数提供的CustomRuntime功能已经解锁了用户使用编程语言的限制，目前已经有webassembly，swift，rust等成功例子。我们可以同样借助这个功能来将KonaJDK11引入SCF，从而实现高版本Java的支持。</p>\n<p>过程如下：</p>\n<ol>\n<li>下载KonaJDK11，<a href=\"https://github.com/Tencent/TencentKona-11/releases\">https://github.com/Tencent/TencentKona-11/releases</a> </li>\n<li>由于KonaJDK11的二进制包比较大，需要使用SCF层的概念来上传KonaJDK11程序包</li>\n</ol>\n<p>首先需要创建层，由于KonaJDK11程序包超过50MB，所以可以选择COS方式，现将KonaJDK11安装包上传到腾讯云COS，之后在创建层时指定路径即可， 具体使用可以参考产品说明<a href=\"https://cloud.tencent.com/document/product/583/45760\">https://cloud.tencent.com/document/product/583/45760</a> </p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1a393e9081c44f1cbad42bbe7e350c39~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<ol start=\"3\">\n<li>创建云函数， 注意这里需要使用CustomRuntime，我们选择Shell函数示例，再次基础上拓展我们的KonaJDK11的支持.</li>\n</ol>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4c835a6c428a4a008a75ee0ec0232e7b~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>进入【高级配置】->【层配置】->【添加层】</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/4fb4743049694b12901d9fccb3785790~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>按照下图所示配置好【层】【超时时间】与【内存】点击【完成】</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d4af2963bb624326a303820927b7ade7~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<ol start=\"4\">\n<li>根据SCF CustomRuntime的<a href=\"https://cloud.tencent.com/document/product/583/47274\">使用说明</a>，需要编写CustomRuntime的启动文件 Bootstrap，SCF CustomRuntime会在函数启动时第一步找到并执行这个名为bootstrap的可执行文件。</li>\n<li>我们的bootstrap中需要配置环境变量，并启动Java程序. 我们先假设我写了一个名为Hello的class，里面只打印hello SCF 字符串。 之后将bootstrap文件和Hello.class文件一起打包成一个zip文件，上传到SCF部署，这时bootstrap的内容如下：</li>\n</ol>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/44ea8a4ae27243779d79c7994cf6e2de~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>可以看到就是简单的环境变量配置和执行java -version 与 Hello程序。</p>\n<p>之后点击【测试】触发执行，之后我们可以看到函数执行日志如下：</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/76847b3e0fc94b0296a59928d437974b~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>我们已经可以从日志里看到 openjdk version \"11.0.9.1-ga\"的 Java版本，并且看到了Hello程序正常输出。至此，KonaJDK 11 已经顺利跑在了云函数环境中。</p>\n<p>注意此处显示【测试失败】是正常的，因为我们还没有编写处理【函数事件】的逻辑，也就是还没有实现具体的云函数。</p>\n<h2 id=\"三、实现spring云函数\"><a href=\"#%E4%B8%89%E3%80%81%E5%AE%9E%E7%8E%B0spring%E4%BA%91%E5%87%BD%E6%95%B0\" aria-label=\"三、实现spring云函数 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>三、实现spring云函数</h2>\n<p>现在让我们来用spring框架实现一个能跑在KonaJDK11上的云函数。为了清晰，我们写一个最简单的springboot Demo, 它的controller长这样：</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/28dbb153d52a4394982878e571a2b6af~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>入口函数长这样：</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bbd23d9c334d41ffb22bdd9318966a54~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>OK,目前这个Demo可以接受 <code class=\"language-text\">http Get localhost:8080/hello</code> 请求并返回 <code class=\"language-text\">hello, this is a springboot demo!</code> 字符串。 那么如何将它改编成云函数呢？ </p>\n<p>从 SCF CustomRuntime 文档以及一些公开的资料，可以看到编写CustomRuntime的函数，只需要两个关键步骤：</p>\n<ol>\n<li>编写可执行启动程序bootstrap，在bootstrap里面启动我们的spring云函数</li>\n<li>编写云函数。这一步首先需要了解CustomRuntime工作的流程，从<a href=\"https://cloud.tencent.com/developer/article/1690709\">这篇</a>文章可以看到，主要流程如下：</li>\n</ol>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b0ce3625e05a46ed9e23ce59ef78f518~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>具体说来，就是在bootstrap启动云函数以后，sping云函数在自身初始化时需要先POST一个Ready的httpRequest给 SCF服务端， 目的是通知SCF函数初始化完毕，可以获得下发的事件了。</p>\n<p>之后，spring需要一个循环，循环内部通过向SCF服务端发送HTTP GET请求，获得待处理事件，再调用内部逻辑，处理完事件之后通过POST请求发送给SCF服务端，循环等待下一次事件下发。</p>\n<p>针对Springboot， 我们的云函数主要有以下几个需要处理的地方：</p>\n<ol>\n<li>事件下发： Springboot云函数主要是启动并监听云函数内部的一个自定义http端口，通过http请求完成处理任务。 SCF云函数目前http请求主要通过API Gateway事件下发，也就是说，spring云函数的逻辑里面，需要将API Gateway事件转换成http事件之后再发给函数内部的springboot监听的端口。好在整个这一套逻辑的转换SCF其实已经提供给了我们，就在SCF java event的代码中，可以从 <a href=\"https://github.com/tencentyun/SCF-java-libs/blob/master/SCF-java-events/src/main/java/com/qcloud/SCF/runtime/AbstractSpringHandler.java\">https://github.com/tencentyun/SCF-java-libs/blob/master/SCF-java-events/src/main/java/com/qcloud/SCF/runtime/AbstractSpringHandler.java</a> 这个代码直接抽取复用。</li>\n<li>初始化： 也就是在第一次启动云函数的时候，我们需要启动springboot，另其建立httpserver并监听端口。 之后每次事件下发，只需要发送httprequest即可。</li>\n<li>监听事件： 这里就是按照 SCF CustomRutime 的要求，写一个循环，使用http GET请求获取event，并发送给内部springboot监听的端口。</li>\n</ol>\n<p>经过上面的梳理，逻辑已经基本上清晰了：首先，需要在 cold launch阶段启动springboot入口函数， 通知SCF服务端，springboot云函数初始化完毕，等待接收消息。之后就是一个大循环，循环里面工作如下：</p>\n<ul>\n<li>通过 <code class=\"language-text\">Http GET</code> 请求从SCF服务端获得 ApiGateway 下发的event</li>\n</ul>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/22775122c15c402dae03e9a55647b259~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<ul>\n<li>Api GW event转换成 http request 并发送到 springboot 监听的端口，等待返回处理结果</li>\n<li>springboot 返回的 event 转换为 ApiGateway Response， 通过POST请求返回给SCF 服务端</li>\n<li>进入下一次循环，等待下一次事件下发.</li>\n</ul>\n<p>处理流程代码也很简单：</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/8a3e98843b234d1a88930ebd435153d3~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>至此，我们已经完成了云函数的编写，之后我们可以测试一下，将bootstrap和编译后的 <code class=\"language-text\">springboot-application.jar</code> 打包到一个zip文件，然后上传到SCF云函数进行部署。</p>\n<p>之后按照如下配置 apiGW 的 event，注意这里配置 Get，“/hello” 是由于我们的springboot 云函数的controller配置成了接收Get， “/hello” 请求并打印和返回字符串，实际上用户需要根据自己的业务，修改apiGW这里event相应的内容。</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/e8d2275a12004cb5b52e147b79013c94~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>然后点击[测试]: 稍等一下就可以看到如下log：</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/908ae59d6ce9417db6480f3f9de181ee~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>springboot已经启动， 然后我们还可以看到：</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/62a459d8a54842b3b6ad84892a71efd6~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>函数已经正常响应了GET /hello的请求。</p>\n<h2 id=\"四、利用appcds特性提速降存\"><a href=\"#%E5%9B%9B%E3%80%81%E5%88%A9%E7%94%A8appcds%E7%89%B9%E6%80%A7%E6%8F%90%E9%80%9F%E9%99%8D%E5%AD%98\" aria-label=\"四、利用appcds特性提速降存 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>四、利用appCDS特性提速降存</h2>\n<p>在上面的springboot云函数中，我们可以看到一次冷启动耗时和内存如下：</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/44ac1d7355bc4bfabe34bf4b06dca0f6~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>同时log中也包含了springboot的启动时间</p>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/026157cfb4474b238b669fbfcbc133ef~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<p>总体来说就是耗时6秒多，使用了168MB的内存。</p>\n<p>那么，如何提高启动速度减少内存使用呢？</p>\n<p>JDK11里面自带appCDS功能，具openJDK官方说法，该功能可以减少java类加载时间同时减少内存占用量，提高启动速度。 这不正是我们想要的么，我们现在已经有了KonaJDK+springboot的云函数，那么怎么在KonaJDK中使用起来这个功能呢？</p>\n<ol>\n<li>appCDS功能使用步骤：</li>\n</ol>\n<p>按照JDK官方文档， appCDS使用方式主要是以下几个步骤：</p>\n<ul>\n<li>生成待 <code class=\"language-text\">dump</code> 的类文件列表， 使用 <code class=\"language-text\">-Xshare:off -XX:+UseAppCDS -XX:DumpLoadedClassList=classes.lst</code> JVM选项运行程序，会生成classes.lst文件</li>\n<li>使用 <code class=\"language-text\">-Xshare:dump -XX:+UseAppCDS -XX:SharedClassListFile=classes.lst \\ -XX:SharedArchiveFile=dump.jsa</code> 生成dump.jsa文件</li>\n<li>使用appCDS正常启动java程序，使用JVM选项 <code class=\"language-text\">-Xshare:on -XX:+UseAppCDS -XX:SharedArchiveFile=dump.jsa</code></li>\n<li>云函数中enable appCDS</li>\n</ul>\n<p>针对云函数SCF的场景，主要需要以下适配工作</p>\n<ul>\n<li>由于在云函数中，目前只有/tmp目录是可写目录，所以1中的步骤我们需要将所有涉及到的文件路径变更为 <code class=\"language-text\">/tmp/classes.list</code> 和 <code class=\"language-text\">/tmp/dump.jsa</code></li>\n<li>由于我们期望最终生成的dump.jsa可以在多个云函数实例中使用，我们需要得到/tmp/dump.jsa文件，然后将其和云函数一起打包，这样在使用时候，我们只需要指定Jvm参数 <code class=\"language-text\">-XX:SharedArchiveFile=dump.jsa</code> 即可复用 <code class=\"language-text\">dump.jsa</code> 文件。 所以我们需要获得生成的 <code class=\"language-text\">/tmp/dump.jsa</code> 文件，由于SCF不能直接下载 <code class=\"language-text\">/tmp</code>目录的文件，所以我们根据COS的文档写了一小段程序，帮助我们在生成 <code class=\"language-text\">/tmp/dump.jsa</code> 文件后上传到指定的COS中，具体可以参考<a href=\"https://cloud.tencent.com/document/product/436/6273\">COS java 的sdk </a></li>\n<li>在得到 <code class=\"language-text\">dump.jsa</code>之后，我们就可以对整个云函数重新打包，最终打包的文件中包含3个子文件， 云函数 CustomRuntime的启动脚本bootstrap, springboot云函数的实现 <code class=\"language-text\">SCF-springboot-web-1.0-SNAPSHOT.jar</code> ,以及appCDS的archive文件 dump.jsa，我们将这3个文件打包重新部署。</li>\n<li>再部署之后，我们需要添加 <code class=\"language-text\">JAVA_TOOL_OPTIONS</code> 环境变量 <code class=\"language-text\">JAVA_TOOL_OPTIONS=-Xshare:on -XX:SharedArchiveFile=dump.jsa</code></li>\n</ul>\n<p>这样就可以在启动云函数时使用这些 jvm 选项了。</p>\n<ol start=\"3\">\n<li>效果</li>\n</ol>\n<p>在使用AppCDS之后出发云函数的冷启动，可以看到如下效果：</p>\n<ul>\n<li>内存使用 从原来的<strong>169MB降低到了100MB</strong></li>\n</ul>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/7d8b6f7b99794f7b8a7b99191c3deb1f~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<ul>\n<li>springboot启动时间从原来的<strong>6.137s提高到了4.772s</strong></li>\n</ul>\n<p><img src=\"https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/aa8783a3658d4047beac48d279684e88~tplv-k3u1fbpfcp-zoom-1.image\"></p>\n<h2 id=\"总结\"><a href=\"#%E6%80%BB%E7%BB%93\" aria-label=\"总结 permalink\" class=\"anchor\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>总结</h2>\n<p>至此，我们在腾讯 Serverless 云函数上借助 CustomRuntime 完成了KonaJDK11 + SpringBoot云函数的使用，并利用KonaJDK11中AppCDS特性优化了云函数冷启动的速度与内存损耗。 文中利用CustomeRuntime引入KonaJDK11的方法可以作为腾讯云Faas上解锁多语言或高版本Java语言runtime的一种通用方式。</p>\n<p>在未来腾讯KonaJDK团队会进一步针对腾讯云业务Faas场景的特点提供更多的功能与性能提升，敬请关注。</p>","tableOfContents":"<ul>\n<li><a href=\"/best-practice/2021-03-24-scf-konajdk11-spring/#%E4%B8%80%E3%80%81%E8%83%8C%E6%99%AF\">一、背景</a></li>\n<li><a href=\"/best-practice/2021-03-24-scf-konajdk11-spring/#%E4%BA%8C%E3%80%81scf%E4%BD%BF%E7%94%A8jdk11\">二、SCF使用JDK11</a></li>\n<li><a href=\"/best-practice/2021-03-24-scf-konajdk11-spring/#%E4%B8%89%E3%80%81%E5%AE%9E%E7%8E%B0spring%E4%BA%91%E5%87%BD%E6%95%B0\">三、实现spring云函数</a></li>\n<li><a href=\"/best-practice/2021-03-24-scf-konajdk11-spring/#%E5%9B%9B%E3%80%81%E5%88%A9%E7%94%A8appcds%E7%89%B9%E6%80%A7%E6%8F%90%E9%80%9F%E9%99%8D%E5%AD%98\">四、利用appCDS特性提速降存</a></li>\n<li><a href=\"/best-practice/2021-03-24-scf-konajdk11-spring/#%E6%80%BB%E7%BB%93\">总结</a></li>\n</ul>"},"previousBlog":{"id":"15e265c5-4495-53a8-8d10-02909b8ab82f","frontmatter":{"thumbnail":"https://main.qcloudimg.com/raw/cb8be2ca0ef4971973d7e3bde82687f6.jpg","authors":["April"],"categories":["best-practice"],"date":"2021-03-25T00:00:00.000Z","title":"Serverless Wordpress 系列建站教程（五）","description":"基于 Serverless 架构的 Wordpress 高级能力配置","authorslink":null,"translators":null,"translatorslink":null,"tags":["Serverless","WordPress"],"keywords":null,"outdated":null},"wordCount":{"words":125,"sentences":20,"paragraphs":20},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2021-03-25-wp5.md","fields":{"slug":"/best-practice/2021-03-25-wp5/","keywords":["php","云函数","WordPress","插件","上传"]}},"nextBlog":{"id":"286a22c7-8662-5105-a6fe-de6fb25bd445","frontmatter":{"thumbnail":"https://main.qcloudimg.com/raw/984bf4cf35beba9c5f1233d1d13cfd94.png","authors":["陈涛"],"categories":["best-practice"],"date":"2021-03-17T00:00:00.000Z","title":"如何使用 Serverless + CLB 快速部署 Web 服务？","description":"更低成本、免运维，为开发者平滑迁移应用上云提供参考","authorslink":null,"translators":null,"translatorslink":null,"tags":["Serverless","CLB"],"keywords":null,"outdated":null},"wordCount":{"words":126,"sentences":29,"paragraphs":28},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2021-03-17-clb.md","fields":{"slug":"/best-practice/2021-03-17-clb/","keywords":["serverless","云函数","width"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"f0acbdfd-118b-58af-8a7b-21f4e09b9176","previousBlogId":"15e265c5-4495-53a8-8d10-02909b8ab82f","nextBlogId":"286a22c7-8662-5105-a6fe-de6fb25bd445"}}}