最近我们将一部分Web及后台业务迁移到了腾讯云Tab平台上,大部分过程都是很舒爽的,剩下的一些小坑或者一些常见问题的解决方案罗列在这里做以分享,希望对大家有所帮助。
一、Tab的简单介绍
TAB(移动开发工具)是腾讯云和LeanCloud联合推出,适合快速构建中小型移动应用的平台。官方文档链接:https://tab.leancloud.cn/docs/。虽说更适用于移动应用开发,经我们实践,其在Web应用的构建方面也是可以胜任的,正如题目所言,开始Web构建之旅吧~
二、如果你想要搭建一个DEMO
TAB目前是提供免费版本的,功能基本不受限,只不过资源受限,因此可以0花费的尝鲜一下。官网有很多的Demo,对于Web开发来说,小编更推荐一个名为TODO的Demo。跟随其中指引及云引擎快速入门便可以轻松搭建出一个NodeJS的开发环境并部署到云端。此外,强烈建议安装一个云引擎命令行工具。此工具可以很方便的将代码直接部署到云端,而不用Commit到GitHub,然后再从网页交互界面点击部署按钮,可以使整个开发过程更为丝滑~
三、后台开发语言应该如何选择 ?
虽然TAB提供了四种可以选择的语言:NodeJS,Python,JAVA,PHP,小编尝试了Python和NodeJS两种,对另外两种只有皮毛了解。下面是给大家的建议:
如果做业务迁移,使用原有语言,修改数据库相关接口操作即可。
如果从头开始做的项目,可优先考虑NodeJS和Python,因为其开发效率较高。
在NodeJS和Python之间选择的话,如果从没接触过NodeJS或对异步编程比较不感冒的情况下,选择Python比较好(Django可能不可用),代码清晰并且可维护性好。
如果想尝试下NodeJS或者这是你的主流开发语言,选择NodeJS就好。
四、HTML渲染模版如何选择?
根据你使用的Web框架的不同,HTML模版的选择可能也是有限的。在前面提到的TODODEMO中,其使用了jade模版,为了尝鲜,小编也使用了一下。使用感受如下:
* 语法简洁可能是其jade给人的第一印象,可以显著减少代码量。。。
* 在WebStorm IDE中,其语法高亮及自动补充目前还不是很完善。
* 其继承机制很是强大,可以更好的组织模版结构。
* 不好的消息是,它长得跟其他模版差异太大,迁移代码时会想哭。
* 好一点的消息是,它也支持HTML代码块,可以让代码迁移多一些便利。
如果没有特殊需求,模版尽量接近原生HTML就好了,尽可能将代码移至JS以减少对模版的依赖,日后做代码迁移,需要更换模版时,就会将代码改动量降到最低。
五、数据库有哪些注意事项
数据存储服务是TAB的核心服务,无论后台还是客户端,都是通过网络请求来查询或者存储数据。而TAB的计价方式是数据请求量,每月100W免费额度,超过部分要付费~ 后文会提到减少请求量的一些方式,或许这就是本文的精髓了~.~
先说正题,TAB的数据存储不像传统的关系型数据库,其更像NoSQL数据库MongoDB,一个重要的区别是,你不需要再为表建立索引了。当然,在控制台的"存储-数据"页面,你仍然可以看到索引设置,但一定注意,这不是用来加快查询的。其为唯一索引,目的是保证不会有重复数据。
官方文档提供了两种数据存储相关的指南,数据存储开发指南及数据模型设计指南,分别主要侧重于数据创建、查询等客户端常用操作及数据模型的设计准则。
你可以在使用过程中,对表的结构作出修改,但是据其文档所说,当数据表数据量大于一定阈值时(现在我又找不到具体在哪里看到的了),将不允许变更表的结构。此外,单条记录的大小是受限的(128KB)。
云引擎免费版本中,会有数据请求并发量的限制,当并发请求量大于30时,会引发错误码为403的错误(Msg:Too many requests.) 。此问题的发生场景一般是进行批量操作,例如保存一组记录,在NodeJS或者JAVA中,默认是异步进行,所以请求会并发进行,解决方案有两个:
当有批量操作接口可以使用时,使用批量接口代替。
对请求操作附加随机时延,将请求时间分散开来。
另外,最为关键的一点,单次查询返回数据量的默认值为100个,可手动设置Limit将这个值提升至1000,如果想要更多数据量,只能分次取出并且合并了,可以参考这里。
六、其他注意事项
在Web应用场景中,一定,一定,一定要为TAB数据存储相关操作(find, save)做一层封装以便可以做一些额外的处理。例如,可以实现findAll() 以返回全部查询数据而非最多1000条。
查阅文档阅读:Query 时 include 语句的使用场景。
在NodeJS中,如果自己编写的函数中有异步操作,尽量使用Promise以保持一致。
云引擎在切换到正式版后,需要增加一条命令 lean pulish 以部署到正式环境。
七、如何减少请求量 ?
在使用过一段时间后,你会发现每月的100万免费请求量根本不够用啊~尤其是对于我们的业务(上报,监控,分析) 更是如此。这时有两条路摆在眼前:
产品经理式思维:这些上报都是我们需要的吗?把"性价比"最低的的那些不上报了吧
赵日天式思维:我不服,我不管,就要上!
我们最终选择了后者,起码现在不是死胡同,还是有优化区间的。
我们提出了两种方案以减少请求量,这两种方案适用于不同的场景。
方案一、留下需要查询的公用字段,合并记录中值有差别的字段到一个Merge字段中
具体实现为:提供一个批量保存的CGI,其将原有的多条记录重新组织对象结构,合并多条记录中值不同的字段为一个列表并作为一条记录的一个字段存储,从而将多条记录合并为一条记录。
那么问题来了,我已经写好的代码岂不是又要大改?
经过我们的实践,并不用改动上层代码,因为我们使用了自己包装过的find函数,在查询结果返回后,如果发现有些字段是被合并的,我们会将其直接展开并将展开后的结果返回,在上层代码看来,这个过程是几乎透明的。但需要注意的是,对展开后的对象最好不要进行save()操作,因为这将导致创建一条新的记录。
这也是前面强烈建议对Tab数据存储操作进行封装的原因,可以允许我们实现额外的逻辑层。
方案二、利用内存缓存,对已知没有数据改动的save() 操作进行忽略处理。
方案一可以将多条记录合并为一条减少请求量,但其适用场景为上报类数据(数据是不会改动的,最为统计分析用)。如果数据表为逻辑类数据(数据总量不大,但是有非常频繁的update操作),方案一是没有效果的。
有一个怪圈是:客户端想保存(更新)一条数据时,它不确定这条数据在服务端是否已经存在了,如果查询是否存在,还要额外浪费一条请求量(并且耗时)。如果建立唯一索引,又会导致变更的数据改动被拒绝保存。
我们的方案是一个曲折的方案:服务端提供一个save的CGI,这个CGI真的做了很多的事情。。。
我们先深呼吸一口气~
首先,你要为目标的表指定一组唯一索引的字段,用来说明这些字段相同的即为同一条数据,一张表中仅能出现一次。当第一条存储请求到来时,保存到数据库后,会计算这条记录的唯一索引字段值的MD5值,剩余字段值的MD5值,并以唯一索引MD5值为Key将上述信息连同保存后ObjectId缓存到内存,当另一条记录到来时,会有三种情况方式对应于不同的处理方式:
当这条记录的唯一索引MD5在内存缓存没有发现,被认为是一条新的记录,将会进行"查询-创建/更新"操作。
当其唯一索引MD5在内存缓存命中,但是又发现其他字段值发生了变更,便可根据缓存中记录的objectId直接更新,而不用进行上一步需要的"查询"操作。
当唯一索引MD5命中并且剩余字段MD5值同样没有变,便会能为这条数据并没有发生变动,直接忽略就好,不会产生任何请求量。
此外,我们会定期将内存缓存同步到数据库固化存储,以便在服务重启时可以继续利用以往的缓存数据。
-------------------------------
与上文相关的大部分内容都封装在我们项目的 TabUtil.js 及 TabBridge.js 中。
TabUtil.js 为一个封装的工具类,负责对find, save 操作的封装,能力主要有失败时自动重试,find() 操作返回所有记录而非最多1000条,及将合并后的字段自动展开为多条记录。
TabBridge.js 提供了更像是服务端后台的能力,例如提供了基于内存缓存的save() 操作接口及将多条数据合并为一条的CGI。
如果想了解其实现细节或者复用这些代码,请@Masterkang -- [email protected]