一.基本概念
二.数据库体系结构的设计思路
)1)可用性
(2)读取性能
(3)一致性
)4)可扩展性
一.基本概念
概念1“单一库”
概念2“瓷砖”
平铺解决的问题是“数据量过多”的问题,也就是通常所说的“水平分割”。
随着分片的引入,“数据路由”的概念确定了哪些数据将访问哪些库。
路由规则通常有三种方法。
(1)范围:范围
优点:简单,易于扩展
缺点:各围堰的压力不均匀(新号段更活跃) ) )。
)2)散列)散列
优点:简单,数据均衡,负载均匀
缺点:迁移麻烦(2库扩展3库数据迁移) )。
(3)路由服务:配置服务器
优点:灵活性强,业务与路由算法解耦
缺点:每次访问数据库时增加一次查询
大多数互联网企业采用的方案2 :散列库、散列路由
概念3“分组”
分组解决了“可用性”问题。 分组通常通过主从方式实现。
互联网企业数据库的实际软件体系结构进行了分片和分组,如下图所示
二.数据库体系结构的设计思路
数据库软件架构师平时设计什么? 请至少考虑以下四点。
)1)如何确保数据可用性
)2)如何提高数据库的读取性能)大多数APP读多写少,读取先成为瓶颈)。
)3)如何保证一致性
)4)如何提高可扩展性
2.1如何确保数据可用性?
解决可用性问题的思路是=冗馀
如何确保网站的可用性? 复制站点、冗馀站点
如何保证服务的可用性? 复制服务、冗馀服务
如何确保数据的可用性? 数据复制,冗馀数据
数据冗馀会导致副作用=一致性问题(一致性问题暂且不谈,可用性问题暂且不谈) )。
如何确保数据库的“读取”可用性?
冗馀库
阅读冗长的库带来的副作用? 读写有延迟,可能不一致
上图为多家互联网公司mysql的体系结构,写入仍然是单点,无法保证写入的可用性。
如何确保数据库的“写入”可用性?
冗馀写入库
采用双主互备方式,可以冗余地编写数据库.
副作用是? 解决两个写同步、可能的数据冲突(例如,“自增长id”同步冲突)和同步冲突的常见解决方案有以下两种:
)1) 2个写入数据库通过不同的初始值、同一步骤增加id。 1写入库的id为0、2、4、6…; 2库的id为1、3、5、7…
)2)不使用数据的id,业务层独自生成唯一的id,避免数据冲突
58同城没有使用上述两种框架读写的“高可用性”,58同城采用“两主为主从”的方式。
虽然还是双主机,但只有一个主机在提供服务。 另一个主机是“shadow-master”,只是为了确保高可用性,平时不提供服务。
主控锁定,shadow-master居首位(vip漂移,对业务层透明,无需人工干预) ) ) ) ) ) )。
这个方法的优点:
1 )读写及时
2 )读写可用性高
不足:
1 )无法通过添加从库扩展读取性能
2 )资源利用率50%,冗主不服务
那么,如何提高读取性能呢? 进入第二个话题,如何提供读取性能?
2.2如何扩展引脚性能?
提高读取性能的方法大致有三种,第一种是建立索引。 这种方式没有展开,应该提到的是,不同的数据库可以制作不同的索引。
不在库中创建索引;
联机库创建联机访问索引,如uid
联机库创建联机访问索引,例如time。
第二种扩展读取性能的方法是增加从库。 这个方法大家用得很多,但有两个缺点。
)库越多,同步越慢
)2)同步越晚,数据不一致窗口越大(不一致是在后面叙述,还是先说提高读性能) )。
58同城没有通过该方法提高数据库的读取性能,而是采用增加缓存。 典型的缓存体系结构如下。
上游是业务APP,下游是主库、库(读写分离)、缓存。
58同城的游戏是服务数据库缓存集
业务层不直接面向db和cache,服务层屏蔽了底层db、cache的复杂性。 为什么要部署服务层,今天不展开,58采用“服务数据库缓存集”的方式提供数据访问,通过缓存提高了读取性能。
无论是用主从方式扩展读性能,还是用缓存方式扩展读性能,数据都必须复制多份(主从、db cache ),会引起一致性问题。
2.3如何保证一致性?
主从数据库的一致性,通常有两种解决方案:
(1)中间件
如果某一个key有写操作,在不一致时间窗口内,中间件会将这个key的读操作也路由到主库上。
这个方案的缺点是,数据库中间件的门槛较高(百度,腾讯,阿里,360等一些公司有,当然58也有)
(2)强制读主
58的“双主当主从用”的架构,不存在主从不一致的问题。
第二类不一致,是db与缓存间的不一致
常见的缓存架构如上,此时写操作的顺序是:
(1)淘汰cache
(2)写数据库
读操作的顺序是:
(1)读cache,如果cache hit则返回
(2)如果cache miss,则读从库
(3)读从库后,将数据放回cache
在一些异常时序情况下,有可能从【从库读到旧数据(同步还没有完成),旧数据入cache后】,数据会长期不一致。
解决办法是“缓存双淘汰”,写操作时序升级为:
(1)淘汰cache
(2)写数据库
(3)在经验“主从同步延时窗口时间”后,再次发起一个异步淘汰cache的请求
这样,即使有脏数据如cache,一个小的时间窗口之后,脏数据还是会被淘汰。带来的代价是,多引入一次读miss(成本可以忽略)。
除此之外,58同城的最佳实践之一是:建议为所有cache中的item设置一个超时时间。
说完一致性,最后一个话题是扩展性。
2.4如何提高数据库的扩展性?
原来用hash的方式路由,分为2个库,数据量还是太大,要分为3个库,势必需要进行数据迁移,58同城有一个很帅气的“数据库秒级扩容”方案。
如何秒级扩容?
首先,我们不做2库变3库的扩容,我们做2库变4库(库加倍)的扩容(未来4->8->16)
服务+数据库是一套(省去了缓存)
数据库采用“双主”的模式。
扩容步骤:
第一步,将一个主库提升
第二步,修改配置,2库变4库(原来MOD2,现在配置修改后MOD4)
扩容完成
原MOD2为偶的部分,现在会MOD4余0或者2
原MOD2为奇的部分,现在会MOD4余1或者3
数据不需要迁移,同时,双主互相同步,一遍是余0,一边余2,两边数据同步也不会冲突,秒级完成扩容!
最后,要做一些收尾工作:
(1)将旧的双主同步解除
(2)增加新的双主(双主是保证可用性的,shadow-master平时不提供服务)
(3)删除多余的数据(余0的主,可以将余2的数据删除掉)
这样,秒级别内,我们就完成了2库变4库的扩展。
OK,今天主要分享了58同城,数据库软件架构上:
(1)如何保证数据可用性
(2)如何提高数据库读性能
(3)如何保证数据一致性
(4)如何进行秒级扩容
希望大家有收获,谢谢大家!
原文出自:数据库软件架构设计些什么