{"componentChunkName":"component---src-templates-best-practice-detail-tsx","path":"/best-practice/2020-10-12-labelhub","result":{"data":{"currentBlog":{"id":"7095aff6-92f7-584e-9803-b6f1db15e4f4","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/20201012/1602475343467-1602323330220-%E4%B8%A4%E8%A1%8C_%E8%93%9D%E8%89%B2s.jpg","authors":["LuckyYo"],"categories":["best-practice"],"date":"2020-10-12T00:00:00.000Z","title":"Labelhub 基于腾讯云 Serverless 技术为人工智能企业提供数据与模型解决方案","description":"轻松构建数据可视化运维面板实践分享","authorslink":null,"translators":null,"translatorslink":null,"tags":["Serverless","人工智能"],"keywords":"Serverless Framework,Serverless,SCF,labelhub,人工智能","outdated":null},"wordCount":{"words":289,"sentences":59,"paragraphs":59},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-10-12-labelhub.md","fields":{"slug":"/best-practice/2020-10-12-labelhub/","keywords":["go","python","rest api","serverless","云函数","Serverless","函数","组件","部署","user","bash","配置文件","labelhub","common"]},"html":"<p>Labelhub 是一家致力于为人工智能企业提供完善的数据与模型解决方案公司，可以帮助 AI 企业更好的管理数据，从而提高其核心 AI 产品迭代速度，Labelhub 拥有优秀的敏捷团队，开发领域涉及机器学习、模型训练以及软件应用。目前已经与多家大中型企业进行深度合作，在行业相关比赛中也多次获奖。</p>\n<p><img src=\"https://img.serverlesscloud.cn/20201010/1602321819012-image.png\"></p>\n<p>Labelhub 团队在业务极速扩张的时期，选择使用腾讯云 <code class=\"language-text\">Serverless</code> 技术来打造一个轻量的内部运维及数据可视化系统。通过使用 <a href=\"https://github.com/serverless/components/tree/cloud\">Tencent Serverless Framework</a>，基于云上 Serverless 服务（云函数及触发器等），无需配置和部署，即可快速开发一套定制化数据可视化系统，腾讯云 <code class=\"language-text\">Serverless</code> 技术不仅满足了业务发展的需求，而且不需要耗费太多的人力和资金成本，是 Labelhub 的不二之选。 </p>\n<p>在实践中，作者对腾讯云 Serverless 产品逐渐产生了浓厚的兴趣，希望能把自己对腾讯云 Serverless 技术的理解，以及如何使用腾讯云 Serverless 技术进行项目开发的实践经验分享给大家。</p>\n<h2 id=\"前言\"><a href=\"#%E5%89%8D%E8%A8%80\" 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>我所在的团队开发了一款针对人工智能企业数据标注产品<a href=\"https://app.labelhub.cn\">Labelhub</a>，目前正式的销售工作处于摸索阶段，对于目标客户，产品的定位，一直没有很好进行梳理。随着业务的逐渐开展，平台的运维安全也并没有进行系统的监控管理。因此我考虑将产品的业务数据、服务器数据及应用监控数据做一个基本的内部运维及数据可视化系统。  </p>\n<p>虽然有很多的开源工具选择，但是都避免不了部署及配置，二次开发也比较麻烦，因此考虑自行开发一套简单的按内部需求完全定制化的系统。</p>\n<p>最终，我决定使用 <code class=\"language-text\">Serverless</code> 来打造这样一个轻量的内部系统，<code class=\"language-text\">Serverless</code> 无疑是时下最热的 IT 词汇之一，作为一种新型的互联网软件产品架构，虽然早在 2012 年就被提出，但随着近几年容器技术、<code class=\"language-text\">IoT</code>、区块链以及 5G技术的快速发展，<code class=\"language-text\">Serverless</code>的概念也借势得以迅速发展。 </p>\n<p>它究竟能够带来什么，它的红利是否有门槛，离我们究竟有多远，值不值得现在开始投入，我会通过这一个项目的一系列文章来和大家一起探讨，从一名普通开发者的角度去看看 <code class=\"language-text\">Serverless</code>。</p>\n<h2 id=\"概要说明\"><a href=\"#%E6%A6%82%E8%A6%81%E8%AF%B4%E6%98%8E\" 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>我希望此系列文章能够浅显易懂，我会尽可能详细的介绍我在开发这个系统的过程中，对于<code class=\"language-text\">Serverless</code> 的理解。通过这一系列文章，我希望能够提供给大家的内容包括：</p>\n<ul>\n<li>如何开发一个<code class=\"language-text\">real world serverless app</code></li>\n<li>对于服务拆分的理解，如何更有效的利用资源</li>\n<li>\n<p>现有的BaaS迁移至FaaS的设想</p>\n<blockquote>\n<p>(如果想到更多会继续补全)</p>\n</blockquote>\n</li>\n</ul>\n<p>此系列文章是基于 <a href=\"https://cloud.tencent.com/document/product/1154\">腾讯Serverless Framework</a> 工具，同时后端使用 <code class=\"language-text\">Python</code> 进行开发</p>\n<h2 id=\"项目构建\"><a href=\"#%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA\" 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><strong>搭建后端项目结构</strong></p>\n<p><code class=\"language-text\">Serverless Framework</code> 的文档中心里，框架支持里目前有 <code class=\"language-text\">Flask</code> 以及 <code class=\"language-text\">Django</code> ，按照文档示例中进行，会发现部署一个简单的 <code class=\"language-text\">rest api</code> 十分容易，整个过程如官方宣称的极速部署。\n但看一下项目的结构会发现，只有一个 <code class=\"language-text\">yml</code> 配置文件、一个依赖文本和一个 <code class=\"language-text\">app.py</code> 文件，由于配置文件中会使用 <code class=\"language-text\">hooks</code> 参数将依赖安装到当前文件夹，这是一个非常简单的一个示例。\n在搭建后端项目目录的时候，通常情况下本地开发时并不需要考虑以下两点：</p>\n<ul>\n<li>三方库的引入</li>\n<li>公共函数的调用</li>\n</ul>\n<p>对于 <code class=\"language-text\">Serverless</code>，则需要考虑这两个问题。</p>\n<p>当在示例中执行 <code class=\"language-text\">sls deploy</code> ，部署成功后可以在控制台查看函数代码，此时会发现依赖文件也在文件列表中，这很好的解释了为什么说 <code class=\"language-text\">一个函数是一个应用</code>。\n但是实际开发过程中，我们不可能每一个功能模块都会去安装一次依赖，因此我们可以借助公共模块来解决这个问题。但是公共模块如何进行引入呢。\n由于 <code class=\"language-text\">Serverless cli Component v2</code> 已经取消了 <code class=\"language-text\">include</code> 配置，对于 <code class=\"language-text\">v1</code> 可以很轻松的使用 <code class=\"language-text\">include</code> 配置将公共组件包含在函数中，从而各子函数能够很方便的进行调用。而对于 <code class=\"language-text\">v2</code>，其实我们可以通过 <code class=\"language-text\">Layer</code> 来解决这个问题。</p>\n<blockquote>\n<p>对于 v1 和 v2 的区别以及详细介绍，可参考<a href=\"https://www.serverlesschina.com/post/37.html\">Serverless Framework Cli的版本进化</a></p>\n</blockquote>\n<p>模块的拆分，我们则可以通过<a href=\"https://cloud.tencent.com/document/product/1154/48261\">应用管理中的多实例管理</a>来进行。</p>\n<h2 id=\"项目实践\"><a href=\"#%E9%A1%B9%E7%9B%AE%E5%AE%9E%E8%B7%B5\" 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><strong>项目根目录的处理</strong></p>\n<p>创建项目文件夹</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"54391613628454330000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`mkdir labelhub-dashboard`, `54391613628454330000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">mkdir</span> labelhub-dashboard</code></pre></div>\n<p>在项目根目录下应用配置文件</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"32034003054453940000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`cd labelhub-dashboard\ntouch serverless.yml`, `32034003054453940000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token builtin class-name\">cd</span> labelhub-dashboard\n<span class=\"token function\">touch</span> serverless.yml</code></pre></div>\n<p>在应用配置文件中只用定义应用的名称</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"49131491951740090000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`app: labelhub-dashboard`, `49131491951740090000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">app: labelhub-dashboard</code></pre></div>\n<p><strong>公共文件及三方依赖目录的处理</strong></p>\n<p>在根目录文件夹下创建公共模块文件夹</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"32999008551866237000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`mkdir common`, `32999008551866237000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">mkdir</span> common</code></pre></div>\n<p>我们将依赖以及公共函数放到<code class=\"language-text\">common</code>中便于其他模块进行调用</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"42082475923486330000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`# labelhub-dashboard/common\ntouch requirements.txt\n# 创建数据库连接工具类\ntouch dataUtils.py`, `42082475923486330000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># labelhub-dashboard/common</span>\n<span class=\"token function\">touch</span> requirements.txt\n<span class=\"token comment\"># 创建数据库连接工具类</span>\n<span class=\"token function\">touch</span> dataUtils.py</code></pre></div>\n<p>由于只是测试，也可以直接在 <code class=\"language-text\">common</code> 下运行 <code class=\"language-text\">pip install pymysql -t ./</code> 将依赖安装到当前路径下。</p>\n<blockquote>\n<p>这里使用pymysql来连接数据库进行测试</p>\n</blockquote>\n<p>编辑 <code class=\"language-text\">dataUtils.py</code> 文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"24118681547557007000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import pymysql\n\nclass MysqlUtils:\n    def __init__(self):\n        self.getConn({\n            'host': 'xxx',\n            'user': 'xxx',\n            'port': 3306,\n            'db': 'xxx',\n            'password': 'xxx'\n        })\n\n    def getConn(self, conf):\n        self.connection = pymysql.connect(\n            host=conf['host'],\n            user=conf['user'],\n            password=conf['password'],\n            port=conf['port'],\n            db=conf['db'],\n            charset='utf8',\n            cursorclass=pymysql.cursors.DictCursor,\n            autocommit=1\n        )\n\n    def doAction(self, stmt, data):\n        try:\n            self.connection.ping(reconnect=True)\n            cursor = self.connection.cursor()\n            cursor.execute(stmt, data)\n            result = cursor\n            cursor.close()\n            return result\n        except Exception as e:\n            try:\n                cursor.close()\n            except:\n                pass\n            return False`, `24118681547557007000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">import</span> pymysql\n\n<span class=\"token keyword\">class</span> <span class=\"token class-name\">MysqlUtils</span><span class=\"token punctuation\">:</span>\n    <span class=\"token keyword\">def</span> <span class=\"token function\">__init__</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        self<span class=\"token punctuation\">.</span>getConn<span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n            <span class=\"token string\">'host'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'xxx'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'user'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'xxx'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'port'</span><span class=\"token punctuation\">:</span> <span class=\"token number\">3306</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'db'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'xxx'</span><span class=\"token punctuation\">,</span>\n            <span class=\"token string\">'password'</span><span class=\"token punctuation\">:</span> <span class=\"token string\">'xxx'</span>\n        <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">def</span> <span class=\"token function\">getConn</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">,</span> conf<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        self<span class=\"token punctuation\">.</span>connection <span class=\"token operator\">=</span> pymysql<span class=\"token punctuation\">.</span>connect<span class=\"token punctuation\">(</span>\n            host<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'host'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            user<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'user'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            password<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'password'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            port<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'port'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            db<span class=\"token operator\">=</span>conf<span class=\"token punctuation\">[</span><span class=\"token string\">'db'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n            charset<span class=\"token operator\">=</span><span class=\"token string\">'utf8'</span><span class=\"token punctuation\">,</span>\n            cursorclass<span class=\"token operator\">=</span>pymysql<span class=\"token punctuation\">.</span>cursors<span class=\"token punctuation\">.</span>DictCursor<span class=\"token punctuation\">,</span>\n            autocommit<span class=\"token operator\">=</span><span class=\"token number\">1</span>\n        <span class=\"token punctuation\">)</span>\n\n    <span class=\"token keyword\">def</span> <span class=\"token function\">doAction</span><span class=\"token punctuation\">(</span>self<span class=\"token punctuation\">,</span> stmt<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n            self<span class=\"token punctuation\">.</span>connection<span class=\"token punctuation\">.</span>ping<span class=\"token punctuation\">(</span>reconnect<span class=\"token operator\">=</span><span class=\"token boolean\">True</span><span class=\"token punctuation\">)</span>\n            cursor <span class=\"token operator\">=</span> self<span class=\"token punctuation\">.</span>connection<span class=\"token punctuation\">.</span>cursor<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            cursor<span class=\"token punctuation\">.</span>execute<span class=\"token punctuation\">(</span>stmt<span class=\"token punctuation\">,</span> data<span class=\"token punctuation\">)</span>\n            result <span class=\"token operator\">=</span> cursor\n            cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">return</span> result\n        <span class=\"token keyword\">except</span> Exception <span class=\"token keyword\">as</span> e<span class=\"token punctuation\">:</span>\n            <span class=\"token keyword\">try</span><span class=\"token punctuation\">:</span>\n                cursor<span class=\"token punctuation\">.</span>close<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n            <span class=\"token keyword\">except</span><span class=\"token punctuation\">:</span>\n                <span class=\"token keyword\">pass</span>\n            <span class=\"token keyword\">return</span> <span class=\"token boolean\">False</span></code></pre></div>\n<p>准备就绪，就可以进行部署了。前面说过，因为 <code class=\"language-text\">common</code> 我们会作为 <code class=\"language-text\">公共函数及三方库</code> 存放的地方，因此我们需要用 <code class=\"language-text\">Layer</code> 组件来进行部署。在 <code class=\"language-text\">common</code> 中创建配置文件</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"71176718346045910000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`touch serverless.yml`, `71176718346045910000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">touch</span> serverless.yml</code></pre></div>\n<p>编辑配置文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"62419940795202126000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`component: layer\t# 注意，这里使用的是layer组件\nname: common-layer\norg: labelhub-dashboard\napp: labelhub-dashboard\nstage: dev\n\ninputs:\n  name: commonfiles\t# 记住这个名字\n  region: ap-guangzhou\n  src:\n    src: ./\n    exclude:\n      - .env\n  runtimes:\n    - Python3.6\n  description: packages`, `62419940795202126000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">component: layer\t<span class=\"token comment\"># 注意，这里使用的是layer组件</span>\nname: common-layer\norg: labelhub-dashboard\napp: labelhub-dashboard\nstage: dev\n\ninputs:\n  name: commonfiles\t<span class=\"token comment\"># 记住这个名字</span>\n  region: ap-guangzhou\n  src:\n    src: ./\n    exclude:\n      - .env\n  runtimes:\n    - Python3.6\n  description: packages</code></pre></div>\n<p>然后执行 <code class=\"language-text\">sls deploy</code>，<code class=\"language-text\">Layer</code> 层部署成功后，会出现函数的详细信息，需要注意其中<code class=\"language-text\">version</code>字段的值，部署完成后我们开始创建功能模块目录。</p>\n<p><strong>功能模块目录的处理</strong></p>\n<p>在根目录下创建一个测试子模块</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"2972865000762104000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`mkdir user-data`, `2972865000762104000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">mkdir</span> user-data</code></pre></div>\n<p>创建测试文件</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"37407982936312640000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`touch index.py`, `37407982936312640000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">touch</span> index.py</code></pre></div>\n<p>编辑测试文件</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"25813044276430365000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`from mysqlUtils import MysqlUtils\n\nimport json\n\ndb = MysqlUtils()\n\ndef get_users():\n    search_stmt = (\n            &quot;SELECT * FROM \\`user\\` limit 100;&quot;\n        )\n    result = db.doAction(search_stmt, ())\n    if result == False:\n        return False\n    return result\n    \ndef main_handler(event, context):\n    result = get_users()\n    data = [{'id': user['id'], 'name': str(user['name']), 'created_at': user['created_at'].strftime('%Y-%m-%d %H:%M:%S')} for user in result.fetchall()]\n    return data`, `25813044276430365000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"python\"><pre class=\"language-python\"><code class=\"language-python\"><span class=\"token keyword\">from</span> mysqlUtils <span class=\"token keyword\">import</span> MysqlUtils\n\n<span class=\"token keyword\">import</span> json\n\ndb <span class=\"token operator\">=</span> MysqlUtils<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n<span class=\"token keyword\">def</span> <span class=\"token function\">get_users</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    search_stmt <span class=\"token operator\">=</span> <span class=\"token punctuation\">(</span>\n            <span class=\"token string\">\"SELECT * FROM `user` limit 100;\"</span>\n        <span class=\"token punctuation\">)</span>\n    result <span class=\"token operator\">=</span> db<span class=\"token punctuation\">.</span>doAction<span class=\"token punctuation\">(</span>search_stmt<span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">if</span> result <span class=\"token operator\">==</span> <span class=\"token boolean\">False</span><span class=\"token punctuation\">:</span>\n        <span class=\"token keyword\">return</span> <span class=\"token boolean\">False</span>\n    <span class=\"token keyword\">return</span> result\n    \n<span class=\"token keyword\">def</span> <span class=\"token function\">main_handler</span><span class=\"token punctuation\">(</span>event<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span><span class=\"token punctuation\">:</span>\n    result <span class=\"token operator\">=</span> get_users<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    data <span class=\"token operator\">=</span> <span class=\"token punctuation\">[</span><span class=\"token punctuation\">{</span><span class=\"token string\">'id'</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">'id'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'name'</span><span class=\"token punctuation\">:</span> <span class=\"token builtin\">str</span><span class=\"token punctuation\">(</span>user<span class=\"token punctuation\">[</span><span class=\"token string\">'name'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'created_at'</span><span class=\"token punctuation\">:</span> user<span class=\"token punctuation\">[</span><span class=\"token string\">'created_at'</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">.</span>strftime<span class=\"token punctuation\">(</span><span class=\"token string\">'%Y-%m-%d %H:%M:%S'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">}</span> <span class=\"token keyword\">for</span> user <span class=\"token keyword\">in</span> result<span class=\"token punctuation\">.</span>fetchall<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">]</span>\n    <span class=\"token keyword\">return</span> data</code></pre></div>\n<p>这里有两点需要说明：</p>\n<ul>\n<li>明明 <code class=\"language-text\">mysqlUtils</code> 是在 <code class=\"language-text\">common</code> 文件夹中，而这里却直接引入 <code class=\"language-text\">mysqlUtils</code> ，稍后在配置文件中会说明</li>\n<li>查询函数 <code class=\"language-text\">get_users()</code> 为何写在这里。其实也可以写在 <code class=\"language-text\">mysqlUtils.py</code> 中，但是因为 <code class=\"language-text\">mysqlUtils.py</code> 是在 <code class=\"language-text\">Layer</code> 层，而 <code class=\"language-text\">Layer</code> 层的部署目前使用情况来看，比函数组件部署要耗时更长，因此我把它放在需要使用的函数文件中。即尽量不去修改 <code class=\"language-text\">common</code> 里的文件。</li>\n</ul>\n<p>准备就绪后就可以部署函数了。首先仍然是创建配置文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"93776822461698740000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`touch serverless.yml`, `93776822461698740000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">touch</span> serverless.yml</code></pre></div>\n<p>编辑配置文件：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"42047897085119760000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`component: scf # 注意，这里使用的是scf组件\nname: userdata\nstage: dev\napp: labelhub-dashboard\norg: labelhub-dashboard\n\n#组件参数\ninputs:\n  name: \\${name}-\\${stage}-\\${app} #函数名称\n  src:\n    src: ./ #代码路径\n    exclude:\n      - .env\n  handler: index.main_handler #入口\n  runtime: Python3.6 # 云函数运行时的环境\n  region: ap-guangzhou # 云函数所在区域\n  layers:\n    - name: commonfiles\n      version: 1\n  events: # 触发器\n    - apigw: # 网关触发器\n        parameters:\n          endpoints:\n            - path: /\n              method: GET`, `42047897085119760000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">component: scf <span class=\"token comment\"># 注意，这里使用的是scf组件</span>\nname: userdata\nstage: dev\napp: labelhub-dashboard\norg: labelhub-dashboard\n\n<span class=\"token comment\">#组件参数</span>\ninputs:\n  name: <span class=\"token variable\">${name}</span>-<span class=\"token variable\">${stage}</span>-<span class=\"token variable\">${app}</span> <span class=\"token comment\">#函数名称</span>\n  src:\n    src: ./ <span class=\"token comment\">#代码路径</span>\n    exclude:\n      - .env\n  handler: index.main_handler <span class=\"token comment\">#入口</span>\n  runtime: Python3.6 <span class=\"token comment\"># 云函数运行时的环境</span>\n  region: ap-guangzhou <span class=\"token comment\"># 云函数所在区域</span>\n  layers:\n    - name: commonfiles\n      version: <span class=\"token number\">1</span>\n  events: <span class=\"token comment\"># 触发器</span>\n    - apigw: <span class=\"token comment\"># 网关触发器</span>\n        parameters:\n          endpoints:\n            - path: /\n              method: GET</code></pre></div>\n<p>通过配置文件，我们可以发现，其中的 <code class=\"language-text\">layers</code> 配置中的 <code class=\"language-text\">name</code> 以及 <code class=\"language-text\">version</code> ，就是在部署 <code class=\"language-text\">common</code> 时的名称和部署成功后的版本号。</p>\n<p>最后执行 <code class=\"language-text\">sls deploy</code> 完成部署，直接访问生成的 <code class=\"language-text\">url</code> 地址，可以查看到正确的返回信息。</p>\n<p><strong>小结</strong></p>\n<p>最终文件夹的结构为：</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"26274411827127640000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"代码复制成功\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`labelhub-dashboard/\n------------------serverless.yml\n------------------common/\n------------------------requirements.txt\n------------------------serverless.yml\n------------------------mysqlUtils.py\n------------------user-data/\n---------------------------serverless.yml\n---------------------------index.py`, `26274411827127640000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                复制代码<svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\">labelhub-dashboard/\n------------------serverless.yml\n------------------common/\n------------------------requirements.txt\n------------------------serverless.yml\n------------------------mysqlUtils.py\n------------------user-data/\n---------------------------serverless.yml\n---------------------------index.py</code></pre></div>\n<p>在部署 <code class=\"language-text\">user-data</code> 函数时，我们看到引入 <code class=\"language-text\">mysqlUtils</code> ，是通过直接引入的方式，而在 <code class=\"language-text\">user-data</code> 函数的配置文件中可以看到我们使用了对应的 <code class=\"language-text\">layers</code> 配置。从这里可以看出，在函数的配置中，<code class=\"language-text\">layers</code> 其实就相当于 <code class=\"language-text\">v1</code> 中的  <code class=\"language-text\">include</code> 配置，默认 <code class=\"language-text\">Layer</code> 组件中的文件与函数文件在相同目录下。</p>\n<p>其实我们可以将所有文件创建好后，在根目录中执行 <code class=\"language-text\">sls deploy --all</code> 来一次性进行部署，但在使用过程中会出现函数组件部署报错，找不到对应的 <code class=\"language-text\">Layer</code> 组件，这也是因为函数组件部署过程中会去读取 <code class=\"language-text\">layers</code> 的配置，而通过实际使用过程中发现 <code class=\"language-text\">Layer</code> 组件的部署几乎都会比函数组件慢很多，因此官方也是建议优先部署 <code class=\"language-text\">Layer</code> 组件，之后再统一部署函数组件。那么我们就需要考虑，函数的应用根目录，是否可以和公共组件目录同级，这样在使用 <code class=\"language-text\">sls deploy --all</code> 的时候，才可以避免同时更新 Layer 层。</p>\n<p>至此，简单的后端开发环境就已经搭建好了，相比于官方提供的文档的示例，完善了对于实际开发过程中三方依赖和公共函数的处理，后续开发过程中若需要更多依赖，只需要在对应的组件中进行添加即可，而对于功能模块的扩展，也只需要创建相应的目录去进行扩展。</p>\n<p>后面的文章，我会详细介绍对于单个模块功能的开发过程，更多依赖的添加进行尝试，尽可能按照实际开发过程来进一步优化项目的结构。</p>\n<blockquote>\n<p><strong>参考链接：</strong></p>\n<ol>\n<li><a href=\"https://app.labelhub.cn\">Labelhub</a></li>\n<li><a href=\"https://cloud.tencent.com/document/product/1154\">腾讯云 Serverless Framework</a></li>\n<li><a href=\"https://www.serverlesschina.com/post/37.html\">Serverless Framework Cli 的版本进化</a></li>\n<li><a href=\"https://cloud.tencent.com/document/product/1154/48261\">应用管理中的多实例管理</a></li>\n</ol>\n</blockquote>\n<hr>\n<hr>\n<div id='scf-deploy-iframe-or-md'></div>\n<hr>\n<p>欢迎访问：<a href=\"https://serverlesscloud.cn/\">Serverless 中文网</a>，您可以在 <a href=\"https://serverlesscloud.cn/best-practice\">最佳实践</a> 里体验更多关于 Serverless 应用的开发！</p>","tableOfContents":"<ul>\n<li><a href=\"/best-practice/2020-10-12-labelhub/#%E5%89%8D%E8%A8%80\">前言</a></li>\n<li><a href=\"/best-practice/2020-10-12-labelhub/#%E6%A6%82%E8%A6%81%E8%AF%B4%E6%98%8E\">概要说明</a></li>\n<li><a href=\"/best-practice/2020-10-12-labelhub/#%E9%A1%B9%E7%9B%AE%E6%9E%84%E5%BB%BA\">项目构建</a></li>\n<li><a href=\"/best-practice/2020-10-12-labelhub/#%E9%A1%B9%E7%9B%AE%E5%AE%9E%E8%B7%B5\">项目实践</a></li>\n</ul>"},"previousBlog":{"id":"4c8dfa44-dbb1-5dce-8485-456a0bf8ff53","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/20201026/1603696069933-1603694644424-%E8%B7%A8%E5%A2%83%E7%94%B5%E5%95%86.jpg","authors":["侯颖堃"],"categories":["best-practice"],"date":"2020-10-26T00:00:00.000Z","title":"专访：跨境电商 SaaS ERP 领星完成 7000 万人民币 A 轮融资的背后","description":"ERP on Tencent Serverless","authorslink":null,"translators":null,"translatorslink":null,"tags":["Serverless","ERP"],"keywords":"Serverless Framework,Serverless,SCF,ERP,SAAS,领星","outdated":null},"wordCount":{"words":188,"sentences":28,"paragraphs":28},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-10-26-lingxing.md","fields":{"slug":"/best-practice/2020-10-26-lingxing/","keywords":["serverless","云函数","Serverless","腾讯","技术","开发人员","业务","领星","网络科技","颖堃","SaaS","开发"]}},"nextBlog":{"id":"4af7123d-e5b7-5c3d-9c99-d85c35c84898","frontmatter":{"thumbnail":"https://img.serverlesscloud.cn/2020930/1601452545995-1601451648554-%E5%BE%AE%E4%BF%9Djpg.jpg","authors":["Weibao"],"categories":["best-practice"],"date":"2020-09-28T00:00:00.000Z","title":"微保的 Serverless 云函数实践之路","description":"微保 Serverless 实践之架构演进","authorslink":null,"translators":null,"translatorslink":null,"tags":["Serverless","架构设计"],"keywords":"Serverless Framework,Serverless,SCF","outdated":null},"wordCount":{"words":369,"sentences":79,"paragraphs":79},"fileAbsolutePath":"/opt/build/repo/content/best-practice/2020-09-28-weibao.md","fields":{"slug":"/best-practice/2020-09-28-weibao/","keywords":["serverless","云函数","函数","日志","架构","Serverless","团队","业务","中间层","serverlesscloud","微保"]}}},"pageContext":{"isCreatedByStatefulCreatePages":false,"blogId":"7095aff6-92f7-584e-9803-b6f1db15e4f4","previousBlogId":"4c8dfa44-dbb1-5dce-8485-456a0bf8ff53","nextBlogId":"4af7123d-e5b7-5c3d-9c99-d85c35c84898"}}}