浅析小程序云原生数据库的设计与应用

2020 年 6 月 05 日

浅析小程序云原生数据库的设计与应用

导语

小程序云开发拥有易接入、高性能、高可用等特性,提供完整的原生云端能力支持,可有效降低后端与运维成本,帮助开发者更专注于业务,实现快速上线与迭代。其中,小程序云开发的数据库是一个既可在小程序前端操作、也能在云函数中读写的 JSON 数据库,强大且稳定。

本篇,将简要地为大家介绍,我们是怎样为云开发构建一个安全易用、高性能和高可用的 nosql 文档型数据库。

Serverless 理念引领新的开发趋势

在介绍云开发数据库的架构前,我先简单介绍一下云开发数据库的设计背景。

对于小程序等应用的开发者而言,传统的开发模式和敏捷开发模式除了需要开发者编写核心的业务逻辑外,都不可避免地需要对后端的基础设施进行管控和优化。比如,一个应用的逻辑可以很简单,可一旦涉及到应用的发布部署,就需要开发者花费大量精力进行服务器、数据库、网络等基础设施的申请和搭建,还要考虑这些后端基础设施的稳定性、可用性和监控指标。这一切耗时耗力又与产品的核心功能无关,对于需要快速开发和试错的产品,传统的模式开发速度慢、部署和运维成本较高。

但通过 serverless 无服务器架构,用户可以无需关心后端的基础设施,直接通过云 API 一键接入云函数、云数据库和云存储来获取算力、数据库、存储等基础的后端能力。这种随用随取的开发模式,不但可以让开发者能更专注于自身的业务逻辑,还具有低成本、开发速度快以及免运维等诸多优势。对于小程序云开发而言,它结合了 serverless 和小程序的两者的开发理念,以微信作为小程序前端运行的依托,同时又通过接入云函数、云数据库和云存储,来达到对后端基础设施的开箱即用。这些特性可以在很大程度上解放小程序开发者的生产力,降低开发的成本和难度,让小程序开发者向全栈发展,更容易开发出稳定高效的后端服务。

例如,腾讯相册这款官方小程序就使用云开发来构建。

传统的开发模式,开发者必须从小程序端开始,发送一系列请求到后台进行鉴权,文件和数据库处理等繁琐的操作,同时也需要耗费不少精力进行许多基础服务的设计和搭建以及后期的运维等工作。

但通过云开发,开发者可以天然地获取微信的登录态、方便地获取存储和数据库等能力,其它的负载、容灾、监控等,都由云开发来负责,而这一切都对开发者是透明的。这就大大提高了开发者的效率。

通过云开发,腾讯相册小程序将开发时间由 1 周以上压缩到只有 1 到 2 天。

云开发数据库架构介绍

云数据库作为云开发中的数据库组件,具有以下几个特点:

  1. 安全性:对于数据库而言,安全性是第一位的,丢数据的情况不可容忍
  2. 易用性:云数据库开箱即用,用完即走,无需运维部署
  3. 低成本:云数据库支持按访问量、数据量收费,成本控制更精细更低廉
  4. 高性能:云数据作为一款 nosql 文档型数据库,天然具有非常高的读写性能。同时我们底层硬件也使用了固态硬盘来提供更强的读写能力
  5. 灵活性:当用户业务量扩展,需要更大规模更高性能的数据库时,云数据库也支持热迁移上云,过程用户无感知

下面,我将对云开发数据库的基本架构做一个简要的介绍

云数据的整体架构可以分为这么几部分:最上层的客户端、中间部分的接入层、底部的存储层及周边管控、告警、备份模块等

我们从最上层的客户端部分看起,开发者通过云开发提供的 SDK,可以在微信小程序和 qq 小程序中一键获取云数据库的登录态,然后将数据读写请求发送给接入层。接入层收到用户的读写请求后,由 keeper 和 agent 这两个无状态的模块对接入的读写请求进行相关处理。

其中 keeper 主要负载请求的鉴权、认证缓存,以及读写请求数的统计,是云数据库权限校验,负载均衡和计费功能实现的核心模块。同时,keeper 还对事务类的请求进行了优化,通过一致性哈希和缓存会话,keeper 会将不同事务的请求压力分摊到 agent 模块,提供更好的事务使用性能。

agent 模块则有下面几大功能:

一是维护接入层到底层数据库实例的连接池,通过复用已建立的连接来减少请求鉴权和连接创建的耗时。二是统计请求的并发数,对读写请求的 QPS 进行平滑处理,避免短时间的毛刺影响数据库性能和可用性。三是对热迁移的优化,通过 agent 模块,我们会在热迁移切换数据库实例时,将请求挂起,切换后再将请求恢复这种方式,实现热迁移过程对用户的全程无感知。

读写请求通过了接入层,再接下来会进入到我们的存储层进行数据库实例的读写。而我们的数据库实例在设计上具有如下几个特点:

一、为了保证数据库的高可用,我们的每个数据库实例都是由一个副本集整体来进行服务。

二、数据安全性方面,我们使用了一致性算法来保证副本集数据的最终一致性。通过定期备份支持用户将数据回档到指定时刻。

三、我们也充分利用云数据的日志、监控、拨测等模块收集的信息,对云数据进行了自动化的运维的相关设计,对常见数据库异常进行秒级探测和自动处理,保证用户业务平稳运行。

云开发数据库设计与优化

那么,围绕云开发数据库,我们做了哪些特性优化呢?

访问控制优化

首先是权限控制方面。用户只能访问自己的数据库, 所有连接必须 认证,用户无法访问其他用户的数据库。但可以在自己的数据库上建立多 个不同权限的账户(比如建一个只读的账户)。当然有了微信全链路免鉴权的特性,这里用户不需要太关心认证问题。

其次是连接数控制方面。我们会分两层进行控制:

1)在接入层进行 客户端连接控制,根据初始化时实例类型(免费 / 付费等)进行不同的初始化限制,如果超过限制则提示相应的用户;

2)接入层到存储层也有相应的连接数控制,会 池化 到后端数据库所有主从节点的链接,避免因过多链接而导致的数据库性能问题。

最后是机器层面的出入流量控制以及资源使用限制,原理与连接数控制类似。用户所有的请求都会经过接入层,因此可以在接入层控制 qps 进而实现后续的 按量付费 功能。qps 超过阈值后可以提示用户或者在接入层做排队处理。

PS:有人可能会质疑了,这里不是弹性伸缩的嘛?为何还有 qps 的限制呢?不应该是我 qps 越来越高,后端的数据库资源也跟着不断扩容嘛?

是的,默认的配置下会有一定弹性扩展空间,但是会有一个限制。当然,这里限制具体多少跟产品策略有关。

数据安全优化

数据安全是数据库最重要的特性之一。毕竟一个存在丢数据风险的数据库并不可能在市场激烈的竞争中活下来。那么云数据库是如何保证数据安全的呢?

1)分布式多副本容灾。云开发数据库底层默认三副本,即一份数据会存储三份放在不同的机器上。节点区分主从状态,主节点可写可读,从节点只读。存储节点之间采用 raft-like 的副本集协议来实现三副本数据的 最终一致性。另外,所有到数据库的连接必须认证以及所有数据均 加密压缩 存储这两点保证了数据的链路安全以及存储安全。

2)高可用。当机器发生故障时副本集内的数据节点会自动切换(FailOver),从节点变为主节点继续提供服务,将对业务的影响降到最低。

3)备份 / 回档能力。备份对用户 完全透明,后台根据数据库的状态自动选择性地进行全量以及增量备份;支持 7 天内任意时间回档,可以选择只回档单个库表,大大减少回档所需的时间。

另外,如果节点故障需要新加一个节点到副本集中,可选择从备份文件中进行恢复,减少对源集群的 侵入性

4)多可用区容灾。云数据库默认跨三机房(AZ)部署,也对用户透明,任意一个机房挂掉也不会对服务产生任何影响;同时也可以支持 跨多地域,两地三中心 等模式。比如北京、上海、深圳各有一个节点,业务采取就近接入的方式来降低业务访问元数据的时延。

弹性伸缩

很多时候,业务的访问呈现很明显的 周期性或者不均匀 的特征,比如外卖类业务属于饭点时高峰期,其他时段访问较少;游戏类业务属于晚上及周末高峰期,上班时间较少;还有一些电商类业务属于遇到特殊时间点(双十一,618)做活动大促时是高峰期等等。

如果按照传统的数据库运维模式,需要提前预估量级,然后运维执行扩容,等活动结束后再缩容回来(不然成本是个问题)。那么在小程序的场景,既然要做到用户对后端服务无感知,那么资源的扩缩容也应当不被感受到。

基于这个出发点,我们实现了云数据库的弹性伸缩。依赖管控系统的负载监控模块,我们可以动态地调整数据库的资源,并且自动调整敏感度,来有效应对数据库负载突增的情况,在负载低的时候也可以将资源释放提供给其他更需要的实例。其次,为了避免单个大查询引起的频繁调整,我们设置了滑动窗口和“去毛刺”机制,保证了弹性伸缩尽可能平滑地进行。

当实例状态发生变更(比如 免费–> 付费冷–> 热)的时候,可能会需要进行数据迁移,比如从性能较差的机器迁移到性能较好的机器上。

有了接入层的配合,我们实现了用户无感知的数据库热迁移。可以实现在不停服的情况下将用户的数据从一个数据库无损地迁移到另一个数据库。

智能 DBA

为了进一步减少后台侧的运维操作,我们实现了自动化运维平台。通过对运行时的存储节点状态的监控,对每个节点进行探活及故障判断,然后在决策中心根据故障的统计结果进行相应的自动化运维操作(比如磁盘只读了则强制切主)同时也会告警给运维人员,确保自动化运维结果正确。

对于一部分 自动化运维没办法覆盖 的问题,我们有各个层面和维度(机器、实例、节点等)全套的 秒级监控,各项指标共计 69+ 项,后端可以实时感知到数据库的状态;发现问题尽早处理。

索引 是数据库中非常重要的概念,用于加速数据库的查找。在小程序的场景下,我们希望将用户对于后端的数据库的认知降低到越少越好。于是实现了一系列查询优化的功能,比如 自动建索引

当我们的接入层和存储层发现用户有很多查询到后端都是全表扫描时,就会根据用户的 query 具体字段进行对应索引的添加工作。等到索引建立完成,用户就可以直接享受优化后的查询结果。重要的是,这一过程用户同样也是无感知的。

不同场景下的云开发数据库应用

电商类小程序的应用

使用基础读写能力,实现查询商品列表

使用聚合搜索,实现对商品列表的排序

使用云开发数据库的事务能力,实现下单时查询、扣除商品数量。

O2O 类小程序的应用

使用地理搜索能力,实现寻找最近的商家

社交类小程序的应用

使用实时数据推送服务,实现多人实时聊天

结语

在小程序场景下,云开发数据库围绕 数据安全易用性低成本高性能灵活性 5 个主要场景需求,进行了相应的改造及优化,使得数据库可以更加贴合小程序的使用场景。

我们也有理由相信,云开发数据库将在 serverless 理念的指导下不断完善自己,发展得越来越好。

作者介绍

腾讯 TEG 云架构平台部 研发工程师 杨哲、刘翔

腾讯 CSIG 云产品部 前端工程师 王伟嘉

2020 年 6 月 05 日 17:24 1466

评论

发布
暂无评论
发现更多内容

JAVA小抄-000-初始

NoNoGirl

JAVA stream

重新认识Go语言中的slice

麻瓜镇

golang

金融「中台」十宗罪

fino星君

中台 企业中台 业务中台

centos7 maven私服自动启动

kcnf

[读书随笔]从哲学上的问题分类看TDD

老狗

哲学 TDD

瞎琢磨先生の好物推荐(软件/网站)

瞎琢磨先生

关于GDB你需要知道的技巧

this_is_for_u

c c++ C#

瞎琢磨先生の常用的 linux 命令

瞎琢磨先生

Linux Shell

如何利用数据异构实现多级缓存或者数据迁移

松花皮蛋me

缓存 分布式 分库分表

Redis学习笔记(基础命令)

编程随想曲

redis

开始每周写作计划

M1racle

DDD 实践手册(4. Aggregate — 聚合)

Joshua

设计模式 领域驱动设计 架构模式

写作的意义到底是什么

七镜花园-董一凡

写作

习惯与惯性

伯薇

个人成长 习惯 习惯养成 提升能力

C++定时器的实现

this_is_for_u

c c++ C#

《TCP/IP详解》概述

网瘾少年SEC

TCP 网络协议 IP

当我们谈到ThreadLocal的时候,我们在谈什么?

Jason

Java 多线程 ThreadLocal

我也曾对架构师的力量一无所知

曲水流觞TechRill

对你来说,阅读是另一种生活的方式吗?

叶小鍵

读懂才会用 : Redis的多线程

小眼睛聊技术

Java redis 程序员 编程语言 后端

翻译和产品本地化的区别是什么?

葛仲君

翻译 本地化 全球化 产品开发

基于vue(element ui) + ssm + shiro 的权限框架

吴邪

如何对Code Review的评论进行分级

宝玉

代码审查 Code Review

机会是留给不停寻找他们的人,而不是原地等待的人

非著名程序员

程序员 提升认知 机会 行动派

面试指南 | 终于要跟大家见面了,我有点紧张。

Apache Flink

大数据 flink 流计算 实时计算 大数据处理

如何成为有效学习的高手(含思维导图)

lmymirror

读书笔记 高效学习 刻意学习 高手 思维导图

准备重读测试驱动开发

escray

学习日记 CSD 认证实战营

婚姻就是合伙开公司,各自做好自己的工作很重要

鼎玉谷

管理 婚姻 公司 付出 人情

C++线程池的实现

this_is_for_u

c++ C# 线程池

笔记:《如何系统思考》之如何做到系统思考

wiflish

思维方式

Clickhouse 性能测试

久吾尔岂

浅析小程序云原生数据库的设计与应用-InfoQ