高并发、高负载解决方案之----------数据库分库分表的应用场景及解决方案

数据库分库分表的应用场景及解决方案

   现实业务场景中,为了保障客户体验并满足业务的线性增长。会对数据量巨大,且业务会始终进行的产品进行分表分库策略。但是如何合理的根据业务采取争取的分表分库策略至关重要。下面以具体实例来进行分析。

  • 场景一:用户中心,单key业务如何进行数据库切分

  • 场景二:订单中心,多key业务如何进行数据库切分

  

场景一:用户中心数据库切分架构实践|场景介绍

  用户中心是一个十分常见的业务系统,涵盖用户登录、注册、信息查询与修改等服务。

  用户的核心元数据为:

  User(uid,login_name,nickname,password,sex,age)

  其中   ●   uid :用户ID,主键

       ●    login_name,nickname,password,sex,age :用户的其他属性

  在业务初期,单表单库就能满足业务需求

  

场景一:用户中心数据库切分方法|范围法

  当数据量越来越大时,需要对数据库进行水平切分,常见的切分算法有“范围法”和“哈希法”。

  范围法:以用户中心的业务uid为划分依据,将数据水平切分到两个数据库实例上去:

  

  范围法的优点是:

  • 切分策略简单,根据uid,按照范围,user- center很快能够定位到数据在哪个库上

  • 扩容简单,如果容量不够,只要增加user-db3即可

  范围法的不足是:

  • uid必须要满足递增的特性

  • 数据量不均,新增的user-db3,在初期的数据会比较少

  • 请求量不均,一般来说,新注册的用户活跃度会比较高,故user-db2往往会比user-db1负载要高,导致服务器利用率不平衡

  

场景一:用户中心数据库切分方法|哈希法

  哈希法:以用户中心的业务uid为划分依据,将数据水平切分到两个数据库实例上去

  

  哈希法的优点是:

  •切分策略简单,根据uid,按照范围,user- center很快能够定位到数据在哪个库上

  •数据量均衡:只要uid是均衡的,数据在各个库上的分布一定是均衡的

  •请求量均衡:只要uid是均衡的,负载在各个库上的分布一定是均衡的

  哈希法的不足是:

  •扩容麻烦,如果需要增加一个库,需要重新hash,这有可能会导致数据迁移,给平滑升级带来困难。

  

场景一:用户中心数据查询需求分析

  任何脱离业务的架构设计都是耍流氓,在进行架构讨论之前,首先要对业务进行简要分析,看看表结构上有哪些查询需求。

  根据业务经验,用户中心往往有以下几类业务需求:

  (1)用户侧,前台访问,最典型的有两类需求

   用户登录:通过login_name/email/phone查询用户实体,1%的请求属于这种类型

   用户信息查询:登录之后,通过uid来查询用户的实例,99%请求属于这种类型。

   用户侧查询的基本特点是:基本是单条记录查询,访问量大,服务要求高可用,并且对一致性要求较高

  (2)运营侧,后台访问。需要满足产品及运营层面的各类需求,访问模式各异,按照年龄、性别、登录时间、注册时间等属性来 进行查询。运营侧需求的的基本特点是:大量的批量分页查询需求,访问量较低,对可用性要求不高,对一致性的要求也没有这么严格。

  

场景一:用户中心数据查询需求解决方案-用户侧  

  1.索引表法:

   思路:uid可以直接定位到数据库,login_name不可以直接定位到库。建立login_name到login_id的映射关系。

  解决方案:

  • 建立一个索引表记录login_name->uid的映射关系

• 用login_name来访问时,先通过索引表查询到uid,再定位相应的库

• 索引表属性较少,可以容纳非常多数据,一般不需要分库

• 如果数据量过大,可以通过login_name来分库

  不足:多一次数据库查询,性能下降一倍。

  2.缓存映射法:

  思路:访问索引表的性能比较低。将映射放在缓存中可以获得更好的性能体验。

  解决方案:

• login_name查询先到cache中查询uid,再根据uid定位数据库

• 假设cachemiss,采用扫全库法获取login_name对应的uid,放入cache

• login_name到uid的映射关系不会变化,映射关系一旦放入缓存,不会更改,无需淘汰,缓存命中率超高

• 如果数据量过大,可以通过login_name进行cache水平切分

 不足:多一次cache查询。

  3.login_name生成uid

  思路:不进行远程查询,由login_name直接得到uid

  解决方案:

• 在用户注册时,设计函数login_name生成uid,uid=f(login_name),按uid分库插入数据

• 用login_name进行登录时,先通过函数计算出uid,再由uid路由到对应数据库进行查询。

不足:对login_name到uid的生成函数要求较高,有uid生成冲突的风险

  4.login_name基因融入uid

  思路:从login_name抽取“基因” 融入uid中。

  

  

  解决方案:

• 在用户注册时,设计函数login_name生成4bit基因,login_name_gene=f(login_name),如上图粉色部分

• 同时,生成60bit的全局唯一id,作为用户的标识,如上图绿色部分

• 接着把4bit的login_name_gene也作为uid的一部分,如上图屎黄色部分

• 生成64bit的uid,由id和login_name_gene拼装而成,并按照uid分库插入数据

• 用login_name来访问时,先通过函数由login_name再次复原4bit基因,login_name_gene=f(login_name),通过                  login_name_gene%8直接定位到库

  

场景一:用户中心数据查询需求解决方案-运营侧

  后台运营侧的查询需求各异,基本是批量的分页查询,计算量和返回数据量较大,比较消耗数据库性能。此时如果后台业务和前台业务共用一批服务和同一个数据库。有可能会导致后台少数几个请求的批量查询的低效访问造成数据库服务器cpu瞬时100%,影响前台用户的正常访问。另外,由于后台业务的查询需求多种多样,需要在数据库上建立多种索引,这些索引会占用大量的内存和磁盘,从而造成前台业务的uid/login_name的查询和写入性能大幅度降低,处理时间增长。对这一类业务,应该采用“前后台分离”的架构方案:

  

场景二:订单中心数据查询需求分析

  还是那句话,任何脱离业务的架构设计都是耍流氓,在进行架构讨论之前,首先要对业务进行简要分析,看看表结构上有哪些查询需求。

  根据业务经验,订单中心往往有以下几类业务需求:

  (1)用户侧,前台访问,最典型的有三类需求

  订单实体查询:通过oid查询订单实体,90%都是这种需求。

  用户订单列表查询:通过buyer_id分页查询用户历史订单列表,9%流量属于这种需求。

  商家订单列表查询:通过seller_uid分页查询商家历史订单列表,1%流量属于这类需求。

  前台访问的特点是:吞吐量大,服务要求高可用,对一致性要求较高。其中商家对一致性要求较低,可以接受一定程度的延迟。

  (2)运营侧,后台访问。根据产品、运营需求,访问模式各异:按照时间,架构,商品和详情来进行查询

后台访问的特点:运营侧的查询基本上是批量的分页查询,访问量低,对可用性一致性的要求不高,允许秒甚至十秒级别的查询延迟。

  

场景二:订单中心数据查询需求解决方案

  后台运营侧的查询需求各异,基本是批量的分页查询,计算量和返回数据量较大,比较消耗数据库性能。此时如果后台业务和前台业务共用一批服务和同一个数据库。有可能会导致后台少数几个请求的批量查询的低效访问造成数据库服务器cpu瞬时100%,影响前台用户的正常访问。对这一类业务,应该采用“前后台分离”的架构方案:前台业务架构不变,站点访问,服务分层,数据库水平切分。

  

  

场景二:订单中心数据库切分方法

  明确了订单中心的访问需求后,问题转化为,前台的oid,buyer_id,seller_id如何来进行数据库的水平切分呢?

  需要同时满足以下条件:

  1.根据buyer_uid%n,可以定位到数据库

   2.根据oid%n,可以定位到数据库

  3.根据seller_uid%n,可以定位到数据库

  以上业务是一个1:N(1个买家:N个订单)和N:N(1个买家:N个卖家, 1个卖家:N个买家)的业务场景,对于“多对多”的业务,水平切分应该使用“数据冗余法”

  

场景二:订单中心数据库切分方法

  

  • 当有订单生成时,通过buyer_uid分库,oid中融入分库基因,写入DB-buyer库

  • 通过线下异步的方式,通过binlog+canal,将数据冗余到DB-seller库中

• buyer库通过buyer_uid分库,seller库通过seller_uid分库,前者满足oid和buyer_uid的查询需求,后者满足seller_uid的查询需求

  

场景二:订单中心数据库切分方法|数据冗余法

  为什么要冗余数据?

  互联网数据量很大的业务场景,往往数据库需要进行水平切分来降低单库数据量。

  水平切分会有一个patitionkey,通过patition key的查询能够直接定位到库,但是非patitionkey上的查询可能就需要扫描多个库了。

  此时常见的架构设计方案,是使用数据冗余这种反范式设计来满足分库后不同维度的查询需求。

  例如:订单业务,对用户和商家都有订单查询需求:

  

  Order(oid,info_detail);

  T(buyer_uid,seller_uid,oid);

  如果用buyer_uid来分库,seller_uid的查询就需要扫描多库。

  如果用seller_uid来分库,buyer_uid的查询就需要扫描多库。

  此时可以使用数据冗余来分别满足buyer_uid和seller_uid上的查询需求

  T1(buyer_uid,seller_uid,oid)

  T2(seller_uid,buyer_uid,oid)

  同一个数据,冗余两份,一份以buyer_uid来分库,满足买家的查询需求;一份以seller_uid来分库,满足卖家的查询需求。

  

场景二:订单中心数据库切分方法|如何实现数据冗余

  

  

  1.服务同步双写

  服务同步双写,即由服务层同步写冗余数据。

  流程如右图:

  (1)业务应用代用服务层,写入数据

  (2)服务层将数据写入DB1

  (3)服务层将数据写入DB2

  (4)服务层返回新增数据成功给业务应用

  

  优点:

  •简单,服务层由单写,改为两次写人

  •数据一致性较高,双写成功后才返回

  缺点:

  • 因为由单写变为了两次写入,请求时间增长

  • 数据仍有可能不一致(数据写入DB1后,服务宕机或重启,则数据无法写人DB2)

  3.线下异步双写

  

  为了屏蔽“复杂性”,数据双写由线下服务或者任务来完成,不再由服务层完成

  

  流程如右图:

  (1)业务应用代用服务层,写入数据

  (2)服务层将数据写入DB1

  (3)服务层返回新增数据成功给业务应用

  (4)数据会被写入到数据库的log中

  (5)线下服务或者任务读取数据库log

  (6)线下服务或者任务插入T2数据

   

  优点:

  •数据双写与业务完全解耦

  •请求处理时间短

  缺点:

  •返回业务新增成功时,会存在一个数据不一致的时间窗口,但能保证最终一致性

  •数据一致性依赖于线下服务或者任务的可凹陷

原文地址:https://www.cnblogs.com/hanxue112253/p/9531811.html

时间: 2024-08-29 06:35:40

高并发、高负载解决方案之----------数据库分库分表的应用场景及解决方案的相关文章

数据库分库分表存在的问题及解决方案

读写分离分散了数据库读写操作的压力,但是没有分散存储压力,当数据库的数据量达到千万甚至上亿条的时候,单台数据库服务器的存储能力就会达到瓶颈,主要体现在以下几个方面: 数据量太大,读写性能会下降,即使有索引,索引也会变得很大,性能同样会下降 数据文件会变得很大,数据库备份和恢复需要消耗更长的时间 数据文件越大,极端情况下丢失数据的风险就会越高 基于上述原因,单个数据库服务器存储的数据量不能太大,需要控制在一定的范围内,为了满足业务数据存储的需求,需要将存储分散到多台数据库服务器上 常见的分散存储的

关系型数据库分库分表解决方案

关系型数据库分库分表解决方案 关系型数据库单库或单表在数据达到一定量级后,单个节点的就会出现性能瓶颈.通常的做法就是考虑分库分表. 为什么要分? 分库降低了单点机器的负载:分表,提高了数据操作的效率,尤其是Write操作的效率. 如何分? 按号段分: (1) user_id为区分,1-1000的对应DB1,1001-2000的对应DB2,以此类推:优点:可部分迁移缺点:数据分布不均 (2)hash取模分: 对user_id进行hash(或者如果user_id是数值型的话直接使用user_id 的

数据库分库分表(sharding)系列

数据库分库分表(sharding)系列     目录; (一) 拆分实施策略和示例演示 (二) 全局主键生成策略 (三) 关于使用框架还是自主开发以及sharding实现层面的考量 (四) 多数据源的事务处理 (五) 一种支持自由规划无须数据迁移和修改路由代码的Sharding扩容方案 (一) 拆分实施策略和示例演示 第一部分:实施策略 图1.数据库分库分表(sharding)实施策略图解 1.准备阶段 对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系统业务逻辑和数据库sch

数据库分库分表

1. 数据库分库分表 1.1. 前言 1.1.1. 名词解释 1.2. 数据库架构演变 1.3. 分库分表前的问题 1.3.1. 用户请求量太大 1.3.2. 单库太大 1.3.3. 单表太大 1.4. 分库分表的方式方法 1.4.1. 垂直拆分 1.4.2. 水平拆分 1.5. 分库分表后面临的问题 1.5.1. 事务支持 1.5.2. 多库结果集合并(group by,order by) 1.5.3. 跨库join 1.6. 分库分表方案产品 1.7. 为什么不建议分库分表 1.8. 参考

转数据库分库分表(sharding)系列(二) 全局主键生成策略

本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案.关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示 本文原文连接: http://blog.csdn.net/bluishglc/article/details/7710738 ,转载请注明出处! 第一部分:一些常见的主键生成策略 一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键

数据库分库分表(sharding)系列(二) 全局主键生成策略

本文将主要介绍一些常见的全局主键生成策略,然后重点介绍flickr使用的一种非常优秀的全局主键生成方案.关于分库分表(sharding)的拆分策略和实施细则,请参考该系列的前一篇文章:数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示 本文原文连接: http://blog.csdn.net/bluishglc/article/details/7710738 ,转载请注明出处! 第一部分:一些常见的主键生成策略 一旦数据库被切分到多个物理结点上,我们将不能再依赖数据库自身的主键

数据库分库分表(sharding)系列(一) 拆分实施策略和示例演示

本文原文连接: http://blog.csdn.net/bluishglc/article/details/7696085 ,转载请注明出处!本文着重介绍sharding切分策略,如果你对数据库sharding缺少基本的了解,请参考我另一篇从基础理论全面介绍sharding的文章:数据库Sharding的基本思想和切分策略 第一部分:实施策略 图1.数据库分库分表(sharding)实施策略图解(点击查看大图) 1.准备阶段 对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系

数据库分库分表(sharding)

第一部分:实施策略 图1.数据库分库分表(sharding)实施策略图解(点击查看大图) 1.准备阶段 对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系统业务逻辑和数据库schema.一个好的建议是绘制一张数据库ER图或领域模型图,以这类图为基础划分shard,直观易行,可以确保开发人员始终保持清醒思路.对于是选择数据库ER图还是领域模型图要根据项目自身情况进行选择.如果项目使用数据驱动的开发方式,团队以数据库ER图作为业务交流的基础,则自然会选择数据库ER图,如果项目使用的

数据库分库分表(sharding)系列(一)数据库Sharding的基本思想和切分策略

本文原文连接: http://blog.csdn.net/bluishglc/article/details/7696085 ,转载请注明出处!本文着重介绍sharding切分策略,如果你对数据库sharding缺少基本的了解,请参考我另一篇从基础理论全面介绍sharding的文章:数据库Sharding的基本思想和切分策略 第一部分:实施策略 图1.数据库分库分表(sharding)实施策略图解(点击查看大图) 1.准备阶段 对数据库进行分库分表(Sharding化)前,需要开发人员充分了解系