Python Flask快速入门与进阶

## download:Python Flask快速入门与进阶

数据库什么时候分表?

子数据库和子表要解决的是现有海量数据访问的性能瓶颈,以及不断增加的数据量的架构前瞻。
数据库划分和表划分的关键指标是否是数据量。我们以fire100.top网站的资源表t_resource为例。系统运行初期,每天只上传几十个资源。此时使用单数据库单表的方式足以支撑系统的存储,数据量小几乎没有任何数据库性能瓶颈。
但是有一天,一个神秘的流量进来了,系统产生的资源数据量突然增加到10万甚至上百万。此时资源表数据量达到数千万,查询响应变得缓慢,数据库的性能瓶颈逐渐显现。
以MySQL数据库为例,单个表的数据量达到亿级。当通过添加索引和SQL调优等传统优化策略获得的性能提升仍然很小时,可以考虑划分数据库和表。
既然MySQL在存储海量数据时会出现性能瓶颈,是否可以考虑用其他方案替代?比如高性能非关系数据库MongoDB?
可以,但这取决于存储的数据类型!
目前互联网上大多数公司的核心数据几乎都存储在关系数据库(MySQL、Oracle等。),因为它们拥有堪比NoSQL的稳定性和可靠性,产品的成熟生态系统,以及其他存储工具不具备的核心交易特性。不过还是可以考虑用MongoDB来评论和赞美这些非核心数据。
如何划分数据库和表

子数据库和子表的核心是将数据分片并相对均匀地路由到不同的数据库和表中,分片后快速定位数据并整合搜索结果。

图书馆和桌子可以从垂直(纵向)和水平(横向)两个纬度来划分。我们以经典的订单业务为例,看看如何拆分。

垂直分裂
1.垂直存储
一般来说,垂直数据库是按照业务和功能的维度划分的,不同的业务数据放在不同的数据库中,核心概念库是专用的。
根据业务类型,将数据拆分到多个数据库中,订单、支付、会员、积分等表放在相应的订单数据库、支付数据库、会员数据库、积分数据库中。不同服务禁止跨数据库直连,获取的对方业务数据全部通过API接口交互,这也是微服务拆分的重要依据。

垂直的数据库划分很大程度上取决于业务的划分,但是有时候业务之间的划分并不是那么清晰,比如电商中订单数据的拆分,其他很多业务都是依赖订单数据的,有时候界限划分的并不好。
垂直子数据库将一个数据库的压力分散到多个数据库,提高了部分数据库的性能。但是没有解决单个表数据量大带来的性能问题,需要后面的子表来解决。
2.垂直子表
对业务中字段较多的大表进行竖表拆分。一般将宽业务表中的独立字段或不常用字段拆分成单独的数据表,这是一种将大表拆分成小表的模式。
例如,一个t_order表有几十个字段,其中订单金额的相关字段是经常计算的。为了不影响订单表t_order的性能,可以将order amount的相关字段分开,维护一个单独的t_order_price_expansion表,使每个表只存储原表的一部分字段,这些字段由订单号order_no关联,然后将拆分后的表路由到不同的库。

数据库是以行为为单位将数据加载到内存中的,所以拆分后的核心表大部分是访问频率高的字段,字段的长度也较短,这样可以将更多的数据加载到内存中,减少磁盘IO,提高索引查询的命中率,进一步提高数据库性能。
水平分裂
数据库和表垂直分离后,仍然会存在单个数据库和表中数据过多的问题。当我们的应用无法进行细粒度的垂直划分时,单个数据库读写和存储的性能仍然存在瓶颈。这时候就需要配合数据库和表的横向分离。
1、图书馆的水平
横向数据库拆分是将同一个表按照一定的规则拆分成不同的数据库,每个数据库可以位于不同的服务器上,从而实现横向扩展,是提高数据库性能的常用方法。

例如,db_orde_1和db_order_2的数据库中有相同的t_order表。当我们访问一个订单时,我们可以通过对订单的订单号取模来指定该订单应该在哪个数据库中操作:订单号mod 2(数据库实例的数量)。
这种方案往往可以解决单库存和性能瓶颈的问题,但是由于同一个表分布在不同的数据库中,数据访问需要额外的路由工作,因此系统的复杂度也有所提高。
2.水平表
在同一个数据库中,一个数据量很大的表按照一定的规则被分成若干个结构相同的表,每个表只存储原表的一部分数据。
例如,一个t_order订单表有900万个数据,t_order_1、t_order_2和t_order_3三个表被水平拆分。每个表有300万个数据,以此类推。

水平表虽然拆分了表,但是子表都在同一个数据库实例中,只是解决了单个表数据过多的问题,并没有把拆分的表分散到不同的机器上,仍然在争夺CPU、内存、网络IO等。同一个物理机器。为了进一步提高性能,需要将拆分后的表分散到不同的数据库中,以达到分布式的效果。

存在哪个数据库的表。
在未来,会有一个问题。一个表将出现在多个数据库中。到底应该存放在哪个数据库的哪个表呢?
我们在上面已经多次提到某些规则。实际上,这个规则是一个路由算法,它决定了一个数据应该存储在哪个数据库的哪个表中。
常见的有取模算法、范围限制算法、范围+取模算法和预定义算法。
1.模块化算法
关键字段模块化(从散列结果中取余数hash(XXX) mod N),其中N是数据库实例或子表的数量)是最常见的路由方法。
以t_order表为例,先将数据库从0到N-1编号,然后对t_order表中的order number字段取模hash (order_no) mod n得到余数I,I=0存储第一个库,i=1存储第二个库,i=2存储第三个库,以此类推。

相同顺序的数据将落在相同的数据库和表中。查询时使用同样的规则,以t_order订单号作为查询条件,可以快速定位数据。
优势
实现简单,数据分布相对均匀,请求不容易命中一个数据库。
劣势
模块化算法对集群的扩展支持不是很友好。集群中有n个数据库real hash (user _ id) mod n。当某台机器停机时,本应到达数据库的请求不能被处理,然后被丢弃的实例将被踢出集群。
此时,机器号减少算法改变hash(user_id) mod N-1,相同的用户数据落在不同的数据库中。本机恢复后,以user_id为条件的用户数据查询会少一些。
2.范围限制算法
范围限制算法由一些范围字段分割,如时间或ID区域。
用户表t_user分为三个表:t_user_1、t_user_2和t_user_3。然后将user_id范围从1到1000 W的用户数据放入t_user_1,1000到2000 W放入t_user_2,2000到3000 W放入t,日期范围也是如此。
优势
单表数据量可控。
横向扩展很简单,增加节点即可,不需要迁移其他碎片化数据。
劣势
因为连续切片可能存在数据热点,比如按时间域切片时,如果某段时间(如双11)订单急剧增加,存储11月数据的表可能会频繁读写,而存储在其他切片表中的历史数据很少被查询,导致数据倾斜,数据库压力分布不均匀。

3.范围+模数算法
为了避免热数据的问题,我们可以优化上限算法。
这次我们先通过range算法定义每个数据库的用户表t_user只存储1000w的数据,第一个db_order_1库存的userId从1到1000 W,第二个数据库是10002000w,第三个数据库是20003000w,以此类推。

在每个数据库中,用户表t_user被拆分成t_user_1、t_user_2、t_user_3等。,userd模路由到相应的表。
有效避免了数据分布不均匀的问题,数据库的横向扩展也很简单。直接添加实例不需要迁移历史数据。
4.地理位置碎片化
地理位置碎片化其实是一个更大的范围,是以城市或者区域来划分的。比如华东和华北的数据放在不同的碎片化数据库和表中。
5.预定义算法
预定义算法是预先明确知道子数据库和子表的数量,它可以直接将某一类数据路由到指定的数据库或表,甚至在查询的时候。
子数据库和子表的问题
不难发现,与拆分前的单数据库、单表相比,现在系统的数据存储架构已经变得非常复杂。看几个有代表性的问题,比如:
分页、排序和跨节点联合查询
分页、排序、联查,这些开发中频繁使用的看似普通的操作,在数据库和表划分后却是令人头疼的事情。查询分散在不同库中的表的数据,然后将所有结果汇总合并提供给用户。
例如,我们需要查询11月和12月的订单数据。如果两个月的数据分散在不同的数据库实例中,我们需要查询两个数据库相关的数据。合并、排序和分页数据的过程很复杂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值