写点什么

云上成本贵,用 tidb

  • 2024-01-05
    北京
  • 本文字数:7767 字

    阅读完需:约 25 分钟

原文来源:https://tidb.net/blog/d267f7d3


aws 的费用是非常贵的云上 rds 的费用更高。我来给出一组数据。如果全部用 aws 来储存数据。一个月的费用是 500w 美元左右。某某某公司。


于是乎 dba 中的冯大嘴喊出了云数据库就是杀猪盘。让每个公司自建数据库。



云上数据疯狂扩张,阿里巴巴是十几万个数据库。开发了 tddl。放弃了 oracle,选择自建


云下也有几百上千个数据库。数据库多,一直告警。管又管不过来怎么办。


一堆告警。


前言

在高并发系统当中,分库分表是必不可少的技术手段之一,同时也是 BAT 等大厂面试时,经常考的热门考题。


你知道我们为什么要做分库分表吗?


这个问题要从两条线说起:垂直方向 和 水平方向。

1 垂直方向

垂直方向主要针对的是业务,下面聊聊业务的发展跟分库分表有什么关系。

1.1 单库

在系统初期,业务功能相对来说比较简单,系统模块较少。


为了快速满足迭代需求,减少一些不必要的依赖。更重要的是减少系统的复杂度,保证开发速度,我们通常会使用单库来保存数据。


系统初期的数据库架构如下:



此时,使用的数据库方案是:一个数据库包含多张业务表。 用户读数据请求和写数据请求,都是操作的同一个数据库。

1.2 分表

系统上线之后,随着业务的发展,不断的添加新功能。导致单表中的字段越来越多,开始变得有点不太好维护了。


一个用户表就包含了几十甚至上百个字段,管理起来有点混乱。


这时候该怎么办呢?


答:分表。


将用户表拆分为:用户基本信息表 和 用户扩展表。



用户基本信息表中存的是用户最主要的信息,比如:用户名、密码、别名、手机号、邮箱、年龄、性别等核心数据。


这些信息跟用户息息相关,查询的频次非常高。


而用户扩展表中存的是用户的扩展信息,比如:所属单位、户口所在地、所在城市等等,非核心数据。


这些信息只有在特定的业务场景才需要查询,而绝大数业务场景是不需要的。


所以通过分表把核心数据和非核心数据分开,让表的结构更清晰,职责更单一,更便于维护。


除了按实际业务分表之外,我们还有一个常用的分表原则是:把调用频次高的放在一张表,调用频次低的放在另一张表。


有个非常经典的例子就是:订单表和订单详情表。

1.3 分库

不知不觉,系统已经上线了一年多的时间了。经历了 N 个迭代的需求开发,功能已经非常完善。


系统功能完善,意味着系统各种关联关系,错综复杂。


此时,如果不赶快梳理业务逻辑,后面会带来很多隐藏问题,会把自己坑死。


这就需要按业务功能,划分不同领域了。把相同领域的表放到同一个数据库,不同领域的表,放在另外的数据库。


具体拆分过程如下:



将用户、产品、物流、订单相关的表,从原来一个数据库中,拆分成单独的用户库、产品库、物流库和订单库,一共四个数据库。


在这里为了看起来更直观,每个库我只画了一张表,实际场景可能有多张表。


这样按领域拆分之后,每个领域只用关注自己相关的表,职责更单一了,一下子变得更好维护了。

1.4 分库分表

有时候按业务,只分库,或者只分表是不够的。比如:有些财务系统,需要按月份和年份汇总,所有用户的资金。


这就需要做:分库分表了。


每年都有个单独的数据库,每个数据库中,都有 12 张表,每张表存储一个月的用户资金数据。



这样分库分表之后,就能非常高效的查询出某个用户每个月,或者每年的资金了。


此外,还有些比较特殊的需求,比如需要按照地域分库,比如:华中、华北、华南等区,每个区都有一个单独的数据库。


甚至有些游戏平台,按接入的游戏厂商来做分库分表。

2 水平方向

水分方向主要针对的是数据,下面聊聊数据跟分库分表又有什么关系。

2.1 单库

在系统初期,由于用户非常少,所以系统并发量很小。并且存在表中的数据量也非常少。


这时的数据库架构如下:



此时,使用的数据库方案同样是:一个 master 数据库包含多张业务表。


用户读数据请求和写数据请求,都是操作的同一个数据库,该方案比较适合于并发量很低的业务场景。

2.2 主从读写分离

系统上线一段时间后,用户数量增加了。


此时,你会发现用户的请求当中,读数据的请求占据了大部分,真正写数据的请求占比很少。


众所周知,数据库连接是有限的,它是非常宝贵的资源。而每次数据库的读或写请求,都需要占用至少一个数据库连接。


如果写数据请求需要的数据库连接,被读数据请求占用完了,不就写不了数据了?


这样问题就严重了。


为了解决该问题,我们需要把读库和写库分开。


于是,就出现了主从读写分离架构:



考虑刚开始用户量还没那么大,选择的是一主一从的架构,也就是常说的一个 master 一个 slave。


所有的写数据请求,都指向主库。一旦主库写完数据之后,立马异步同步给从库。这样所有的读数据请求,就能及时从从库中获取到数据了(除非网络有延迟)。


读写分离方案可以解决上面提到的单节点问题,相对于单库的方案,能够更好的保证系统的稳定性。


因为如果主库挂了,可以升级从库为主库,将所有读写请求都指向新主库,系统又能正常运行了。


读写分离方案其实也是分库的一种,它相对于为数据做了备份,它已经成为了系统初期的首先方案。


但这里有个问题就是:如果用户量确实有些大,如果 master 挂了,升级 slave 为 master,将所有读写请求都指向新 master。


但此时,如果这个新 master 根本扛不住所有的读写请求,该怎么办?


这就需要一主多从的架构了:



上图中我列的是一主两从,如果 master 挂了,可以选择从库 1 或从库 2 中的一个,升级为新 master。假如我们在这里升级从库 1 为新 master,则原来的从库 2 就变成了新 master 的的 slave 了。


调整之后的架构图如下:



这样就能解决上面的问题了。


除此之外,如果查询请求量再增大,我们还可以将架构升级为一主三从、一主四从 … 一主 N 从等。

2.3 分库

上面的读写分离方案确实可以解决读请求大于写请求时,导致 master 节点扛不住的问题。但如果某个领域,比如:用户库。如果注册用户的请求量非常大,即写请求本身的请求量就很大,一个 master 库根本无法承受住这么大的压力。


这时该怎么办呢?


答:建立多个用户库。


用户库的拆分过程如下:



在这里我将用户库拆分成了三个库(真实场景不一定是这样的),每个库的表结构是一模一样的,只有存储的数据不一样。

2.4 分表

用户请求量上来了,带来的势必是数据量的成本上升。即使做了分库,但有可能单个库,比如:用户库,出现了 5000 万的数据。


根据经验值,单表的数据量应该尽量控制在 1000 万以内,性能是最佳的。如果有几千万级的数据量,用单表来存,性能会变得很差。


如果数据量太大了,需要建立的索引也会很大,从小到大检索一次数据,会非常耗时,而且非常消耗 cpu 资源。


这时该怎么办呢?


答:分表,这样可以控制每张表的数据量,和索引大小。


表拆分过程如下:



我在这里将用户库中的用户表,拆分成了四张表(真实场景不一定是这样的),每张表的表结构是一模一样的,只是存储的数据不一样。


如果以后用户数据量越来越大,只需再多分几张用户表即可。

2.5 分库分表

当系统发展到一定的阶段,用户并发量大,而且需要存储的数据量也很多。这时该怎么办呢?


答:需要做分库分表。


如下图所示:



图中将用户库拆分成了三个库,每个库都包含了四张用户表。


如果有用户请求过来的时候,先根据用户 id 路由到其中一个用户库,然后再定位到某张表。


路由的算法挺多的:


  • 根据 id 取模,比如:id=7,有 4 张表,则 7%4=3,模为 3,路由到用户表 3。

  • 给 id 指定一个区间范围,比如:id 的值是 0-10 万,则数据存在用户表 0,id 的值是 10-20 万,则数据存在用户表 1。

  • 一致性 hash 算法


这篇文章就不过多介绍了,后面会有文章专门介绍这些路由算法的。

3 真实案例

接下来,废话不多说,给大家分享三个我参与过的分库分表项目经历,给有需要的朋友一个参考。

3.1 分库

我之前待过一家公司,我们团队是做游戏运营的,我们公司提供平台,游戏厂商接入我们平台,推广他们的游戏。


游戏玩家通过我们平台登录,成功之后跳转到游戏厂商的指定游戏页面,该玩家就能正常玩游戏了,还可以充值游戏币。


这就需要建立我们的账号体系和游戏厂商的账号的映射关系,游戏玩家通过登录我们平台的游戏账号,成功之后转换成游戏厂商自己平台的账号。


这里有两个问题:


  1. 每个游戏厂商的接入方式可能都不一样,账号体系映射关系也有差异。

  2. 用户都从我们平台登录,成功之后跳转到游戏厂商的游戏页面。当时有 N 个游戏厂商接入了,活跃的游戏玩家比较多,登录接口的并发量不容小觑。


为了解决这两个问题,我们当时采用的方案是:分库。即针对每一个游戏都单独建一个数据库,数据库中的表结构允许存在差异。



我们当时没有进一步分表,是因为当时考虑每种游戏的用户量,还没到大到离谱的地步。不像王者荣耀这种现象级的游戏,有上亿的玩家。


其中有个比较关键的地方是:登录接口中需要传入游戏 id 字段,通过该字段,系统就知道要操作哪个库,因为库名中就包含了游戏 id 的信息。

3.2 分表

还是在那家游戏平台公司,我们还有另外一个业务就是:金钻会员。


说白了就是打造了一套跟游戏相关的会员体系,为了保持用户的活跃度,开通会员有很多福利,比如:送游戏币、充值有折扣、积分兑换、抽奖、专属客服等等。


在这套会员体系当中,有个非常重要的功能就是:积分。


用户有很多种途径可以获取积分,比如:签到、充值、玩游戏、抽奖、推广、参加活动等等。


积分用什么用途呢?


  1. 退换实物礼物

  2. 兑换游戏币

  3. 抽奖


说了这么多,其实就是想说,一个用户一天当中,获取积分或消费积分都可能有很多次,那么,一个用户一天就可能会产生几十条记录。


如果用户多了的话,积分相关的数据量其实挺惊人的。


我们当时考虑了,水平方向的数据量可能会很大,但是用户并发量并不大,不像登录接口那样。


所以采用的方案是:分表。


当时使用一个积分数据库就够了,但是分了 128 张表。然后根据用户 id,进行 hash 除以 128 取模。



需要特别注意的是,分表的数量最好是 2 的幂次方,方便以后扩容。

3.3 分库分表

后来我去了一家从事餐饮软件开发的公司。这个公司有个特点是在每天的中午和晚上的就餐高峰期,用户的并发量很大。


用户吃饭前需要通过我们系统点餐,然后下单,然后结账。当时点餐和下单的并发量挺大的。


餐厅可能会有很多人,每个人都可能下多个订单。这样就会导致用户的并发量高,并且数据量也很大。


所以,综合考虑了一下,当时我们采用的技术方案是:分库分表。


经过调研之后,觉得使用了当当网开源的基于 jdbc 的中间件框架:sharding-jdbc。


当时分了 4 个库,每个库有 32 张表。


4 总结

上面主要从:垂直和水平,两个方向介绍了我们的系统为什么要分库分表。


说实话垂直方向(即业务方向)更简单。


在水平方向(即数据方向)上,分库和分表的作用,其实是有区别的,不能混为一谈。


  • 分库:是为了解决数据库连接资源不足问题,和磁盘 IO 的性能瓶颈问题。

  • 分表:是为了解决单表数据量太大,sql 语句查询数据时,即使走了索引也非常耗时问题。此外还可以解决消耗 cpu 资源问题。

  • 分库分表:可以解决 数据库连接资源不足、磁盘 IO 的性能瓶颈、检索数据耗时 和 消耗 cpu 资源等问题。


如果在有些业务场景中,用户并发量很大,但是需要保存的数据量很少,这时可以只分库,不分表。


如果在有些业务场景中,用户并发量不大,但是需要保存的数量很多,这时可以只分表,不分库。


如果在有些业务场景中,用户并发量大,并且需要保存的数量也很多时,可以分库分表。


好了,今天的内容就先到这里。


是不是有点意犹未尽?


没关系,其实分库分表相关内容挺多的,本文作为分库分表系列的第一弹,作为一个开胃小菜吧,分享给大家。


这样就搞了一堆数据库



老板直接炸锅


有没有一种更好的办法呢?有就是同一账户数据库


在计算机行业 google 创业时搞了一堆 x86 机器做了一个 bigtable 的项目。就形成了 hadoop 的生态。


单机里面 cpu 不够用也就慢慢变成了双核 三十二核心 双路 256 核心



之前在单机数据库的时代我们没办法发明一种可以无限扩容的数据库。所以采用了分库分表的方式但是现在 tidb 一台机器就能支撑之前分库分表的环境



而且这个数据库还支撑大数据分析再也不会出现妈妈说我查不动的情况了。


测试结果比较

差距最大的 q1 q9 有 100 多倍,最小 q4 也有 5 倍



原先需要这么多数据库



原先需要 10 套 4xlarge 的数据库顶 a 业务的账户系统


再需要 10 套 4xlarge 的数据库顶 b 业务的账户系统


再来十套数据库顶 a 业务的订单系统


再来十套数据库顶 b 业务的订单系统


40 套数据库。另外还有其他 100 套 这样组成了 135 套数据库


一套数据库需要 2 个 cluster 一个 cluster 负责读业务。一个 slave 数据库负责同步功能


aws rds 费用



rds 预估费用页面 https://aws.amazon.com/cn/rds/mysql/pricing/?pg=pr&loc=2 多可用区存储费率 每月每 GB 0.45 USD 多可用区预调配 IOPS 费率 每月每 IOPS 0.36 USD


也就是一套数据库 20000 一个月 总共有四十套。


这些数据库容量都是很富裕的 得应付突发事件。平时 cpu 就 1%


一套数据库一个水桶。这 120 个水桶满满当当就存放了 10 桶水的业务。真是弃之可惜食之无味。


那么有没有一种数据库又便宜又好用呢。有 哪就是 tidb 数据库。


之前用 mysql 数据库最好用的是阿里的 tddl 数据库。当年我师父谢睿告诉我


之前一个 dba 工程师的工作内容可能包括以下几个方面:


  • 监控带宽、流量、并发、业务接口等关键资源及访问信息的变化趋势。

  • 根据相应趋势变化不断演进和优化 dba 架构。

  • 设计各类解决方案,解决公司业务发展中遇到的 dba 技术瓶颈。

  • 编写各种自动化脚本(shell,python),自动化部署优化服务。

  • 实现 dba 平台化运维。

  • 制定 dba 运维流程、规范、制度,并有序推进。

  • 研究先进 dba 运维理念、模式,确保业务持续稳定、有序。


但是现在 dba 还得帮公司省钱。如果贵公司的业务多。公司里面有个几百个数据库很正常。


这些数据库的月费用就是百万级别的。


那么我们能不能省下这些费用呢?没问题的 tidb 就是专门干这个的。


我们从两方面来省数据库的钱


双剑合璧


oltp,和 olap 数据库合二为一,同一套数据库即跑 oltp 也跑 olap 业务盛夏 redshift 的钱。


在用 aws 的物理机中


  • TiDB 资源控制和隔离:此部分主要介绍 TiDB 与 NUMA 和 cgroup 技术结合实现单机多实例部署时资源控制和隔离,以及 TiDB 自带的资源控制参数; TiDB 数据隔离:此部分主要介绍 TiDB Label 与 Placement Rules in SQL 技术实现数据存储隔离; 基于上述资源控制和数据隔离技术实现单集群多业务融合架构; 方案收益分析; 监控和报警隔离说明:融合部署的业务应用可以根据重要性分别配置监控和报警。

  • 把一台物理机当成 2 台使用通过绑定 numa。节约了机器又提高了性能。解决了机器不够的问题。



  • 多个业务 A 业务 B 业务用户中心公用一个数据库。做到了资源最大化利用。如果 A 用户量多就支援 A 业务。如果 B 用户量多就支援 B 业务。并由于大集群带来的业务容量的提升。无论各个业务量再怎么增长也能支撑的住。原本为了满足 A 的增长,B 业务的增长得准备两套物理机器。现在由于共用,可以相互资源就节省了服务器的使用。并且把 5 套套业务机器并成一套。提升了 5 倍性能。TiDB 多业务融合方案是指将多个业务系统部署在同一套 TiDB 集群中,利用 Placement Rule 来实现资源隔离和负载均衡。





他就是线下的雪花模型



在这样的系统架构下我们采用了这样的



每类业务分配 4 核心 8g 内存的 tidb,用于各类业务的 oltp 业务查询。在用资源管控来约束最大的 cpu 占比。把更多的资源,内存留给 tikv tiflash


tiflash 层采用 s3 作为冷存储 因为 s3 本身可无限扩容费用又是最低的


而且 tiflash 的 cpu 是可以动态扩容的 这个时候就可以很好的利用 aws 的 spot 实例 价格是 ec2 的 10 分之 1



准备条件

  1. 准备一个 S3 的 bucket,用于存储 TiFlash 数据。你也可以使用已有的 bucket,但需要为每个 TiDB 集群预留专门的 key 前缀。关于 S3 bucket 的更多信息,请参考 AWS 文档。也可以使用兼容 S3 的其他对象存储,比如 MinIO。TiFlash 使用的 S3 API 接口列表包括:


  • PutObject

  • GetObject

  • CopyObject

  • DeleteObject

  • ListObjectsV2

  • GetObjectTagging

  • PutBucketLifecycle


  • 给准备好的 S3 bucket 添加一个用于清理已删除数据的生命周期


  1. 确保 TiDB 集群中没有任何 TiFlash 节点。如果有,则需要将所有表的 TiFlash 副本数设置为 0,然后缩容掉所有 TiFlash 节点。比如:

使用方式

默认情况下,TiUP 会将 TiFlash 部署为存算一体架构。如需将 TiFlash 部署为存算分离架构,请参考以下步骤手动进行配置:


  1. 准备 TiFlash 的拓扑配置文件,比如 scale-out.topo.yaml,配置内容如下:


  • 注意以上 ACCESS_KEY_ID 和 SECRET_ACCESS_KEY 是直接写在配置文件中的。你也可以选择使用环境变量的方式单独配置。如果两种方式都配置了,环境变量的优先级高于配置文件。如需通过环境变量配置,请在所有部署了 TiFlash 进程的机器上,切换到启动 TiFlash 进程的用户环境(通常是 tidb),然后修改 ~/.bash_profile,增加这些配置:

  • storage.s3.endpoint 支持使用 http 模式和 https 模式连接 S3,可以直接通过修改 URL 来选择。比如 https://s3.{region}.http://amazonaws.com


  1. 执行扩容 TiFlash 节点,并重新设置 TiFlash 副本数:

  2. 以编辑模式打开 TiDB 配置文件:

  3. 在 TiDB 配置文件中添加以下配置项:

  4. 重启 TiDB:


  1. 修改 TiDB 配置,用存算分离的方式查询 TiFlash。


用最少的钱办最大的事,这就是 tidb 给我们节约费用最大的帮助。


这部分计划了很久我们有 300 多个数据库。我计算了一个数据库的费用可供大家参考一下。用 tidb 能省下来的费用。

aws rds 费用


rds预估费用页面 https://aws.amazon.com/cn/rds/mysql/pricing/?pg=pr&loc=2 多可用区存储费率 每月每 GB 0.45 USD 多可用区预调配 IOPS 费率 每月每 IOPS 0.36 USD

tidb 费用

价格的比较


本文是按照美元计价的月费用如果 rmb 计价就很恐怖了。



一个历史归档数据库一年的话费能从 96 万减少到 16 万 费用节省 80w。不可想像。这样的数据库有几百个。他能省多少钱各位 cfo 去算算。上云是真省钱呀。


尾记


TCO: TCO(Total Cost of Ownership, 总体拥有成本)其实并不陌生。1996 年,IBM 为 PC 和网络用户提出这个概念,同时,Intel 也提出了管理标准 WfM,两家公司还开发出一些进行 TCO 管理的解决方案。此外,Intel、IBM 与 HP 等公司携手制定了很多规范,例如:DMI(桌面管理接口)以及 WfM(联网化管理)等,这些标准得到了业界的支持并逐渐成为了厂商所共同遵循的标准。当时,业界对 TCO 的讨论程度之热烈至今还记忆犹新。


就算是 IDC 托管也是不可能保证做到随时分钟级别的服务器资源弹性伸缩。在业务不确定性日趋增大的市场背景下,拥有及时的弹性部署能力将成为大部分中小企业的刚需。这一点就能为企业节约大量资源,避免采购过量浪费,或者资源不足拖累业务的两难情况。


而恰恰是这些特性,大大降低企业的成本,例如,企业可以按需使用计算和存储资源,不必支付高昂的固定费用。同时,弹性伸缩可以让企业在高峰期轻松扩展计算和存储资源,避免浪费资源。


这些特性是云计算的核心优势,作者没有将它们纳入成本分析中,因此分析结果是不完整的。


最后还有一点,就是作者没有考虑到公有云提供的其他强大能力。


特别是对中小企业来说,原文的分析可能会造成误导,甚至可以说,任何不考虑人力成本的 IT 服务成本分析都是耍流氓。


其次,作者没有考虑到公有云的特性。相比于传统的 IDC,公有云提供了即插即用,弹性伸缩,按需按量计费等特性。


怎么用好云我们任重道远。


by the way 云是有返点的,交给公司公司用的更便宜。


发布于: 刚刚阅读数: 4
用户头像

TiDB 社区官网:https://tidb.net/ 2021-12-15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
云上成本贵,用tidb_7.x 实践_TiDB 社区干货传送门_InfoQ写作社区