精华内容
下载资源
问答
  • Oracle数据库分区是作为Oracle数据库性能优化的一种重要的手段和方法,做手头的项目以前,只聆听过分区的大名,感觉特神秘,看见某某高手在讨论会上夸夸其谈时,真是骂自己学艺不精,近作GPS方面的项目,处理的数据...
  • 谈谈怎么实现Oracle数据库分区表   数据库的读写分离   SQLSERVER性能监控级别步骤   Oracle索引问题诊断与优化(1)
    展开全文
  • 谈谈怎么实现Oracle数据库分区表 Oracle数据库分区是作为Oracle数据库性能优化的一种重要的手段和方法,做手头的项目以前,只聆听过分区的大名,感觉特神秘,看见某某高手在讨论会上夸夸其谈时,真是骂自己学艺不精...

     

    数据库分区分表以及读写分离

    谈谈怎么实现Oracle数据库分区表

    Oracle数据库分区是作为Oracle数据库性能优化的一种重要的手段和方法,做手头的项目以前,只聆听过分区的大名,感觉特神秘,看见某某高手在讨论会上夸夸其谈时,真是骂自己学艺不精,最近作GPS方面的项目,处理的数

    据量达到了几十GB,为了满足系统的实时性要求,必须提高数据的查询效率,这样就必须通过分区,以解燃眉之急!

    先说说分区的好处吧!

    1) 增强可用性:如果表的某个分区出现故障,表在其他分区的数据仍然可用;

    2) 维护方便:如果表的某个分区出现故障,需要修复数据,只修复该分区即可;

    3) 均衡I/O:可以把不同的分区映射到磁盘以平衡I/O,改善整个系统性能;

    4) 改善查询性能:对分区对象的查询可以仅搜索自己关心的分区,提高检索速度。

    Oracle数据库提供对表或索引的分区方法有三种:

    ü 范围分区

    ü Hash分区(散列分区)

    ü 复合分区

     

    一、范围分区详细说明

    范围分区就是对数据表中的某个值的范围进行分区,根据某个值的范围,决定将该数据存储在哪个分区上。如根据序号分区,根据时间等来进行分区。根据序号,比如小于2000000的放在part01, 2000000~4000000的放在part02。。。

    create table AAA
    (
     id number primary key,
     indate date not null
    )
    partition by range(indate)
    (
     partition part_01 values less than(to_date('2006-01-01','yyyy-mm-dd'))tablespace space01,
     partition part_02 values less than(to_date('2010-01-01','yyyy-mm-dd'))tablespace space02,
     partition part_03 values less than(maxvalue)tablespace space03
    );

    space01\ space02\ space03为建立的三个表空间,相当于把建立的一个大的表分在了3个不同的表空间的分区上了。

     

    二、Hash分区(散列分区)详细说明

       散列分区为通过指定分区编号来均匀分布数据的一种分区类型,因为通过在I/O设备上进行散列分区,使得这些分区大小一致。也就是只命名分区名称,这样均匀进行数据分布。

     

    三、复合分区详细说明

       有时候我们需要根据范围分区后,每个分区内的数据再散列地分布在几个表空间中,这样我们就要使用复合分区。复合分区是先使用范围分区,然后在每个分区内再使用散列分区的一种分区方法。

    partition by range(indate)subpartition by hash(id) 
    subpartitions 3 store in (space01, space02, space03) 

    partition part_01 values less than(to_date(’2006-01-01’,’yyyy-mm-dd’)), 
    partition part_02 values less than(to_date(’2010-01-01’,’yyyy-mm-dd’)), 
    partition part_03 values less than(maxvalue) 
     );

     

    四、分区表操作

    1、插入记录:insert into AAA values(1 ,sysdate);

    2、查询分区表记录:select * from AAA partition(part_01);

    3、更新分区表的记录:update AAA partition(part_01) t set indate=’’where id=1; 但是当更新的时候指定了分区,而根据查询的记录不在该分区中时,将不会更新数据

    4、删除分区表记录:delete from AAA partition(part_02) t where id=4; 如果指定了分区,而条件中的数据又不在该分区中时,将不会删除任何数据。

    5、增加一个分区:alter table AAA add partition part_04 values less than(to_date(’2012-01-01’,’yyyy-mm-dd’)) tablespace dinya_spa ce03; 增加一个分区的时候,增加的分区的条件必须大于现有分区的最大值,否则系统将提示ORA-14074 partition bound must collate higher than that of the last partition 错误。

    6、合并一个分区:alter table AAA merge partitions part_01,part_02 into partition part_02; ,如果在合并的时候把合并后的分区定为part_01的时候,系统将提示ORA-14275 cannot reuse lower-bound partition as resulting partition 错误。

    7、删除分区:alter table AAA drop partition part_01; 删除分区表的一个分区后,查询该表的数据时显示,该分区中的数据已全部丢失,所以执行删除分区动作时要慎重,确保先备份数据后再执行,或将分区合并。

     

    五、建立索引

        分区表和一般表一样可以建立索引,分区表可以创建局部索引和全局索引。当分区中出现许多事务并且要保证所有分区中的数据记录的唯一性时采用全局索引。

    1.       局部索引分区的建立:create index idx_t on AAA(id) 
     local 

    partition idx_1 tablespace space01, 
    partition idx_2 tablespace space02, 
    partition idx_3 tablespace space03 
    );

    2.       全局索引建立时global 子句允许指定索引的范围值,这个范围值为索引字段的范围值:create index idx_t on AAA(id)
    global partition by range(id) 

    partition idx_1 values less than (1000) tablespace space01, 
    partition idx_2 values less than (10000) tablespace space02, 
    partition idx_3 values less than (maxvalue) tablespace space03 
    );

    当然也可以不指定索引分区名直接对整个表建立索引:

    create index idx_t on AAA(id);

     

     

     

    数据库的垂直切分和水平切分

     

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

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

    综上,分库降低了单点机器的负载;分表,提高了数据操作的效率,尤其是Write操作的效率。

     


     

     

     

     

    数据库的读写分离

     

     读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

           为什么要分库、分表、读写分?

           单表的数据量限制,当单表数据量到一定条数之后数据库性能会显著下降。数据多了之后,对数据库的读、写就会很多。分库减少单台数据库的压力。接触过几个分库分表的系统,都是通过主键进行散列分裤分表的。这类数据比较特殊,主键就是唯一的获取该条信息的主要途径。比如:京东的订单、财付通的交易记录等。。。该类数据的用法,就是通过订单号、交易号来查询该笔订单、交易。

            还有一类数据,比如用户信息,每个用户都有系统内部的一个userid,与userid对应的还有用户看到的登录名。那么如果分库分表的时候单纯通过userid进行散列分库,那么根据登录名来获取用户的信息,就无法知道该用户处于哪个数据库中。

           或许有朋友会说,我们可以维护一个email----userid的映射关系,根据email先查询到userid,在根据userid的分库分表规则到对应库的对应表来获取用户的记录信息。这么做是可以的,但是这个映射关系的条数本身也是个瓶颈,原则上是没有减少单表内数据的条数,算是一个单点。并且要维护这个映射关系和用户信息的一致性(修改登录名、多登录名等其他特殊需求),最大一个原因,其实用户信息是一个读大于写的库,web2.0都是以用户为中心,所有信息都和用户信息相关联,所以对用户信息拆分还是有一定局限性的。

           对于这类读大于写并且数据量增加不是很明显的数据库,推荐采用读写分离+缓存的模式,试想一下一个用户注册、修改用户信息、记录用户登录时间、记录用户登录IP、修改登录密码,这些是写操作。但是以上这些操作次数都是很小的,所以整个数据库的写压力是很小的。唯一一个比较大的就是记录用户登录时间、记录用户登录IP这类信息,只要把这些经常变动的信息排除在外,那么写操作可以忽略不计。所以读写分离首要解决的就是经常变化的数据的拆分,比如:用户登录时间、记录用户登录IP。这类信息可以单独独立出来,记录在持久化类的缓存中(可靠性要求并不高,登陆时间、IP丢了就丢了,下次来了就又来了)

            以oracle为例,主库负责写数据、读数据。读库仅负责读数据。每次有写库操作,同步更新cache,每次读取先读cache在读DB。写库就一个,读库可以有多个,采用dataguard来负责主库和多个读库的数据同步。

     

    转载于:https://www.cnblogs.com/zhangj391/p/6575171.html

    展开全文
  • 问题:有一个张销售表, 每天会插入数万条销售数据,随着数据的增加, 查询越来越...下面就来看一下如何实现sql service 数据库分区。  假设:有一张销售表,里面有两百万条数据(这个还算少了, 怎么也得千万级...

    转:原文地址 https://www.51baidu.com.cn/Home/Detail/2501

    问题:有一个张销售表, 每天会插入数万条销售数据,随着数据的增加, 查询越来越慢,加上各种筛选条件,查询速度就更慢了,例如数据库分区可以有效解决这个问题。下面就来看一下如何实现sql service 数据库分区。

         假设:有一张销售表,里面有两百万条数据(这个还算少了, 怎么也得千万级以上),查询条件, 往年的数据按照年份来查询, 当年的数据按照季度来查询。

        根据假设, 我们先弄出一个测试环境吧,

    首先我创建了一个数据库, 名字叫 FenQuDemo , 建了一张销售表, 名字叫 FF_SellTable,然后往表里插入了两百万行数据

    我们右键查看FF_SellTable的属性, 应该是下图标注的那样

     

    创建分区

    数据库FenQuDemo 右键 -> 属性 ->文件

     新建5个文件组,对应5个数据库文件,Y2017存放2017年的数据,Q1,Q2,Q3,Q4存放4个季度的数据,这里我们将文件都放在了同一个文件夹,如果条件允许,放在不同的磁盘上会增加读写效率。

    建立分区函数

    建立分区函数就是在当前数据库中创建一个函数,该函数可根据指定列的值将表或索引的各行映射到分区。 使用 CREATE PARTITION FUNCTION 是创建已分区表或索引的第一步

    CREATE PARTITION FUNCTION [FenQuDemoFunc](DATETIME) 
    AS RANGE RIGHT 
    FOR VALUES 
    (N'2018-01-01T00:00:00',N'2018-04-01T00:00:00', N'2018-07-01T00:00:00',N'2018-10-01T00:00:00',N'2019-01-01T00:00:00');

    具体语法和参数请看:使用CREATE PARTITION FUNCTION 建立分区函数,以及参数介绍

    注:如果运行上面的sql语句报错, 错误信息为:“消息 7736,级别 16,状态 1,第 1 行只能在 SQL Server Enterprise Edition 中创建分区函数。只有 SQL Server Enterprise Edition 支持分区。”这是因为你安装的sql不是企业版,数据库分区是企业版才有的功能, 这里是企业版数据库的安装地址,可以去下载安装:SQL Server Management Studio(2012,简体中文企业版)

    建立分区方案

    在当前数据库中创建一个将已分区表或已分区索引的分区映射到文件组的方案。 已分区表或已分区索引的分区的个数和域在分区函数中确定

    CREATE PARTITION SCHEME [FenQuDemoGroup] AS PARTITION [FenQuDemoFunc] TO ([year2017], [Q1],[Q2],[Q3],[Q4])

    具体语法和参数请看:使用 CREATE PARTITION SCHEME 建立分区方案,以及参数介绍

     

    建好的分区函数和分区方案如下:分区方案和分区函数下会多出一个文件

    建立分区索引

    CREATE CLUSTERED INDEX [ClusteredIndex_CreateDate] ON [dbo].[FF_SellTable]
    (
    [f_createTime]
    )WITH (SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, ONLINE = OFF) ON [FenQuDemoGroup]([f_createTime])
    

    参数:

        ClusteredIndex_CreateDate 索引名称

        FF_SellTable 表名(要对那张表进行分区)

        f_createTime 列名(要根据哪一列进行分区)

        FenQuDemoGroup 分区方案名称

     

    这样表分区就完成了

    接下来我们就可以对数据库进行分区查询了, 

    select $PARTITION.FenQuDemoFunc(f_createTime) as 分区编号,count(ID) as 记录数 from FF_SellTable group by $PARTITION.FenQuDemoFunc(f_createTime)

    运行结果如下:

     

    查询具体的分区语法为:

    SELECT TOP 100 * from  FF_SellTable WHERE $PARTITION.FenQuDemoFunc(f_createTime) = 5
    

    至于参数具体意思,以及其他的语法,可以参考 $PARTITION (Transact-SQL)

    分区新增和合并

            现在如果是2019年,需要将2018年的四个季度(Q1,Q2,Q3,Q4)合并成一个新的文件组 year2018,而之前的Q1,Q2,Q3,Q4存放2019年四个季度的数据。

    1.新建2018文件组

    2.合并分区

    先将所有季度文件组都合并,这样2019年数据之前都在2017文件组

    ALTER PARTITION FUNCTION FenQuDemoFunc() MERGE RANGE (N'2018-01-01T00:00:00');
    ALTER PARTITION FUNCTION FenQuDemoFunc() MERGE RANGE (N'2018-04-01T00:00:00');  
    ALTER PARTITION FUNCTION FenQuDemoFunc() MERGE RANGE (N'2018-07-01T00:00:00');  
    ALTER PARTITION FUNCTION FenQuDemoFunc() MERGE RANGE (N'2018-10-01T00:00:00');
    

    可以在分区方案上查看创建SQL语句,这时的分区方案已经更改为:

    CREATE PARTITION SCHEME [FenQuDemoGroup] AS PARTITION [FenQuDemoFunc] TO ([Y2017], [PRIMARY])
    

     

    3.分区新增

    首先将2018年的数据放在year2018文件组

    --选择文件组
    ALTER PARTITION SCHEME FenQuDemoGroup  
    NEXT USED [year2018] ;
     
    --修改分区函数  
    ALTER PARTITION FUNCTION FenQuDemoFunc()  
    SPLIT RANGE (N'2018-01-01T00:00:00.000') ;
    

    同理将2019年的数据分别放在2019年的各个季度中

    ALTER PARTITION FUNCTION FenQuDemoFunc()  MERGE RANGE (N'2018-01-01T00:00:00');
     
    ALTER PARTITION SCHEME FenQuDemoGroup  NEXT USED [Q1];
    ALTER PARTITION FUNCTION FenQuDemoFunc()  SPLIT RANGE (N'2018-01-01T00:00:00.000');
     
    ALTER PARTITION SCHEME FenQuDemoGroup  NEXT USED [Q2]; 
    ALTER PARTITION FUNCTION FenQuDemoFunc()  SPLIT RANGE (N'2018-04-01T00:00:00.000');
     
    ALTER PARTITION SCHEME FenQuDemoGroup  NEXT USED [Q3];
    ALTER PARTITION FUNCTION FenQuDemoFunc()  SPLIT RANGE (N'2018-07-01T00:00:00.000');
     
    ALTER PARTITION SCHEME FenQuDemoGroup  NEXT USED [Q4];
    ALTER PARTITION FUNCTION FenQuDemoFunc()  SPLIT RANGE (N'2018-10-01T00:00:00.000');
    

     

    创建分区方案

    CREATE PARTITION FUNCTION [FenQuDemoFunc](datetime) 
    AS RANGE RIGHT 
    FOR VALUES (
            N'2017-01-01T00:00:00.000',     
            N'2018-01-01T00:00:00.000', 
            N'2019-04-01T00:00:00.000', 
            N'2019-07-01T00:00:00.000', 
            N'2019-10-01T00:00:00.000'
    )
    

    创建分区函数

    CREATE PARTITION SCHEME [FenQuDemoGroup] AS PARTITION [FenQuDemoFunc] TO ([year2017], [year2018], [Q1], [Q2], [Q3], [Q4])

    上述语法,参数可以参考:ALTER PARTITION FUNCTION (Transact-SQL)

     

     

    除了合并分区还有一个其他的办法, 就是现将分区转换为普通表,然后在进行分区,步骤为:先删除表中的索引,然后在重新创建索引,创建索引如下

    CREATE CLUSTERED INDEX [index_sellTable]  ON dbo.FF_SellTable(f_createTime) ON [Primary]
    

    创建完之后刷新一下, 查看表的属性:

     

    原文地址:白码驿站

    展开全文
  • 本文将跳出任何一种数据库,从原理的角度上来分析下面的几个问题: ...有多个副本的数据库怎么在出现各种问题时保证系统的持续可用? 问题三:性能。不使用共享存储的RDBMS,为了保证多个副本间的数据一致性,是...

    本文将跳出任何一种数据库,从原理的角度上来分析下面的几个问题:

    • 问题一:数据一致性。在不使用共享存储的情况下,传统RDBMS(例如:Oracle/MySQL/PostgreSQL等),能否做到在主库出问题时的数据零丢失。
    • 问题二:分区可用性。有多个副本的数据库,怎么在出现各种问题时保证系统的持续可用?
    • 问题三:性能。不使用共享存储的RDBMS,为了保证多个副本间的数据一致性,是否会损失性能?如何将性能的损失降到最低?
    • 总结

    问题一:数据一致性

    问:脱离了共享存储,传统关系型数据库就无法做到主备强一致吗?

    答:我的答案,是No。哪怕不用共享存储,任何数据库,也都可以做到主备数据的强一致。Oracle如此,MySQL如此,PostgreSQL如此,OceanBase也如此。

    如何实现主备强一致?大家都知道数据库中最重要的一个技术:WAL(Write-Ahead-Logging)。更新操作写日志(Oracle Redo Log,MySQL Binlog等),事务提交时,保证将事务产生的日志先刷到磁盘上,保证整个事务的更新操作数据不丢失。那实现数据库主备数据强一致的方法也很简单:

    • 事务提交的时候,同时发起两个写日志操作,一个是将日志写到本地磁盘的操作,另一个是将日志同步到备库并且确保落盘的操作;
    • 主库此时等待两个操作全部成功返回之后,才返回给应用方,事务提交成功;

    整个事务提交操作的逻辑,如下图所示:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    上图所示,由于事务提交操作返回给应用时,事务产生的日志在主备两个数据库上都已经存在了,强同步。因此,此时主库Crash的话,备库提供服务,其数据与主库是一致的,没有任何事务的数据丢失问题。主备数据强一致实现。用过Oracle的朋友,应该都知道Oracle的Data Guard,可工作在 最大性能,最大可用,最大保护 三种模式下,其中第三种 最大保护 模式,采用的就是上图中的基本思路。

    实现数据的强同步实现之后,接下来到了考虑可用性问题。现在已经有主备两个数据完全一致的数据库,备库存在的主要意义,就是在主库出故障时,能够接管应用的请求,确保整个数据库能够持续的提供服务:主库Crash,备库提升为主库,对外提供服务。此时,又涉及到一个决策的问题,主备切换这个操作谁来做?人当然可以做,接收到主库崩溃的报警,手动将备库切换为主库。但是,手动的效率是低下的,更别提数据库可能会随时崩溃,全部让人来处理,也不够厚道。一个HA(High Availability)检测工具应运而生:HA工具一般部署在第三台服务器上,同时连接主备,当其检测到主库无法连接,就切换备库,很简单的处理逻辑,如下图所示:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    HA软件与主备同时连接,并且有定时的心跳检测。主库Crash后,HA探测到,发起一个将备库提升为主库的操作(修改备库的VIP或者是DNS,可能还需要将备库激活等一系列操作),新的主库提供对外服务。此时,由于主备的数据是通过日志强同步的,因此并没有数据丢失,数据一致性得到了保障。

    有了基于日志的数据强同步,有了主备自动切换的HA软件,是不是就一切万事大吉了?我很想说是,确实这个架构已经能够解决90%以上的问题,但是这个架构在某些情况下,也埋下了几个比较大的问题。

    首先,一个一目了然的问题,主库Crash,备库提升为主库之后,此时的数据库是一个单点,原主库重启的这段时间,单点问题一直存在。如果这个时候,新的存储再次Crash,整个系统就处于不可用状态。此问题,可以通过增加更多副本,更多备库的方式解决,例如3副本(一主两备),此处略过不表。

    其次,在主备环境下,处理主库挂的问题,算是比较简单的,决策简单:主库Crash,切换备库。但是,如果不是主库Crash,而是网络发生了一些问题,如下图所示:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    若Master与Slave之间的网络出现问题,例如:断网,网络抖动等。此时数据库应该怎么办?Master继续提供服务?Slave没有同步日志,会数据丢失。Master不提供服务?应用不可用。在Oracle中,如果设置为 最大可用 模式,则此时仍旧提供服务,允许数据不一致;如果设置为 最大保护 模式,则Master不提供服务。因此,在Oracle中,如果设置为 最大保护 模式,一般建议设置两个或以上的Slave,任何一个Slave日志同步成功,Master就继续提供服务,提供系统的可用性。

    网络问题不仅仅出现在Master和Slave之间,同样也可能出现在HA与Master,HA与Slave之间。考虑下面的这种情况:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    HA与Master之间的网络出现问题,此时HA面临两个抉择:

    • HA到Master之间的连接不通,认为主库Crash。选择将备库提升为主库。但实际上,只是HA到Master间的网络有问题,原主库是好的(没有被降级为备库,或者是关闭),仍旧能够对外提供服务。新的主库也可以对外提供服务。两个主库,产生双写问题,最为严重的问题。
    • HA到Master之间的连接不同,认为是网络问题,主库未Crash。HA选择不做任何操作。但是,如果这时实际上确实是主库Crash了,HA不做操作,数据库不对外提供服务。此时,双写问题避免了,但是应用的可用性受到了影响。

    最后,数据库会出现问题,数据库之间的网络会出现问题,那么再考虑一层,HA软件本身也有可能出现问题。如下图所示:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    如果是HA软件本身出现了问题,怎么办?我们通过部署HA,来保证数据库系统在各种场景下的持续可用,但是HA本身的持续可用谁来保证?难道我们需要为HA做主备,然后再HA之上再做另一层HA?一层层加上去,子子孙孙无穷尽也 … …

    其实,上面提到的这些问题,其实就是经典的分布式环境下的一致性问题(Consensus),近几年比较火热的Lamport老爷子的Paxos协议,Stanford大学最近发表的Raft协议,都是为了解决这一类问题。(对Raft协议感兴趣的朋友,可以再看一篇Raft的动态演示PPT:Understandable Distributed Consensus

    问题二:分区可用性

    前面,我们回答了第一个问题,数据库如果不使用共享存储,能否保证主备数据的强一致?答案是肯定的:可以。但是,通过前面的分析,我们又引出了第二个问题:如何保证数据库在各种情况下的持续可用?至少前面提到的HA机制无法保证。那么是否可以引入类似于Paxos,Raft这样的分布式一致性协议,来解决上面提到的各种问题呢?

    答案是可以的,我们可以通过引入类Paxos,Raft协议,来解决上面提到的各类问题,保证整个数据库系统的持续可用。考虑仍旧是两个数据库组成的主备强一致系统,仍旧使用HA进行主备监控和切换,再回顾一下上一节新引入的两个问题:

    • HA软件自身的可用性如何保证?
    • 如果HA软件无法访问主库,那么这时到底是主库Crash了呢?还是HA软件到主库间的网络出现问题了呢?如何确保不会同时出现两个主库,不会出现双写问题?
    • 如何在解决上面两个问题的同时,保证数据库的持续可用?

    为了解决这些问题,新的系统如下所示:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    相对于之前的系统,可以看到这个系统的复杂性明显增高,而且不止一成。数据库仍旧是一主一备,数据强同步。但是除此之外,多了很多变化,这些变化包括:

    • 数据库上面分别部署了HA Client;
    • 原来的一台HA主机,扩展到了3台HA主机。一台是HA Master,其余的为HA Participant;
    • HA主机与HA Client进行双向通讯。HA主机需要探测HA Client所在的DB是否能够提供服务,这个跟原有一致。但是,新增了一条HA Client到HA主机的Master Lease通讯。

    这些变化,能够解决上面的两个问题吗?让我们一个一个来分析。首先是:HA软件自身的可用性如何保证?

    从一台HA主机,增加到3台HA主机,正是为了解决这个问题。HA服务,本身是无状态的,3台HA主机,可以通过Paxos/Raft进行自动选主。选主的逻辑,我这里就不做赘述,不是本文的重点,想详细了解其实现的,可以参考互联网上洋洋洒洒的关于Paxos/Raft的相关文章。总之,通过部署3台HA主机,并且引入Paxos/Raft协议,HA服务的高可用可以解决。HA软件的可用性得到了保障。

    第一个问题解决,再来看第二个问题:如何识别出当前是网络故障,还是主库Crash?如何保证任何情况下,数据库有且只有一个主库提供对外服务?

    通过在数据库服务器上部署HA Client,并且引入HA Client到HA Master的租约(Lease)机制,这第二个问题同样可以得到完美的解决。所谓HA Client到HA Master的租约机制,就是说图中的数据库实例,不是永远持有主库(或者是备库)的权利。当前主库,处于主库状态的时间是有限制的,例如:10秒。每隔10秒,HA Client必须向HA Master发起一个新的租约,续租它所在的数据库的主库状态,只要保证每10秒收到一个来自HA Master同意续租的确认,当前主库一直不会被降级为备库。

    第二个问题,可以细分为三个场景:

    • 场景一:主库Crash,但是主库所在的服务器正常运行,HA Client运行正常

    主库Crash,HA Client正常运行。这种场景下,HA Client向HA Master发送一个放弃主库租约的请求,HA Master收到请求,直接将备库提升为主库即可。原主库起来之后,作为备库运行。

    • 场景二:主库所在的主机Crash。(主库和HA Client同时Crash)

    此时,由于HA Client和主库同时Crash,HA Master到HA Client间的通讯失败。这个时候,HA Master还不能立即将备库提升为主库,因为区分不出场景二和接下来的场景三(网络问题)。因此,HA Master会等待超过租约的时间(例如:12秒),如果租约时间之内仍旧没有续租的消息。那么HA Master将备库提升为主库,对外提供服务。原主库所在的主机重启之后,以备库的状态运行。

    • 场景三:主库正常,但是主库到HA Master间的网络出现问题

    对于HA Master来说,是区分不出场景二和场景三的。因此,HA Master会以处理场景二同样的逻辑处理场景三。等待超过租约的时间,没有收到续租的消息,提升原备库为主库。但是在提升备库之前,原主库所在的HA Client需要做额外的一点事。原主库HA Client发送给HA Master的续租请求,由于网络问题,一直没有得到响应,超过租约时间,主动将本地的主库降级为备库。如此一来,待HA Master将原备库提升为主库时,原来的主库已经被HA Client降级为备库。双主的情况被杜绝,应用不可能产生双写。

    同过以上三个场景的分析,问题二同样在这个架构下被解决了。而解决问题二的过程中,系统最多需要等待租约设定的时间,如果租约设定为10秒,那么出各种问题,数据库停服的时间最多为10秒,基本上做到了持续可用。这个停服的时间,完全在于租约的时间设置。

    到这儿,基本可以说,要实现一个持续可用(分区可用性保证),并且保证主备数据强一致的数据库系统,是完全没问题的。在现有数据库系统上做改造,也是可以的。但是,如果考虑到实际的实现,这个复杂度是非常高的。数据库的主备切换,是数据库内部实现的,此处通过HA Master来提升主库;通过HA Client来降级备库;保证数据库崩溃恢复后,恢复为备库;通过HA Client实现主库的租约机制;实现HA主机的可用性;所有的这些,在现有数据库的基础上实现,都有着相当的难度。能够看到这儿,而且有兴趣的朋友,可以针对此问题进行探讨。

    问题三:性能

    数据一致性,通过日志的强同步,所有数据均可以解决。分区可用性,在出现任何异常情况时仍旧保证系统的持续可用,可用在数据强同步的基础上引入Paxos/Raft等分布式一致性协议来解决,虽然这个目前没有成熟的实现。接下来再让我们来看看一个很多朋友都很感兴趣的问题:如何在保证强同步的基础上,同时保证高性能?回到我们本文的第一幅图:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    为了保证数据强同步,应用发起提交事务的请求时,必须将事务日志同步到Slave,并且落盘。相对于异步写Slave,同步方式多了一次Master到Slave的网络交互,同时多了一次Slave上的磁盘sync操作。反应到应用层面,一次Commit的时间一定是增加了,具体增加了多少,要看主库到备库的网络延时和备库的磁盘性能。

    为了提高性能,第一个很简单的想法,就是部署多个Slave,只要有一个Slave的日志同步完成返回,加上本地的Master日志也已经落盘,提交操作就可以返回了。多个Slave的部署,对于消除瞬时的网络抖动,非常有效果。在Oracle的官方建议中,如果使用最大保护模式,也建议部署多个Slave,来最大限度的消除网络抖动带来的影响。如果部署两个Slave,新的部署架构图如下所示:

    数据一致性-分区可用性-性能—多副本强同步数据库系统实现之我见

    新增一个Slave,数据三副本。两个Slave,只要有一个Slave日志同步完成,事务就可以提交,极大地减少了某一个网络抖动造成的影响。增加了一个副本之后,还能够解决当主库Crash之后的数据安全性问题,哪怕主库Crash,仍旧有两个副本可以提供服务,不会形成单点。

    但是,在引入数据三副本之后,也新引入了一个问题:主库Crash的时候,到底选择哪一个备库作为新的主库?当然,选主的权利仍旧是HA Master来行使,但是HA Master该如何选择?这个问题的简单解决可以使用下面的几个判断标准:

    1. 日志优先。两个Slave,哪个Slave拥有最新的日志,则选择这个Slave作为新的主库。
    2. 主机层面排定优先级。如果两个Slave同时拥有最新的日志,那么该如何选择?此时,选择任何一个都是可以的。例如:可以根据Slave主机IP的大小进行选择,选择IP小的Slave作为新的主库。同样能够解决问题。

    新的主库选择出来之后,第一件需要做的事,就是将新的Master和剩余的一个Slave,进行日志的同步,保证二者日志达到一致状态后,对应用提供服务。此时,三副本问题就退化为了两副本问题,三副本带来的防止网络抖动的红利消失,但是由于两副本强同步,数据的可靠性以及一致性仍旧能够得到保障。

    当然,除了这一个简单的三副本优化之外,还可以做其他更多的优化。优化的思路一般就是同步转异步处理,例如事务提交写日志操作;使用更细粒度的锁;关键路径可以采用无锁编程等。

    多副本强同步,做到极致,并不一定会导致系统的性能损失。当然,极致应该是什么样子的?我的想法是:

    • 对于单个事务来说,RT增加。其响应延时一定会增加(至少多一个网络RT,多一次磁盘Sync);
    • 对整个数据库系统来说,吞吐量不变。远程的网络RT和磁盘Sync并不会消耗本地的CPU资源,本地CPU的开销并未增大。只要是异步化做得好,整个系统的吞吐量,并不会由于引入强同步而降低。

    总结

    洋洋洒洒写了一堆,最后做一个小小的总结:

    • 各种主流关系型数据库系统是否可以实现主备的强一致,是否可以保证不依赖于存储的数据一致性?

    可以。Oracle有,MySQL 5.7,阿里云RDS,网易RDS都有类似的功能。

    • 目前各种关系型数据库系统,能否在保证主备数据强一致的基础上,提供系统的持续可用和高性能?

    可以做,但是难度较大,目前主流关系型数据库缺乏这个能力。

    展开全文
  • 这篇博客文章接下来的部分,将跳出任何一种数据库,从原理的角度上来分析下面的几个问题: ...有多个副本的数据库怎么在出现各种问题时保证系统的持续可用? 问题三:性能。不使用共享存储的RDBMS,为
  • 前面我简单记录过怎么实现分区,现在要实现就是让他自动分区。实现方法就是使用Quartz框架 这个框架很强大,有兴趣可以去http://www.quartz-scheduler.org/下载感觉他的功能,总之它的核心就是调度器。“调度器...
  • 这篇博客文章接下来的部分,将跳出任何一种数据库,从原理的角度上来分析下面的几个...有多个副本的数据库怎么在出现各种问题时保证系统的持续可用? 问题三:性能。不使用共享存储的RDBMS,为了保证多个副...
  • 首先打开sqlserver工具,然后新建一个数据库如图: 写完数据库名称后先不要确认,在左侧选项中选择文件组。给数据库添加一些文件组,如图: 我这里按今年月份,每个月新建一个文件组。然后点击确定。 数据库...
  • 各位大神知不知道怎么解决。没有分区的spark-sql和普通方法有啥区别啊。 String[] predicates = new String[] { "1=1 order by id limit 400000,50000", "1=1 order by id limit 450000,50000", "1=1 ...
  • 本地 跑起来tomcat ,数据库只有 一个分区 ; 我在网上找的 File[] roots = File.listRoots(); 遍历之后 只取到了 '/' 分区 ,请问其它分区 怎么获取
  • MYSQL实现数据库自动分区 oracle_分区 分区分库分表的思考 如何做一次Elasticsearch技术分享? MySQL 分区分表应用场景分析和分区中可能遇到的坑点 阿里不让多表join?我偏要! SQL行转列、列转行 ...
  • ADO.NET操作数据库(三)

    千次阅读 2016-11-02 20:45:40
    SqlDataAdapter其实是对数据操作的封装,让我们写代码变得简单了,adapter是转换器的意思,不需要关心适配器内部是怎么实现的,它能够把数据库中的数据获取到内存里面。 分表存储、分区存储。 使用主从数据库:主...
  • 2.3.4 实现物理设计 27 2.4 反向设计数据库 28 2.5 对象—关系和对象数据库 28 2.5.1 关系模型 28 2.5.2 对象模型 28 2.5.3 对象—关系模型 29 2.5.4 半结构数据模型 30 第3章 Oracle DBA的UNIX/...
  • 你或许能看到所有的和数据库文件相关的数据都放在一个路径,或者分区里,所有的索引也是在一个路径下,同样系统和临时表空间也是如此。重做日志能够放在两个位置。你或许看到上百的表空间都有一到两个文件,你能看到...

空空如也

空空如也

1 2 3 4
收藏数 76
精华内容 30
关键字:

数据库分区怎么实现