基于 Serverless 架构的编程学习小工具

以前我作过一个在线编程的软件,目前用户量大概有几十万,经过这个 App 不只仅能够进行代码的编写、运行还能够进行编程的学习。本身一直对 Serverless 架构情有独钟,刚好赶到个人这个 App 学习板块被不少人吐槽难用,索性就对这个学习板块进行重构,而且打算在重构的时候,直接将这个学习板块搬上 Serverless 架构。前端

本文做者 Anycodespython

基于 Serverless 架构重构是出于两个方面考虑 —— 一是 Serverless 架构能让我的开发者的运维工做变得简单,尤为是不用操心服务器,也不用关心流量洪峰(固然,对于个人我的项目而言,也没太多的洪峰),二是 Serverless 架构的按量付费,极大节约了成本。mysql

总体设计

数据库设计

这个部分在以前是若干个大模块,如今统一整理到一个模块中进行项目重构,因此这里继续复用以前的数据库:git

在这个数据库中,四个模块分别是:新闻文章、开发文档、基础教程以及图书资源。其中开发文档包括大分类,子列表以及正文等内容,这里表关联并无使用外键,而是直接用的 ID 进行表之间的关联。github

说实话,这个数据库设计的并非很好,缘由是由于初次构建这个数据部分,绝大部分数据都是在其余站点采集而来,当时因为模块快速上线,便直接按照原有格式存储,因此能够认为这个数据库中有不少表的字段实际上是无效的,或者针对这个项目是未被使用的。web

后端设计

后端将会总体部署到一个函数上,功能总体结构:sql

总体功能就是云函数 SCF 绑定 API 网关触发器,用户访问 API 网关指定的地址,触发云函数,而后函数在入口处进行功能拆分,请求不一样的方法得到对应的数据。数据库

这里要额外说明一下,后端总体接口部署在一个函数的缘由,是由于我这个模块的使用量并非很是频繁,因此部署到一个函数上也不会出现超过最大实例的限制,若是超出限制是能够申请扩容的;express

其次,全部的接口都是对数据库增删改查,放入到一个函数中,在必定程度上能够保证容器的活性,下降部分冷启动带来的问题,同时容器的复用,也能够在必定程度上下降后台数据库连接池的压力;除此以外,全部的接口功能,都是只须要最少的内存(64M)便可完整运行,不会由于个别接口的预估内存较大,进而影响影响总体的成本。编程

因此这里评估以后,是能够将多个接口,放入到一个函数中,对外提供对应的服务。

前端设计

前端设计,预计在学习资源部分须要有 8 个页面,主要就是科技类新闻、教程、文档、图书等相关功能,经过墨刀绘制的原型图以下:

前端项目开发将会采用 Vue.js,而且将其部署到对象存储中,经过腾讯云对象存储的静态网站功能对外提供服务。

项目开发

后端函数开发

后端函数开发主要包括三部分

  • 部分资源的初始化,部分资源初始化,须要在函数外进行,这样能够保证复用实例的时候不会再次创建连接,防止数据库链接池出现问题:
def getConnection(dbName):
    conn = pymysql.connect(host="",
                           user="root",
                           password="",
                           port=3306,
                           db=dbName,
                           charset='utf8',
                           cursorclass=pymysql.cursors.DictCursor,
                           )
    conn.autocommit(1)
    return conn


connectionArticle = getConnection("anycodes_article")
  • 数据库查询操做

这一部分主要就是针对不一样接口查询数据库,例如获取文章分类:

def getArticleCategory():
    connectionArticle.ping(reconnect=True)
    cursor = connectionArticle.cursor()
    search_stmt = ('SELECT * FROM `category` ORDER BY `sort`')
    cursor.execute(search_stmt, ())
    data = cursor.fetchall()
    cursor.close()
    result = {}
    for eve_data in data:
        if eve_data['pre_name'] not in result:
            result[eve_data['pre_name']] = []
        result[eve_data['pre_name']].append({
            "id": eve_data["sort"],
            "name": eve_data["name"]
        })
    return result

例如获取文章列表:

def getArticleList(cid):
    connectionArticle.ping(reconnect=True)
    cursor = connectionArticle.cursor()
    search_stmt = ('SELECT * FROM `article` WHERE `category` = %s ORDER BY `sort`')
    cursor.execute(search_stmt, (cid,))
    data = cursor.fetchall()
    cursor.close()
    result = [{
                "id": eve_data["aid"],
                "title": eve_data["title"]
            } for eve_data in data]
    return result
  • 最后一部分就是函数的入口,函数入口部分就是作功能分发和接口识别:
def main_handler(event, context):
    try:
        result_data = {
            "error": False
        }
        req_type = event["pathParameters"]["type"]
        if req_type == "get_book_list":
            result_data["data"] = getBookList()
        elif req_type == "get_book_info":
            result_data["data"] = getBookContent(event["queryString"]["id"])
        elif req_type == "get_daily_content":
            result_data["data"] = getDailyContent(event["queryString"]["id"])
        elif req_type == "get_daily_list":
            result_data["data"] = getDailyList(event["queryString"]["category"])
        elif req_type == "get_dictionary_result":
            result_data["data"] = getDictionaryResult(event["queryString"]["word"])
        elif req_type == "get_dev_content":
            result_data["data"] = getDevContent(event["queryString"]["id"])
        elif req_type == "get_dev_section":
            result_data["data"] = getDevSection(event["queryString"]["id"])
        elif req_type == "get_dev_chapter":
            result_data["data"] = getDevChapter(event["queryString"]["id"])
        elif req_type == "get_dev_list":
            result_data["data"] = getDevList()
        elif req_type == "get_article_content":
            result_data["data"] = getArticle(event["queryString"]["id"])
        elif req_type == "get_article_list":
            result_data["data"] = getArticleList(event["queryString"]["id"])
        elif req_type == "get_article_category":
            result_data["data"] = getArticleCategory()
        return result_data
    except Exception as e:
        print(e)
        return {"error": True}

函数部分完成以后,能够配置 API 网关部分:

在整个后端接口开发过程当中,其实并无遇到什么太大的问题,由于这个学习功能的模块基本上就是对数据库进行查询的操做,因此相对来讲很是顺利。

效果预览

总体预览结果:一共包括十几个页面,这里取其中8个主要的页面进行效果展现:

整个页面基本上是还原了设计稿的样子,而且和原有项目进行了部分的整合,不管是列表页面仍是图书页面等,数据加载速度表现良好。

经过 PostMan 进行基本测试:

对接口进行 1000 次访问测试:

能够看到,接口表现良好,并未出现失败的状况,对该测试结果进行耗时的可视化:

其中最大的时间消耗是 219 毫秒,最小是 27 毫秒,平均值 35 毫秒,能够看到总体的效果仍是很是不错。

这样一个项目开发完成,上线以后,前端部分被放到对象存储 COS 中,后端业务被放到云函数 SCF 中,触发器使用的是 API 网关,在监控层面,函数计算有着比较不错的监控纬度:

同时函数并发,弹性伸缩等问题都由云厂商来解决,能够这样说,自从这个组件部署到了 Serverless 架构上,我所作的操做就是若是业务代码有问题,进行简单修复和简单维护。讲真,整个效果仍是不错的。

经过按量付费,能够看到我后端服务产生的费用:

因为云函数没办法看到单个资源的费用,因此整个函数我有几十个,一共花费的费用也远远比服务器的一个月便宜不少。

固然虽说在计算服务这里总体费用只有几元钱相对来讲很是便宜,可是其还有 API 网关的费用和对象存储的费用,例如 API 网关费用:

一样,我这里的 API 网关也是有不少服务的,不只仅是 Anycodes 这样一个服务产生的,可是总体加一块儿 2 月份只有 1 元钱,相对来讲也是蛮低的。

总结

经过我的项目中的一个子模块重构过程,将该项目部署到 Serverless 架构上:

  • 在开发过程当中,我以为是蛮方便的,一方面本身不须要在服务器中安装各种软件,也不须要搭建 web 服务,不须要对 web 服务进行优化,作的只是读取数据库,按照必定的格式进行 return,至于 web 服务等相关模块交给 API 网关来实现,整个一个后端开发大概耗时大约是一个多小时;前端开发是比较耗时的,由于我我的不是专业作前端的,因此不管是布局仍是逻辑开发,都是有点障碍的,可是也只用了 2 天时间;因此这个模块从开发到上线只用了 2 天时间;

  • 项目在部署的时候很是流畅,基于 Serverless Framework 的开发者工具一键部署,后期更新维护,只须要从新部署便可,线上也是无缝切换,不会出现更新服务形成的服务中断,也不用为更新服务可能形成服务中断而作额外的操做,总体后期更新过程快速且简单易用;

  • 资源消耗部分就是使用按量付费,经过一个月的观察,整个资源消耗是蛮低的,总体性能保证的同时,成本也逐渐的被压低,对于我的开发者来讲,确实是一个福音。

经过这样一个简单上 Serverless 架构的过程,也让我对 Serverless 架构有了更深刻的了解和认识,做为一种新技术或者说新的架构,Serverless 的成长还须要一段时间。可是我相信,他的成长,会很快速。

Serverless Framework 30 天试用计划

咱们诚邀您来体验最便捷的 Serverless 开发和部署方式。在试用期内,相关联的产品及服务均提供免费资源和专业的技术支持,帮助您的业务快速、便捷地实现 Serverless!

详情可查阅:Serverless Framework 试用计划

One More Thing

3 秒你能作什么?喝一口水,看一封邮件,仍是 —— 部署一个完整的 Serverless 应用?

复制连接至 PC 浏览器访问:https://serverless.cloud.tencent.com/deploy/express

3 秒极速部署,当即体验史上最快的 Serverless HTTP 实战开发!

传送门:

欢迎访问:Serverless 中文网,您能够在 最佳实践 里体验更多关于 Serverless 应用的开发!


推荐阅读:《Serverless 架构:从原理、设计到项目实战》

相关文章
相关标签/搜索