数据库架构设计思路

author author     2022-08-26     118

关键词:

 

一 、58同城数据库架构设计思路

(1)可用性设计

解决思路:复制+冗余

副作用:复制+冗余一定会引发一致性问题

保证“读”高可用的方法:复制从库,冗余数据,如下图

 0 
带来的问题:主从不一致

解决方案:见下文

保证“写”高可用的一般方法:双主模式,即复制主库(很多公司用单master,此时无法保证写的可用性),冗余数据,如下图

 1 
带来的问题:双主同步key冲突,引不一致

解决方案:

a)方案一:由数据库或者业务层保证key在两个主上不冲突

b)方案二:见下文

58同城保证“写”高可用的方法:“双主”当“主从”用,不做读写分离,在“主”挂掉的情况下,“从”(其实是另外一个主),顶上,如下图

 2 
优点:读写都到主,解决了一致性问题;“双主”当“主从”用,解决了可用性问题

带来的问题:读性能如何扩充?解决方案见下文

(2)读性能设计:如何扩展读性能

最常用的方法是,建立索引

建立非常多的索引,副作用是:

a)降低了写性能

b)索引占内存多了,放在内存中的数据就少了,数据命中率就低了,IO次数就多了

但是否想到,不同的库可以建立不同的索引呢?如下图

 3 
TIPS:不同的库可以建立不同索引

主库只提供写,不建立索引

online从库只提供online读,建立online读索引

offline从库只提供offline读,建立offline读索引

提高读性能常见方案二,增加从库

4

上文已经提到,这种方法会引发主从不一致问题,从库越多,主从时延越长,不一致问题越严重

这种方案很常见,但58没有采用

提高读性能方案三,增加缓存

传统缓存的用法是:

a)发生写请求时,先淘汰缓存,再写数据库

b)发生读请求时,先读缓存,hit则返回,miss则读数据库并将数据入缓存(此时可能旧数据入缓存),如下图

 5 
带来的问题:

a)如上文所述,数据复制会引发一致性问题,由于主从延时的存在,可能引发缓存与数据库数据不一致

b)所有app业务层都要关注缓存,无法屏蔽“主+从+缓存”的复杂性

58同城缓存使用方案:服务+数据+缓存

 6 
好处是:

1)引入服务层屏蔽“数据库+缓存”

2)不做读写分离,读写都到主的模式,不会引发不一致

(3)一致性设计

主从不一致解决方案

方案一:引入中间件

 7 
中间件将key上的写路由到主,在一定时间范围内(主从同步完成的经验时间),该key上的读也路由到主

方案二:读写都到主

8

上文已经提到,58同城采用了这种方法,不做读写分离,不会不一致

数据库与缓存不一致解决方案

两次淘汰法

9

异常的读写时序,或导致旧数据入缓存,一次淘汰不够,要进行二次淘汰

a)发生写请求时,先淘汰缓存,再写数据库,额外增加一个timer,一定时间(主从同步完成的经验时间)后再次淘汰

b)发生读请求时,先读缓存,hit则返回,miss则读数据库并将数据入缓存(此时可能旧数据入缓存,但会被二次淘汰淘汰掉,最终不会引发不一致)

(4)扩展性设计

(4.1)58同城秒级别数据扩容

需求:原来水平切分为N个库,现在要扩充为2N个库,希望不影响服务,在秒级别完成

 10 
最开始,分为2库,0库和1库,均采用“双主当主从用”的模式保证可用性

 11 
接下来,将从库提升,并修改服务端配置,秒级完成扩库

由于是2扩4,不会存在数据迁移,原来的0库变为0库+2库,原来的1库变为1库和3库

此时损失的是数据的可用性

 12 
最后,解除旧的双主同步(0库和2库不会数据冲突),为了保证可用性增加新的双主同步,并删除掉多余的数据

这种方案可以秒级完成N库到2N库的扩容。

存在的问题:只能完成N库扩2N库的扩容(不需要数据迁移),非通用扩容方案(例如3库扩4库就无法完成)

(4.2)非指数扩容,数据库增加字段,数据迁移

[这些方法在(上)篇中都已经介绍过,此处不再冗余,有兴趣的朋友回复“同城”回看(上)篇]

方案一:追日志方案

方案二:双写方案

(4.3)水平切分怎么切

四类场景覆盖99%拆库业务

a)“单key”场景,用户库如何拆分: user(uid, XXOO)

b)“1对多”场景,帖子库如何拆分: tiezi(tid, uid, XXOO)

c)“多对多”场景,好友库如何拆分: friend(uid, friend_uid, XXOO)

d)“多key”场景,订单库如何拆分:order(oid, buyer_id, seller_id, XXOO)

[这些拆库方案在(上)篇中都已经介绍过,此处不再冗余,有兴趣的朋友回复“同城”回看(上)篇]

(5)海量数据下,SQL怎么玩

不会这么玩

a)各种联合查询

b)子查询

c)触发器

d)用户自定义函数

e)“事务”都用的很少

原因:对数据库性能影响极大

拆库后,IN查询怎么玩[回复“同城”回看(上)篇]

拆库后,非Partition key的查询怎么玩[回复“同城”回看(上)篇]

拆库后,夸库分页怎么玩?[回复“同城”回看(上)篇]

问题的提出与抽象:ORDER BY xxx OFFSET xxx LIMIT xxx

单机方案:ORDER BY time OFFSET 10000 LIMIT 100

分库后的难题:如何确认全局偏移量

分库后传统解决方案:查询改写+内存排序

a)ORDER BY time OFFSET 0 LIMIT 10000+100

b)对20200条记录进行排序

c)返回第10000至10100条记录

优化方案一:增加辅助id,以减少查询量

优化方案二:模糊查询

a)业务上:禁止查询XX页之后的数据

b)业务上:允许模糊返回 => 第100页数据的精确性真这么重要么?

最后的大招!!!(由于时间问题,只在DTCC2015上分享了哟)

优化方案三:终极方案,业务无损,查询改写与两段查询

需求:ORDER BY x OFFSET 10000 LIMIT 4; 如何在分库下实现(假设分3库)

步骤一、查询改写: ORDER BY x OFFSET 3333 LIMIT 4

[4,7,9,10] <= 1库返回

[3,5,6,7] <= 2库返回

[6,8,9,11] <= 3库返回

步骤二、找到步骤一返回的min和max,即3和11

步骤三、通过min和max二次查询:ORDER BY x WHERE x BETWEEN 3 AND 11

[3,4,7,9,10] <= 1库返回,4在1库offset是3333,于是3在1库的offset是3332

[3,5,6,7,11] <= 2库返回,3在2库offset是3333

[3,5,6,8,9,11] <= 3库返回,6在3库offset是3333,于是3在3库的offset是3331

步骤四、找出全局OFFSET

3是全局offset3332+3333+3331=9996

当当当当,跳过3,3,3,4,于是全局OFFSET 10000 LIMIT 4是[5,5,6,6]

总结:58同城数据库架构设计思路

(1)可用性,解决思路是冗余(复制)

(1.1)读可用性:多个从库

(1.2)写可用性:双主模式 or 双主当主从用(58的玩法)

(2)读性能,三种方式扩充读性能

(2.1)增加索引:主从上的索引可以不一样

(2.2)增加从库

(2.3)增加缓存:服务+缓存+数据一套(58的玩法)

(3)一致性

(3.1)主从不一致:引入中间层 or 读写都走主库(58的玩法)

(3.2)缓存不一致:双淘汰来解决缓存不一致问题

(4)扩展性

(4.1)数据扩容:提升从库,double主库,秒级扩容

(4.2)字段扩展:追日志法 or 双写法

(4.3)水平切分

(单key)用户库如何拆分:, user(uid XXOO)

(1对多)帖子库如何拆分: tiezi(tid, uid, XXOO)

(多对多)好友库如何拆分: friend(uid, friend_uid, XXOO)

(多key)订单库如何拆分:order(oid, buyer_id, seller_id, XXOO)

(5)SQL玩法

(5.0)不这么玩:联合查询,子查询,触发器,自定义函数,事务

(5.1)IN查询:分发MR or 拼装成不同SQL语句

(5.2)非partition key查询:定位一个库 or 分发MR

(5.3)夸库分页

(5.3.1)修改sql语句,服务内排序

(5.3.2)引入特殊id,减少返回数量

(5.3.3)业务优化,允许模糊查询

(5.3.4)查询改写,二段查询

58同城的案例到这儿

 

二、数据库之父Codd的12条法则

另外,我们回顾一下数据库之父Codd的12条法则,作为数据库设计的指导性方针:

  1. 信息法则 
    关系数据库中的所有信息都用唯一的一种方式表示——表中的值。
  2. 保证访问法则 
    依靠表名、主键值和列名的组合,保证能访问每个数据项。
  3. 空值的系统化处理 
    支持空值(NULL),以系统化的方式处理空值,空值不依赖于数据类型。
  4. 基于关系模型的动态联机目录 
    数据库的描述应该是自描述的,在逻辑级别上和普通数据采用同样的表示方式,即数据库必须含有描述该数据库结构的系统表或者数据库描述信息应该包含在用户可以访问的表中。
  5. 统一的数据子语言法则 
    一个关系数据库系统可以支持几种语言和多种终端使用方式,但必须至少有一种语言,它的语句能够一某种定义良好的语法表示为字符串,并能全面地支持以下所有规则:数据定义、视图定义、数据操作、约束、授权以及事务。(这种语言就是SQL)
  6. 视图更新法则 
    所有理论上可以更新的视图也可以由系统更新。
  7. 高级的插入、更新和删除操作 
    把一个基础关系或派生关系作为单个操作对象处理的能力不仅适应于数据的检索,还适用于数据的插入、修改个删除,即在插入、修改和删除操作中数据行被视作集合。
  8. 数据的物理独立性 
    不管数据库的数据在存储表示或访问方式上怎么变化,应用程序和终端活动都保持着逻辑上的不变性。
  9. 数据的逻辑独立性 
    当对表做了理论上不会损害信息的改变时,应用程序和终端活动都会保持逻辑上的不变性。
  10. 数据完整性的独立性 
    专用于某个关系型数据库的完整性约束必须可以用关系数据库子语言定义,而且可以存储在数据目录中,而非程序中。
  11. 分布独立性 
    不管数据在物理是否分布式存储,或者任何时候改变分布策略,RDBMS的数据操纵子语言必须能使应用程序和终端活动保持逻辑上的不变性。
  12. 非破坏性法则 
    如果一个关系数据库系统支持某种低级(一次处理单个记录)语言,那么这个低级语言不能违反或绕过更高级语言(一次处理多个记录)规定的完整性法则或约束,即用户不能以任何方式违反数据库的约束。

 

还有一些经验:

    • 降低对数据库功能的依赖 
      功能应该由程序实现,而非DB实现。原因在于,如果功能由DB实现时,一旦更换的DBMS不如之前的系统强大,不能实现某些功能,这时我们将不得不去修改代码。所以,为了杜绝此类情况的发生,功能应该有程序实现,数据库仅仅负责数据的存储,以达到最低的耦合。
    • 定义实体关系的原则 
      当定义一个实体与其他实体之间的关系时,需要考量如下:
      • 牵涉到的实体 识别出关系所涉及的所有实体。
      • 所有权 考虑一个实体“拥有”另一个实体的情况。
      • 基数 考量一个实体的实例和另一个实体实例关联的数量。

hybridapp架构设计思路

原文:HybridAPP架构设计思路关于Hybrid模式开发app的好处,网络上已有很多文章阐述了,这里不展开。本文将从以下几个方面阐述Hybridapp架构设计的一些经验和思考。通讯作为一种跨语言开发模式,通讯层是Hybrid架构首先应该考虑... 查看详情

hybridapp架构设计思路

通讯作为一种跨语言开发模式,通讯层是Hybrid架构首先应该考虑和设计的,往后所有的逻辑都是基于通讯层展开。Native(以Android为例)和H5通讯,基本原理:Android调用H5:通过webview类的loadUrl方法可以直接执行js代码,类似浏览... 查看详情

100亿数据1万属性数据架构设计

...分钟系列之《啥,又要为表增加一列属性?》分享了两种数据库属性扩展思路,被喷得厉害。第二天补充了一篇《这才是真正的表扩展方案》,分享了互联网大数据高并发情况下,数据库属性扩容的成熟工具及思路。对于version+e... 查看详情

转载100亿数据1万属性数据架构设计

...分钟系列之《啥,又要为表增加一列属性?》分享了两种数据库属性扩展思路,被喷得厉害。第二天补充了一篇《这才是真正的表扩展方案》,分享了互联网大数据高并发情况下,数据库属性扩容的成熟工具及思路。对于version+e... 查看详情

权限管理架构设计及实现思路

digg_url="http://www.cnblogs.com/taotaozujinet/p/7807689.html";digg_title="权限管理架构设计及实现思路";digg_bgcolor="#F5FAFE";digg_skin="normal";digg_url=undefined;digg_title=undefined;digg_bgcolor=undefined;digg_ 查看详情

从etl走向etlt架构,下一代数据集成平台apacheseatunnel核心设计思路解析

...代的Oracle,DB2来承担,就是用来做查询和存储历史数据的数据库。在这个时代,其实Oracle、DB2这样的数据库本身计算能力还是比较弱的,很难满足所有场景的数仓计算任务需求。在这个过程中就诞生了Information、Talend,还有Kettle... 查看详情

typesdk服务端设计思路与架构之六:性能及调优初步

经过本系列前几篇文字的分析和设计,我们成功地开发出了自己的SDK服务端。在我们自己的调试环境下运行一切正常,但是当然我们不能就这样把这套SDK服务端部署上线到正式生产环境,稍有正式大型项目经验的同学应该都知道... 查看详情

转载数据库软件架构设计些什么

...邀请,上周五晚上在“高效运维1号群”内分享了《58同城数据库软件架构设计与实践》(这个topic今年在数据库大会上分享过),应组织方要求,发出纪要。一、基本概念二、数据库架构设计思路(1)可用性(2)读性能(3)一... 查看详情

mybatis的架构设计分析

...yBatis的几个核心部件,来探究MyBatis的实现。1.接口层---和数据库交互的方式1.1.使用传统的MyBatis提供的API这是传统的传递StatementId和查询参数给SqlSession对象,使用SqlSession对象完成和数据库的交互;MyB 查看详情

浅谈12306核心模型设计思路和架构设计

前言春节期间,无意中看到一篇文章,文章中讲到12306的业务复杂度远远比淘宝天猫这种电商网站要复杂。后来自己想想,也确实如此。所以,很想挑战一下12306这个系统的核心领域模型的设计。一般的电商网站,购买都是基于... 查看详情

typesdk总体设计思路和架构

引言:本文旨在提供读者制作一个自己的聚合SDK的思路,抛砖引玉,让更多的读者对聚合SDK有好的理解。      这是最好的时代,这是最坏的时代,这是智慧的时代,这是愚蠢的时代;这是信仰的时期,这是... 查看详情

转--《浅谈12306核心模型设计思路和架构设计》

12306这个系统,核心要解决的问题是网上售票。涉及到2个角色使用该系统:用户、铁道部。用户的核心诉求是查询余票、购票;铁道部的核心诉求是售票。购票和售票其实是一个场景,对用户来说是购票,对铁道部来说是售票。... 查看详情

mybatis的架构设计以及实例分析

...究MyBatis的实现。一、MyBatis的框架设计 1.接口层---和数据库交互的方式MyBatis和数据库的交互 查看详情

typesdk手游聚合sdk客户端设计思路与架构之四:unity开发平台部分结构设计和思路

在上一篇《iOS平台接口设计及思路》中我们阐述了ios平台的接口结构和思路。在这里我们将阐述unity平台下的接口结构和思路。      unity平台是开发平台,我们的程序代码是在这个ide下堆叠的。unity端并不需... 查看详情

一起架构-某实时分析项目云原生serverless架构的设计思路和poc代码实现

1.前言-云原生与多云混合云的部署架构大家好,我是明哥!在数字化转型的大背景下,越来越多的企业不断将越来越多的应用部署到云上,应用的架构也更加倾向云原生,以支持多云和混合云的部署架构。前... 查看详情

一起架构-某实时分析项目云原生serverless架构的设计思路和poc代码实现

1.前言-云原生与多云混合云的部署架构大家好,我是明哥!在数字化转型的大背景下,越来越多的企业不断将越来越多的应用部署到云上,应用的架构也更加倾向云原生,以支持多云和混合云的部署架构。前... 查看详情

架构师之路再刷一下思路记录-3

数据库架构设计-高可用,度性能,一致性,扩展性-数据冗余带来一致性问题单库->分片(路由,范围,哈希,路由服务)->分片+分组冗余读库,写库单点冗余写库-双写可能冲突,两个写库不同的初始值相同的补偿来避免,... 查看详情

typesdk手游聚合sdk服务端设计思路与架构之一:应用场景分析

TYPESDK服务端设计思路与架构之一:应用场景分析        作为一个渠道SDK统一接入框架,TYPESDK从一开始,所面对的需求场景就是多款游戏,通过一个统一的SDK服务端,能够同时接入几十个甚至几百个... 查看详情