如何应对并发(4) - 分布式数据库及反范式设计

分布式数据库及反范式设计

当数据容量非常大,请求频次非常高,索引优化,异步更新,合并操作,需求裁剪这些都做到位了,你发现系统依然存在严重的瓶颈,需要扩展,这时候,我们再来谈分布式方案。

这个课题我四年前在Qcon架构师大会分享过,当场我看记录,好评数还可以,但事后有高手吐槽说我讲的玩意根本不算什么分布式数据库,可能他们看中硬核的东西,不过我这种野路子,关心的是实战中,中小型互联网公司遇到的数据库压力问题如何高效解决,简单有效是第一宗旨,您要是问一线的,比如淘宝怎么解决数据库压力,别问我,我不会。

今天偷懒了,我把以前文档的内容贴出来。 不过这也是原创哦,四年前的原创。

分库&拆表方案

l 基本认识

n 用分库&拆表是解决数据库容量问题的唯一途径。

n 分库&拆表也是解决性能压力的最优选择。

n 分库 不同的数据表放到不同的数据库服务器中(也可能是虚拟服务器)

n 拆表 一张数据表拆成多张数据表,可能位于同一台服务器,也可能位于多台服务器(含虚拟服务器)。

l 去关联化原则

n 摘除数据表之间的关联,是分库的基础工作。

n 摘除关联的目的是,当数据表分布到不同服务器时,查询请求容易分发和处理。

n 学会理解反范式数据结构设计,所谓反范式,第一要点是不用外键,不允许Join操作,不允许任何需要跨越两个表的查询请求。第二要点是适度冗余减少查询请求,比如说,信息表,fromuid, touid, message字段外,还需要一个fromuname字段记录用户名,这样查询者通过touid查询后,能够立即得到发信人的用户名,而无需进行另一个数据表的查询。

n 去关联化处理会带来额外的考虑,比如说,某一个数据表内容的修改,对另一个数据表的影响。这一点需要在程序或其他途径去考虑。

l 分库方案

n 安全性拆分

u 将高安全性数据与低安全性数据分库,这样的好处第一是便于维护,第二是高安全性数据的数据库参数配置可以以安全优先,而低安全性数据的参数配置以性能优先。参见运维优化相关部分。

n 基于业务逻辑拆分

u 根据数据表的内容构成,业务逻辑拆分,便于日常维护和前端调用。

u 基于业务逻辑拆分,可以减少前端应用请求发送到不同数据库服务器的频次,从而减少链接开销。

u 基于业务逻辑拆分,可保留部分数据关联,前端web工程师可在限度范围内执行关联查询。

n 基于负载压力拆分

u 基于负载压力对数据结构拆分,便于直接将负载分担给不同的服务器。

u 基于负载压力拆分,可能拆分后的数据库包含不同业务类型的数据表,日常维护会有一定的烦恼。

n 混合拆分组合

u 基于安全与业务拆分为数据库实例,但是可以使用不同端口放在同一个服务器上。

u 基于负载可以拆分为更多数据库实例分布在不同数据库上

u 例如,

l 基于安全拆分出A数据库实例,

l 基于业务拆分出B,C数据库实例,

l C数据库存在较高负载,基于负载拆分为C1,C2,C3,C4 实例。

l 数据库服务器完全可以做到 A+B+C1 为一台,C2,C3,C4各单独一台。

l 分表方案

n 数据量过大或者访问压力过大的数据表需要切分

n 纵向分表(常见为忙闲分表)

u 单数据表字段过多,可将频繁更新的整数数据与非频繁更新的字符串数据切分

u 范例 user表 ,个人简介,地址,QQ号,联系方式,头像 这些字段为字符串类型,更新请求少; 最后登录时间,在线时常,访问次数,信件数这些字段为整数型字段,更新频繁,可以将后面这些更新频繁的字段独立拆出一张数据表,表内容变少,索引结构变少,读写请求变快。

n 横向切表

u 等分切表,如哈希切表或其他基于对某数字取余的切表。等分切表的优点是负载很方便的分布到不同服务器;缺点是当容量继续增加时无法方便的扩容,需要重新进行数据的切分或转表。而且一些关键主键不易处理。

u 递增切表,比如每1kw用户开一个新表,优点是可以适应数据的自增趋势;缺点是往往新数据负载高,压力分配不平均。

u 日期切表,适用于日志记录式数据,优缺点等同于递增切表。

u 个人倾向于递增切表,具体根据应用场景决定。

n 热点数据分表

u 将数据量较大的数据表中将读写频繁的数据抽取出来,形成热点数据表。通常一个庞大数据表经常被读写的内容往往具有一定的集中性,如果这些集中数据单独处理,就会极大减少整体系统的负载。

u 热点数据表与旧有数据关系

l 可以是一张冗余表,即该表数据丢失不会妨碍使用,因源数据仍存在于旧有结构中。优点是安全性高,维护方便,缺点是写压力不能分担,仍需要同步写回原系统。

l 可以是非冗余表,即热点数据的内容原有结构不再保存,优点是读写效率全部优化;缺点是当热点数据发生变化时,维护量较大。

l 具体方案选择需要根据读写比例决定,在读频率远高于写频率情况下,优先考虑冗余表方案。

u 热点数据表可以用单独的优化的硬件存储,比如昂贵的闪存卡或大内存系统。

u 热点数据表的重要指标

l 热点数据的定义需要根据业务模式自行制定策略,常见策略为,按照最新的操作时间;按照内容丰富度等等。

l 数据规模,比如从1000万条数据,抽取出100万条热点数据。

l 热点命中率,比如查询10次,多少次命中在热点数据内。

l 理论上,数据规模越小,热点命中率越高,说明效果越好。需要根据业务自行评估。

u 热点数据表的动态维护

l 加载热点数据方案选择

n 定时从旧有数据结构中按照新的策略获取

n 在从旧有数据结构读取时动态加载到热点数据

l 剔除热点数据方案选择

n 基于特定策略,定时将热点数据中访问频次较少的数据剔除

n 如热点数据是冗余表,则直接删除即可,如不是冗余表,需要回写给旧有数据结构。

u 通常,热点数据往往是基于缓存或者key-value 方案冗余存储,所以这里提到的热点数据表,其实更多是理解思路,用到的场合可能并不多.

反范式设计(冗余结构设计)

l 反范式设计的概念

n 无外键,无连表查询。

n 便于分布式设计,允许适度冗余,为了容量扩展允许适度开销。

n 基于业务自由优化,基于i/o 或查询设计,无须遵循范式结构设计。

l 冗余结构设计所面临的典型场景

n 原有展现程序涉及多个表的查询,希望精简查询程序

n 数据表拆分往往基于主键,而原有数据表往往存在非基于主键的关键查询,无法在分表结构中完成。

n 存在较多数据统计需求(count, sum等),效率低下。

l 冗余设计方案

n 基于展现的冗余设计

u 为了简化展现程序,在一些数据表中往往存在冗余字段

u 举例,信息表 message,存在字段 fromuid,touid,msg,sendtime 四个字段,其中 touid+sendtime是复合索引。存在查询为 select * from message where touid=$uid order by sendtime desc limit 0,30;

u 展示程序需要显示发送者姓名,此时通常会在message表中增加字段fromusername,甚至有的会增加fromusersex,从而无需连表查询直接输出信息的发送者姓名和性别。这就是一种简单的,为了避免连表查询而使用的冗余字段设计。

n 基于查询的冗余设计

u 涉及分表操作后,一些常见的索引查询可能需要跨表,带来不必要的麻烦。确认查询请求远大于写入请求时,应设置便于查询项的冗余表。

u 冗余表要点

l 数据一致性,简单说,同增,同删,同更新。

l 可以做全冗余,或者只做主键关联的冗余,比如通过用户名查询uid,再基于uid查询源表。

u 实战范例1

l 用户分表,将用户库分成若干数据表

l 基于用户名的查询和基于uid的查询都是高并发请求。

l 用户分表基于uid分成数据表,同时基于用户名做对应冗余表。

l 如果允许多方式登陆,可以有如下设计方法

n uid,passwd,用户信息等等,主数据表,基于uid 分表

n ukey,ukeytype,uid 基于ukey分表,便于用户登陆的查询。分解成如下两个SQL

u select uid from ulist_key_13 where ukey=’$username’ and ukeytype=‘login’;

u select * from ulist_uid_23 where uid=$uid and passwd=’$passwd’;

n ukeytype定义用户的登陆依据,比如用户名,手机号,邮件地址,网站昵称等。 Ukey+ukeytype 必须唯一。

n 此种方式需要登陆密码统一,对于第三方connect接入模式,可以通过引申额外字段完成。

u 实战范例2:用户游戏积分排名

l 表结构 uid,gameid,score 参见前文实时积分排行。表内容巨大,需要拆表。

l 需求1:基于游戏id查询积分排行

l 需求2:基于用户id查询游戏积分记录

l 解决方案:建立完全相同的两套表结构,其一以uid为拆表主键,其二以gameid为拆表主键,用户提交积分时,向两个数据结构同时提交。

u 实战范例3:全冗余查询结构

l 主信息表仅包括 主键及备注memo 字段(text类型),只支持主键查询,可以基于主键拆表。所以需要展现和存储的内容均在memo字段重体现。

l 对每一个查询条件,建立查询冗余表,以查询条件字段为主键,以主信息表主键id 为内容。

l 日常查询只基于查询冗余表,然后通过in的方式从主信息表获得内容。

l 优点是结构扩展非常方便,只需要扩展新的查询信息表即可,核心思路是,只有查询才需要独立的索引结构,展现无需独立字段。

l 缺点是只适合于相对固定的查询架构,对于更加灵活的组合查询束手无策。

n 基于统计的冗余结构

u 为了减少会涉及大规模影响结果集的表数据操作,比如countsum操作。应将一些统计类数据通过冗余数据结构保存。

u 冗余数据结构可能以字段方式存在,也可能以独立数据表结构存在,但是都应能通过源数据表恢复。

u 实战范例:

l 论坛板块的发帖量,回帖量,每日新增数据等。

l 网站每日新增用户数等。

l 参见Discuz论坛系统数据结构,有较多相关结构。

l 参见前文分段积分结构,是典型用于统计的冗余结构。

l 后台可以通过源数据表更新该数字。

l RedisZset类型可以理解为存在一种冗余统计结构。

n 历史数据表

u 历史数据表对应于热点数据表,将需求较少又不能丢弃的数据存入,仅在少数情况下被访问。

以上为节选,缺失部分请点击 “查看原文”


分几次分享的意思其实很简单,这个文档很早就发布过,给很多人也分享过,但我总觉得效果不够好,不够好的原因是,很多人马马虎虎的看一遍下去,并不真的理解吸收,我还是希望有兴趣的读者多花一点时间思考这些技术问题,能透彻的理解其思路和逻辑,并真正用到工作中,提升代码和数据库操作的效率。

我们平时看技术文档,看技术专家分享的时候,多半存在这个问题,贪多嚼不烂,看着觉得对方方案很牛,但很多都只是听到了一点概念,最后真正吸收和落实的不多,我希望一些做技术的朋友能稍微慢下来,多吸收和领悟一下,然后在实践中用起来,这样,这个分享才是有意义的。

明天我会写一篇对一些技术人员吐槽的文章,谢谢。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
这个PDF文件是我花钱买来的,现在为了挣积分,拿出来与大家分享!! 本书深入浅出地介绍了目前世界上最受欢迎的数据库管理系统之一——SQL Server。全书共分三个部分:第一部分阐释了数据库的基本概念,讲解了数据库建模语言;第二部分展示了从概念建模到在SQL Server 2008上真正实现数据库的过程;第三部分深入探讨了SQL Server若干方面的技术细节,如数据保护、索引、并发访问等。通过将理论融入数据库实践,清晰地讲解了关系型数据库设计原则,完整地展示了如何进行良好的关系型数据库设计,深入揭示了SQL Server 2008的技术细节。   本书浓缩了作者作为SQL Server数据库架构师多年来丰富的实践经验,适合各类数据库开发和管理人员学习参考 目录 第1章 数据库概念简介  1.1 数据库设计阶段   1.1.1 概念阶段   1.1.2 逻辑阶段   1.1.3 实现阶段   1.1.4 物理阶段  1.2 关系数据结构   1.2.1 数据库和模式   1.2.2 表、行和列   1.2.3 信息原则   1.2.4 域   1.2.5 元数据   1.2.6 键   1.2.7 未显式赋值的项(NULL)  1.3 实体之间的关系   1.3.1 二元关系   1.3.2 非二元关系  1.4 数据访问语言(SQL)  1.5 理解依赖性   1.5.1 函数依赖性   1.5.2 判定  1.6 总结 第2章 数据建模语言  2.1 数据建模介绍  2.2 实体  2.3 属性   2.3.1 主键   2.3.2 替代键   2.3.3 外键   2.3.4 域   2.3.5 命名  2.4 关系   2.4.1 识别性关系   2.4.2 非识别性关系   2.4.3 角色名字   2.4.4 关系基数   2.4.5 动词短语(关系名字)  2.5 描述信息  2.6 其他建模方法   2.6.1 信息工程   2.6.2 Chen ERD   2.6.3 Visio   2.6.4 Management Studio数据库关系图  2.7 最佳实践  2.8 总结 第3章 概念阶段数据建模  3.1 理解需求  3.2 文档化过程  3.3 需求收集   3.3.1 客户访谈   3.3.2 要回答的问题   3.3.3 现存的系统和原型   3.3.4 其他类型的文档  3.4 识别对象和过程   3.4.1 识别实体   3.4.2 实体间关系   3.4.3 识别属性和域  3.5 识别业务规则和业务过程   3.5.1 识别业务规则   3.5.2 识别基础业务过程  3.6 完成概念模型   3.6.1 识别明显的、额外的数据需求   3.6.2 和客户一起评审   3.6.3 重复以上步骤直到客户同意你的模型  3.7 最佳实践  3.8 总结 第4章 规范化过程  4.1 为什么要规范化   4.1.1 消灭重复数据   4.1.2 避免编写不必要的代码   4.1.3 给表瘦身   4.1.4 最大化聚集索引的使用   4.1.5 降低每张表中索引的数量  4.2 规范化应该走多远  4.3 规范化过程  4.4 实体和属性的形式:第一范式   4.4.1 所有属性必须是原子的   4.4.2 实体的所有实例必须包含相同数量的值   4.4.3 实体中出现的所有实体类型都必须不同   4.4.4 第一范式所避免的不规则编程   4.4.5 当前设计不符合第一范式的线索  4.5 属性间的关系   4.5.1 第二范式   4.5.2 第三范式   4.5.3 Boyce-Codd范式  4.6 实体中的多值依赖   4.6.1 第四范式   4.6.2 第五范式  4.7 非规范化  4.8 最佳实践  4.9 总结  4.10 额外的例子  4.11 本书迄今为止所讲述的故事 第5章 实现基础的表结构  5.1 评审逻辑设计  5.2 变换设计   5.2.1 选择名字   5.2.2 处理子类型   5.2.3 决定树的实现方式   5.2.4 选择键的实现方式   5.2.5 决定域的实现方式   5.2.6 设置模式   5.2.7 评审“最终的”实现模型  5.3 实现设计   5.3.1 创建基本表结构   5.3.2 添加唯一性约束   5.3.3 构建默认约束   5.3.4 添加关系(外键)   5.3.5 处理排序规则和排序   5.3.6 计算列   5.3.7 实现用户定义的数据类型   5.3.8 文档化你的数据库   5.3.9 处理依赖信息  5.4 最佳实践  5.5 总结 第6章 保护数据的完整性  6.1 最佳实

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值