mysql海量数据:mysql 海量数据的存储和访问解决方案

第1章 引言

随着互联网应用广泛普及海量数据存储和访问成为了系统设计瓶颈问题对于个大型互联网应用每天几十亿PV无疑对数据库造成了相当高负载对于系统稳定性和扩展性造成了极大问题通过数据切分来提高网站WebSite性能横向扩展数据层已经成为架构研发人员首选方式水平切分数据库可以降低单台机器负载同时最大限度降低了了宕机造成损失通过负载均衡策略有效降低了单台机器访问负载降低了宕机可能性;通过集群方案解决了数据库宕机带来单点数据库不能访问问题;通过读写分离策略更是最大限度了提高了应用中读取(Read)数据速度和并发量目前国内大型互联网应用中大量采用了这样数据切分方案Taobao,Alibaba,Tencent它们大都实现了自己分布式数据访问层(DDAL)以实现方式和实现层次来划分大概分为两个层次(Java应用为例):JDBC层封装ORM框架层实现就JDBC层直接封装而言现在国内发展较好个项目是被称作“变形虫”(Amoeba)项目由阿里集团研究院开发现在仍然处于测试阶段(beta版)其运行效率和生产时效性有待考究就ORM框架层实现而言比如Taobao基于ibatis和Spring分布式数据访问层已有多年应用运行效率和生产实效性得到了开发人员和用户肯定本文就是以ORM框架层为基础而实现分布式数据访问层本课题难点在于分库后路由规则制定和选择以及后期扩展性比如:如何做到用最少数据迁移量达到扩充数据库容量(增加机器节点)核心问题将围绕数据库分库分表路由规则和负载均衡策略展开

第2章 基本原理和概念

2.1基本原理:

人类认知问题过程总是这样:what(什么)-?why(为什么)-?how(如何

做)接下来本文将就这 3个问题展开讨论和研究:

2.1.1什么是数据切分

"Shard" 这个词英文意思是"碎片"而作为数据库相关技术用语似乎最早见于大型多人在线角色扮演游戏中"Sharding" 姑且称的为"分片"Sharding 不是门新技术而是个相对简朴软件Software理念众所周知MySQL 5 的后才有了数据表分区功能那么在此的前很多 MySQL 潜在用户都对 MySQL 扩展性有所顾虑而是否具备分区功能就成了衡量个数据库可扩展性和否个关键指标(当然不是唯指标)数据库扩展性是个永恒话题MySQL 推广者经常会被问到:如在单数据库上处理应用数据捉襟见肘而需要进行分区化的类处理是如何办到呢? 答案是:Sharding Sharding 不是个某个特定数据库软件Software附属功能而是在具体技术细节的上抽象处理是水平扩展(Scale Out亦或横向扩展、向外扩展)解决方案其主要目是为突破单节点数据库服务器 I/O 能力限制解决数据库扩展性问题

通过系列切分规则将数据水平分布到区别DB或table中在通过相应DB路由 或者 table路由规则找到需要查询具体DB或者table以进行Query操作这里所说“sharding”通常是指“水平切分” 这也是本文讨论重点具体将有什么样切分方式呢和路由方式呢?行文至此读者难免有所疑问接下来举个简单例子:我们针对个Blog应用中日志来介绍说明比如日志文章(article)表有如下字段:


article_id(),title(varchar(128)),content(varchar(1024)),user_id()



面对这样个表我们怎样切分呢?怎样将这样数据分布到区别数据库中表中去呢?其实分析blog应用我们不难得出这样结论:blog应用中用户分为两种:浏览者和blog主人浏览者浏览某个blog实际上是在个特定用户blog下进行浏览而blog主人管理自己blog也同样是在特定用户blog下进行操作(在自己空间下)所谓特定用户用数据库字段表示就是“user_id”就是这个“user_id”它就是我们需要分库依据和规则基础我们可以这样做将user_id为 1~10000所有文章信息放入DB1中article表中将user_id为10001~20000所有文章信息放入DB2中 article表中以此类推直到DBn 这样文章数据就很自然被分到了各个数据库中达到了数据切分接下来要解决问题就是怎样找到具体数据库呢?其实问题也是简单明显既然分库时候我们用到了区分字段user_id那么很自然数据库路由过程当然还是少不了 user_id考虑下我们刚才呈现blog应用不管是访问别人blog还是管理自己blog总的我都要知道这个blog用户是谁吧也就是我们知道了这个bloguser_id就利用这个user_id利用分库时候规则反过来定位具体数据库比如user_id是234利用该才规则就应该定位到DB1假如user_id是12343利用该才规则就应该定位到DB2以此类推利用分库规则反向路由到具体DB这个过程我们称的为“DB路由”

当然考虑到数据切分DB设计必然是非常规不正统DB设计那么什么样DB设计是正统DB设计呢?

我们平常规规矩矩用基本都是平常我们会自觉按照范式来设计我们数据库负载高点可能考虑使用相关Replication机制来提高读写吞吐和性能这可能已经可以满足很多需求但这套机制自身缺陷还是比较显而易见(下文会提及)上面提到“自觉按照范式设计”考虑到数据切分DB设计将违背这个通常规矩和约束为了切分我们不得不在数据库表中出现冗余字段用作区分字段或者叫做分库标记字段比如上面article例子中user_id这样字段(当然刚才例子并没有很好体现出user_id冗余性user_id这个字段即使就是不分库也是要出现算是我们捡了便宜吧)当然冗余字段出现并不只是在分库场景下才出现在很多大型应用中冗余也是必须这个涉及到高效DB设计本文不再赘述

2.1.2为什么要数据切分

上面对什么是数据切分做了个概要描述和解释读者可能会疑问为什么需要数据切分呢?像 Oracle这样成熟稳定数据库足以支撑海量数据存储和查询了?为什么还需要数据切片呢?OracleDB确实很成熟很稳定但是高昂使用费用和高端硬件支撑不是每个公司能支付试想年几千万使用费用和动辄上千万元小型机作为硬件支撑这是般公司能支付吗?即使就是能支付假如有更好方案有更廉价且水平扩展性能更好方案我们为什么不选择呢?

但是事情总是不尽人意平常我们会自觉按照范式来设计我们数据库负载高点可能考虑使用相关Replication机制来提高读写吞吐和性能这可能已经可以满足很多需求但这套机制自身缺陷还是比较显而易见首先它有效很依赖于读操作比例Master往往会成为瓶颈所在写操作需要顺序排队来执行过载话Master首先扛不住Slaves数据同步延迟也可能比较大而且会大大耗费CPU计算能力write操作在Master上执行以后还是需要在每台slave机器上都跑这时候 Sharding可能会成为鸡肋了 Replication搞不定那么为什么Sharding可以工作呢?道理很简单它可以很好扩展我们知道每台机器无论配置多么好它都有自身物理上限所以当我们应用已经能触及或远远超出单台机器某个上限时候我们惟有寻找别机器帮助或者继续升级我们硬件但常见方案还是横向扩展, 通过添加更多机器来共同承担压力我们还得考虑当我们业务逻辑不断增长我们机器能不能通过线性增长就能满足需求?Sharding可以轻松将计算存储I/O并行分发到多台机器上这样可以充分利用多台机器各种处理能力同时可以避免单点失败提供系统可用性进行很好隔离

综合以上原因数据切分是很有必要且我们在此讨论数据切分也是将MySql作为背景基于成本考虑很多公司也选择了Free且OpenMySql对MySql有所了解开发人员可能会知道MySQL 5 的后才有了数据表分区功能那么在此的前很多 MySQL 潜在用户都对 MySQL 扩展性有所顾虑而是否具备分区功能就成了衡量个数据库可扩展性和否个关键指标(当然不是唯指标)数据库扩展性是个永恒话题MySQL 推广者经常会被问到:如在单数据库上处理应用数据捉襟见肘而需要进行分区化的类处理是如何办到呢? 答案也是Sharding也就是我们所说数据切分方案

我们用免费MySQL和廉价Server甚至是PC做集群达到小型机+大型商业DB效果减少大量资金投入降低运营成本何乐而不为呢?所以我们选择Sharding拥抱Sharding

2.1.3如何做到数据切分

说到数据切分再次我们讲对数据切分思路方法和形式进行比较详细阐述和介绍说明

数据切分可以是物理对数据通过系列切分规则将数据分布到区别DB服务器上通过路由规则路由访问特定数据库这样来每次访问面对就不是单台服务器了而是N台服务器这样就可以降低单台机器负载压力

据切分也可以是数据库内 对数据通过系列切分规则将数据分布到个数据库区别表中比如将article分为article_001,article_002等子表若干个子表水平拼合有组成了逻辑上个完整article表这样做其实也是很简单 举个例子介绍说明比如article表中现在有5000w条数据此时我们需要在这个表中增加(insert)条新数据insert完毕后数据库会针对这张表重新建立索引5000w行数据建立索引系统开销还是不容忽视但是反过来假如我们将这个表分成100 个table呢从article_001直到article_1005000w行数据平均下来每个子表里边就只有50万行数据这时候我们向张只有50w行数据table中insert数据后建立索引时间就会呈数量级下降极大了提高了DB运行时效率提高了DB并发量当然分表好处还不知这些还有诸如写操作锁操作等都会带来很多显然好处

综上分库降低了单点机器负载;分表提高了数据操作效率尤其是Write操作效率 行文至此我们依然没有涉及到如何切分问题接下来我们将对切分规则进行详尽阐述和介绍说明

上文中提到要想做到数据水平切分在每个表中都要有相冗余 作为切分依据和标记字段通常应用中我们选用user_id作为区分字段基于此就有如下 3种分库方式和规则: (当然还可以有其他方式)

按号段分:

(1) user_id为区分1~1000对应DB11001~2000对应DB2以此类推;

优点:可部分迁移

缺点:数据分布不均

(2)hash取模分:

对user_id进行hash(或者如果user_id是数值型话直接使用user_id 值也可)然后用个特定数字比如应用中需要将个数据库切分成4个数据库我们就用4这个数字对user_idhash值进行取模运算也就是user_id%4,这样话每次运算就有 4种可能:结果为1时候对应DB1;结果为2时候对应DB2;结果为3时候对应DB3;结果为0时候对应DB4这样来就非常均匀将数据分配到4个DB中

优点:数据分布均匀

缺点:数据迁移时候麻烦不能按照机器性能分摊数据

(3)在认证库中保存数据库配置

就是建立个DB这个DB单独保存user_id到DB映射关系每次访问数据库时候都要先查询次这个数据库以得到具体DB信息然后才能进行我们需要查询操作

优点:灵活性强关系

缺点:每次查询的前都要多次查询性能大打折扣

以上就是通常开发中我们选择 3种方式有些复杂项目中可能会混合使用这 3种方式 通过上面描述我们对分库规则也有了简单认识和了解当然还会有更好更完善分库方式还需要我们不断探索和发现

第3章 本课题研究基本轮廓

上面文字我们按照人类认知事物规律what?why?how这样方式阐述了数据库切分些概念和意义以及对些常规切分规则做了概要介绍本课题所讨论分布数据层并不仅仅如此它是个完整数据层解决方案它到底是什么样呢?接下来文字我将详细阐述本研究课题完整思想和实现方式

分布式数据方案提供功能如下:

(1)提供分库规则和路由规则(RouteRule简称RR)将上面介绍说明中提到 3中切分规则直接内嵌入本系统具体嵌入方式在接下来内容中进行详细介绍说明和论述;

(2)引入集群(Group)概念保证数据高可用性;

(3)引入负载均衡策略(LoadBalancePolicy简称LB);

(4)引入集群节点可用性探测机制对单点机器可用性进行定时侦测以保证LB策略正确实施以确保系统高度稳定性;

(5)引入读/写分离提高数据查询速度;

仅仅是分库分表数据层设计也是不够完善当某个节点上DB服务器出现了宕机情况时候会是什么样呢?是我们采用了数据库切分方案也就是说有N太机器组成了个完整DB 如果有台机器宕机也仅仅是个DBN分的数据不能访问而已这是我们能接受起码比切分的前情况好很多了总不至于整个DB都不能访问应用中这样机器故障导致数据无法访问是可以接受假设我们系统是个高并发电子商务网站WebSite呢?单节点机器宕机带来经济损失是非常严重也就是说现在我们这样方案还是存在问题容错性能是经不起考验当然了问题总是有解决方案我们引入集群概念在此我称的为Group也就是每个分库节点我们引入多台机器每台机器保存数据是般情况下这多台机器分摊负载当出现宕机情况负载均衡器将分配负载给这台宕机机器这样

就解决了容错性问题所以我们引入了集群概念并将其内嵌入我们框架中成为框架部分





如上图所示整个数据层有Group1Group2Group3 3个集群组成这 3个集群就是数据水平切分结果当然这 3个集群也就组成了个包含完整数据DB个Group包括1个Master(当然Master也可以是多个)和 N个Slave这些Master和Slave数据是比如Group1中个slave发生了宕机现象那么还有两个slave是可以用这样模型总是不会造成某部分数据不能访问问题除非整个 Group里机器全部宕掉但是考虑到这样事情发生概率非常小(除非是断电了否则不易发生吧)

在没有引入集群以前我们次查询过程大致如下:请求数据层并传递必要分库区分字段(通常情况下是user_id)?数据层根据区分字段Route到具体DB?在这个确定DB内进行数据操作 这是没有引入集群情况当时引入集群会是什么样子呢?看图即可得知我们路由器上规则和策略其实只能路由到具体Group也就是只能路由到个虚拟Group这个Group并不是某个特定物理服务器接下来需要做工作就是找到具体物理DB服务器以进行具体数据操作基于这个环节需求我们引入了负载均衡器概念(LB)负载均衡器职责就是定位到台具体DB服务器具体规则如下:负载均衡器会分析当前sql读写特性如果是写操作或者是要求实时性很强操作直接将查询负载分到Master如果是读操作则通过负载均衡策略分配个Slave我们负载均衡器主要研究放向也就是负载分发策略通常情况下负载均衡包括随机负载均衡和加权负载均衡 随机负载均衡很好理解就是从N个Slave中随机选取个Slave这样随机负载均衡是不考虑机器性能它默认为每台机器性能是假如真实情况是这样这样做也是无可厚非假如实际情况并非如此呢?每个Slave机器物理性能和配置不情况再使用随机不考虑性能负载均衡是非常不科学这样来会给机器性能差机器带来不必要高负载甚至带来宕机危险 同时高性能数据库服务器也不能充分发挥其物理性能基于此考虑从我们引入了加权负载均衡也就是在我们系统内部通过接口可以给每台DB服务器分配个权值然后再运行时LB根据权值在集群中比重分配定比例负载给该DB服务器当然这样概念引入无疑增大了系统复杂性和可维护性有得必有失我们也没有办法逃过

有了分库有了集群有了负载均衡器是不是就万事大吉了呢? 事情远没有我们想象那么简单虽然有了这些东西基本上能保证我们数据层可以承受很大压力 但是这样设计并不能完全规避数据库宕机危害假如Group1中slave2 宕机了那么系统LB并不能得知这样话其实是很危险LB不知道它还会以为slave2为可用状态所以还是会给slave2分配负载这样问题就出来了客户端很自然就会发生数据操作失败或者异常这样是非常不友好!怎样解决这样问题呢? 我们引入集群节点可用性探测机制 或者是可用性数据推送机制 这两种机制有什么区别呢?首先说探测机制吧顾名思义探测即使就是我数据层客户端不定时对集群中各个数据库进行可用性尝试实现原理就是尝试性链接或者数据库端口尝试性访问都可以做到当然也可以用JDBC尝试性链接利用JavaException机制进行可用性判断具体会在后面文字中提到那数据推送机制又是什么呢?其实这个就要放在现实应用场景中来讨论这个问题了般情况下应用DB 数据库宕机话我相信DBA肯定是知道这个时候DBA手动将数据库当前状态通过方式推送到客户端也就是分布式数据层应用端这个时候在更新个本地DB状态列表并告知LB这个数据库节点不能使用请不要给它分配负载个是主动监听机制个是被动被告知机制两者各有所长但是都可以达到同样效果这样来刚才假设问题就不会发生了即使就是发生了那么发生概率也会降到最低

上面文字中提到Master和Slave 我们并没有做太多深入讲解如图所示个Group由1个Master和N个Slave组成为什么这么做呢?其中Master负责写操作负载也就是说切写操作都在Master上进行而读操作则分摊到Slave上进行这样可以大大提高读取效率互联网应用中经过些数据调查得出结论读/写比例大概在 10:1左右 也就是说大量数据操作是集中在读操作这也就是为什么我们会有多个Slave原因但是为什么要分离读和写呢?熟悉DB研发人员都知道写操作涉及到锁问题不管是行锁还是表锁还是块锁都是比较降低系统执行效率事情我们这样分离是把写操作集中在个节点上而读操作其其他N个节点上进行从另个方面有效提高了读效率保证了系统高可用性读写分离也会引入新问题比如我Master上数据怎样和集群中其他Slave机器保持数据同步和致呢?这个是我们不需要过多关注问题MySqlProxy机制可以帮助我们做到这点由于Proxy机制和本课题相关性不是太强

在这里不做详细介绍

综上所述本课题中所研究分布式数据层大体功能就是如此以上是对基本原理些讨论和阐述接下来就系统设计层面进行深入剖析和研究

第4章 系统设计

4.1系统实现层面选择

在引言部分中提到该系统实现层面有两种选择种是基于JDBC层面上选择种是基于现有数据持久层框架层面上选择比如Hibernateibatis两种层面各有长处也各有不足的处基于JDBC层面上系统实现系统开发难度和后期使用难度都将大大提高大大增加了系统开发费用和维护费用本课题定位是在成型ibatis持久层框架基础上进行上层封装而不是对ibatis源码直接修改这样来使本系统不会对现有框架有太多侵入性从而也增加了使用灵活性的所以选择ibatis原因如下:

(1)ibatis学习成本非常低熟练Java Programmer可在非常短时间内熟练使用ibatis;

(2)ibatis是轻量级ORM只是简单完成了ROOR映射其查询语句也是通过配置文件sql-map.xml文件在原生sql层面进行简单配置也就是说我们没有引入诸如Hibernate那样HQL概念从而增强了 sql可控性优秀DBA可以很好从sql层面对sql进行优化使数据层应用有很强可控性Hibernate虽然很强大但是由于 Hibernate是OR个重型封装且引入HQL概念不便于DBA团队(Team)对sql语句控制和性能调优

基于以上两点理由本课题在ORM产品选择上选择了易学易用且轻量级持久层框架ibatis下面讨论也都是特定于ibatis基础上讨论

4.2其他开源框架选择

些大型Java应用中我们通常会采用Spring这样开源框架尤其是 IoC(DI)这部分有效帮助开发人员管理对象依赖关系和层次降低系统各层次的间实体耦合Spring优点和用处我相信这是开发人员众所周知在此不再赘述本课题数据层也将采用Spring做为IoC(DI)框架

4.3系统开发技术和工具介绍

开发语言:Java JDK1.5

集成开发环境:Eclipse 3.3.4

Web环境下测试服务器:JBoss 4.2

构建工具:淘宝自行研发构建工具Antx(类似于Maven)当然也可以用Maven

依赖开源Jar:Spring2.0ibaitscommons-configuration(读取配置文件)log4jjunit等

Tags:  海量数据存储 mysql处理海量数据 海量数据存储方案 mysql海量数据

延伸阅读

最新评论

发表评论