您的位置:新葡亰496net > 奥门新萄京娱乐场 > 新葡亰496net数据库面试葵花宝典,中跨库事务处

新葡亰496net数据库面试葵花宝典,中跨库事务处

发布时间:2019-11-15 12:48编辑:奥门新萄京娱乐场浏览(100)

      最近新接手了一项业务,其中有一个方法,需要对业务表进行写入数据,之后记录到日志表中。这部分代码原先是前人写的,他没有采用任何方案,只是简单的调用Ado.net执行了两次写库操作。因此经常出现系统使用者不断发邮件说数据有问题,经过查看原因就是在于写库操作中,有某个表写入失败,但是其他表写入成功,导致出现了数据不一致的问题。后来本想改用事务,但发现日志表和业务表不在同一个数据库下,甚至不在同一个IP下,对于这个问题,我想到了有以下解决方案。

    根据微服务架构的鼻祖Martin Fowler的忠告,微服务架构中应当尽量避免分布式事务。然而,在某些领域,分布式事务如同宿命中的对手无法避免。在工程领域,分布式事务的讨论主要聚焦于强一致性和最终一致性的解决方案。典型方案包括:

    你目前接触的mysql版本是什么?除了官方版本,还接触过其他的mysql分支版本嘛?

    新葡亰496net,由ado.net管理的事务改为自己手动提交事务和Commit或者RollBack操作:

    1.两阶段提交(2PC, Two-phase Commit)方案;

    产生分支的原因

    step1:按照连接字符串和sql分类,存入Dictionary<string,string>中,Key为连接字符串,Value为针对此数据库的Sql语句,多条用分号隔开;

    2.eBay 事件队列方案;

    许多开发人员认为有必要将其拆分成其他项目,并且每个分支项目都有自己的专长。该需求以及Oracle对核心产品增长缓慢的担忧,导致出现了许多开发人员感兴趣的子项目和分支

    step2:遍历此Dictionary,打开这些连接;

    3.TCC 补偿模式;

    三个流行MySQL分支:Drizzle、MariaDB和Percona Server(包括XtraDB引擎)

    step3:对于每个连接,打开事务;

    4.缓存数据最终一致性。

    MariaDB不仅是mysql的替代品,主要还是创新和提高mysql自有技术。

    step4:执行针对每个连接的sql,出现错误则全部rollback,否则全部commit;

    一致性理论

       新功能介绍

    step5:关闭连接,记录运行情况,记录日志。

    分布式事务的目的是保障分库数据一致性,而跨库事务会遇到各种不可控制的问题,如个别节点永久性宕机,像单机事务一样的ACID是无法奢望的。另外,业界著名的CAP理论也告诉我们,对分布式系统,需要将数据一致性和系统可用性、分区容忍性放在天平上一起考虑。

    1. multi-source replication 多源复制

    2. 表的并行复制

    3. galera cluster集群

    4. 新葡亰496net数据库面试葵花宝典,中跨库事务处理解决方案。spider水平分片

    5. tokuDB存储引擎

    具体代码如下:

    两阶段提交协议(简称2PC)是实现分布式事务较为经典的方案,但2PC 的可扩展性很差,在分布式架构下应用代价较大,eBay 架构师Dan Pritchett 提出了BASE 理论,用于解决大规模分布式系统下的数据一致性问题。BASE 理论告诉我们:可以通过放弃系统在每个时刻的强一致性来换取系统的可扩展性。

    XtraDB是innodb存储引擎的增强版,可用来更好地发挥最新的计算机硬件系统性能,还包含在高性能模式下的新特性。它可以向下兼容,因为它是在innodb基础上构建,所以他有更多的指标和扩展功能。而且它在cpu多核的条件下,可以更好地使用内存,时数据库性能提到更高!

      1         //提交事务用的sql
      2         public const string MultiTran = @"BEGIN TRAN
      3                                             {0}";
      4 
      5         /// <summary>
      6         /// 事务返回的信息
      7         /// </summary>
      8         public struct TransInfo
      9         {
     10             /// <summary>
     11             /// sql总条数
     12             /// </summary>
     13             public int Total;
     14             /// <summary>
     15             /// 事务执行是否成功
     16             /// </summary>
     17             public bool IsSuccess;
     18             /// <summary>
     19             /// 失败时的sql
     20             /// </summary>
     21             public string WrongMessage;
     22         }        
     23 
     24         /// <summary>
     25         /// 跨库事务异常对象
     26         /// </summary>
     27         public class TransException : Exception
     28         {
     29             public TransException(string message) : base(message)
     30             {
     31             }
     32 
     33             public string wrongSQL { get; set; }
     34             public string wrongAt { get; set; }
     35             /// <summary>
     36             /// 已经打开的连接
     37             /// </summary>
     38             public List<SqlConnection> DoneConnection = new List<SqlConnection>();
     39             /// <summary>
     40             /// 出现错误的连接
     41             /// </summary>
     42             public SqlConnection CurrentConnection;
     43             /// <summary>
     44             /// 覆盖Exception中的Message字段,使其可写
     45             /// </summary>
     46             public new string Message { get; set; }
     47         }
     48 
     49         /// <summary>
     50         /// 多操作sql,使用事务,用于多库事务
     51         /// <para>
     52         /// 返回值TransInfo字段:IsSuccess 是否成功,
     53         /// Total sql总条数,
     54         /// WrongAt 失败的sql语句
     55         /// </para>
     56         /// </summary>
     57         /// <param name="sqlwithconn">执行的sql和连接字符串列表key:sql,value:连接字符串</param>
     58         /// <param name="connectionString">连接字符串</param>
     59         /// <returns>sadf</returns>
     60         public static TransInfo RunSqlInTrans(Dictionary<string, string> sqlwithconn)
     61         {
     62             var sqltable = new Dictionary<string, string>();
     63             var conntable = new Dictionary<string, SqlConnection>();
     64 
     65             foreach (var i in sqlwithconn)
     66             {
     67                 if (!sqltable.Keys.Contains(i.Value))
     68                 {
     69                     sqltable.Add(i.Value, i.Key); //sqltable的key是连接字符串,value是sql语句
     70                     conntable.Add(i.Value, new SqlConnection(i.Value));    //key是连接字符串,value是连接对象
     71                 }
     72                 else
     73                 {
     74                     sqltable[i.Value]  = ";"   i.Key;
     75                 }
     76             }
     77 
     78             try
     79             {
     80                 var wrongEx = new TransException("");
     81                 foreach (var i in sqltable)
     82                 {
     83                     //遵照晚开早关原则,在此处打开数据库连接
     84                     conntable[i.Key].Open();
     85                     //连接打开后,将连接对象放入异常处理对象中做记录
     86                     wrongEx.DoneConnection.Add(conntable[i.Key]);
     87                     var dc = new SqlCommand(string.Format(MultiTran, i.Value), conntable[i.Key]);
     88                     try
     89                     {
     90                         dc.ExecuteNonQuery();
     91                     }
     92                     catch (Exception ex)
     93                     {
     94                         //出现异常,抛出异常处理对象
     95                         wrongEx.CurrentConnection = conntable[i.Key];
     96                         wrongEx.wrongAt = i.Key;
     97                         wrongEx.wrongSQL = sqltable[i.Key];
     98                         wrongEx.Message = ex.Message;
     99                         throw wrongEx;
    100                     }
    101                 }
    102                 //全部执行完毕没有发现错误,提交事务
    103                 foreach (var i in conntable)
    104                 {
    105                     var dc = new SqlCommand("COMMIT TRAN", i.Value);
    106                     dc.ExecuteNonQuery();
    107                     i.Value.Close();
    108                 }
    109                 return new TransInfo()
    110                 {
    111                     IsSuccess = true,
    112                     Total = sqlwithconn.Count,
    113                     WrongMessage = ""
    114                 };
    115 
    116             }
    117             catch (TransException e)   //1.回滚所有操作2.关闭所有已经打开的数据库连接4.生成错误对象
    118             {
    119                 foreach (var i in e.DoneConnection)
    120                 {
    121                     if (!i.Equals(e.CurrentConnection))
    122                     {
    123                         var dc = new SqlCommand("ROLLBACK TRAN", i);
    124                         dc.ExecuteNonQuery();
    125                     }
    126                     i.Close();
    127                 }
    128                 return new TransInfo()
    129                 {
    130                     IsSuccess = false,
    131                     Total = sqlwithconn.Count,
    132                     WrongMessage = string.Format("在连接{0}中,操作{1}出现错误,错误信息:{2}", e.wrongAt, e.wrongSQL, e.Message)
    133                 };
    134             }
    135         }
    

    CAP理论

    Drizzle与mysql的差别就比较大了,并且不能兼容,如果想运行此环境,就需要重写一些代码了!

     这样解决了跨库数据表处理有时因为网络问题或其他偶然性问题导致的数据不一致的问题。但是这个解决方案最大的问题就是在于性能问题上,比如如果有多个库假设为A,B,C,D,其中C库的数据修改写入比较复杂,那么在A,B库开启事务后,必须等待C和D库完成或失败后,事务才可以结束,连接才能释放,这个时候,A库和B库就是处于挂起状态,如果处于高IO的生产环境中的话,这个性能的损失可能是致命的,所以这个方案只能用于简单的sql处理,而且处理sql不能太多或者太复杂。而且出现网络波动的话,损失会更大。幸运的是我所接手的这个业务,是在内网环境中,同时只用两句sql在两个库中,所以用这个方案问题不大。

    在分布式系统中,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition Tolerance)3 个要素最多只能同时满足两个,不可兼得。其中,分区容忍性又是不可或缺的。

     

    总结:针对这个问题,我认为当初设计数据库时,能避免跨库就一定要避免。

    一致性:分布式环境下多个节点的数据是否强一致。

    Question 2:

    如果大家有什么更好的解决方案的话,希望和大家多多交流和指教。

    可用性:分布式服务能一直保证可用状态。当用户发出一个请求后,服务能在有限时间内返回结果。

    mysql主要的存储引擎myisam和innodb的不同之处?

     

    分区容忍性:特指对网络分区的容忍性。

    1. 事务的支持不同(innodb支持事务,myisam不支持事务)

    2. 锁粒度(innodb行锁应用,myisam表锁)

    3. 存储空间(innodb既缓存索引文件又缓存数据文件,myisam只能缓存索引文件)

    4. 存储结构

      (myisam:数据文件的扩展名为.MYD myData ,索引文件的扩展名是.MYI myIndex)

    举例:Cassandra、Dynamo 等,默认优先选择AP,弱化C;HBase、MongoDB 等,默认优先选择CP,弱化A。

          (innodb:所有的表都保存在同一个数据文件里面 即为.Ibd)

    BASE 理论

       5. 统计记录行数

    核心思想:

           (myisam:保存有表的总行数,select count(*) from table;会直接取出出该值)

    基本可用(Basically Available):指分布式系统在出现故障时,允许损失部分的可用性来保证核心可用。

           (innodb:没有保存表的总行数,select count(*) from table;就会遍历整个表,消耗相当大)

    软状态(Soft State):指允许分布式系统存在中间状态,该中间状态不会影响到系统的整体可用性。

     

    最终一致性(Eventual Consistency):指分布式系统中的所有副本数据经过一定时间后,最终能够达到一致的状态。

    Question  3:

    一致性模型

    Innodb的体系结构简单介绍一下?

    数据的一致性模型可以分成以下 3 类:

    谈及到innodb的体系结构,首先要考虑mysql的体系结构,分为两部分mysql的server层和存储引擎层

    ▌强一致性:数据更新成功后,任意时刻所有副本中的数据都是一致的,一般采用同步的方式实现。

    先要跟面试官聊清楚mysql的整体方向,然后再去涉及innodb体系结构

    ▌弱一致性:数据更新成功后,系统不承诺立即可以读到最新写入的值,也不承诺具体多久之后可以读到。

    建议从三方面介绍innodb体系结构:内存----线程-----磁盘

    ▌最终一致性:弱一致性的一种形式,数据更新成功后,系统不承诺立即可以返回最新写入的值,但是保证最终会返回上一次更新操作的值。

    内存中包含insert_buffer,data_buffer,index_buffer,redo_log_buffer,double_write

    分布式系统数据的强一致性、弱一致性和最终一致性可以通过Quorum NRW算法分析。

    内存刷新到磁盘的机制,redo,脏页,binlog的刷新条件

    分布式事务解决方案

    各种线程的作用,master_thread,purge_thread,redo log thread,read thread,write thread,page cleaner thread

    1、2PC方案——强一致性

    磁盘中存放着数据文件,redo log,undo log,binlog

    2PC的核心原理是通过提交分阶段和记日志的方式,记录下事务提交所处的阶段状态,在组件宕机重启后,可通过日志恢复事务提交的阶段状态,并在这个状态节点重试,如Coordinator重启后,通过日志可以确定提交处于Prepare还是PrepareAll状态,若是前者,说明有节点可能没有Prepare成功,或所有节点Prepare成功但还没有下发Commit,状态恢复后给所有节点下发RollBack;若是PrepareAll状态,需要给所有节点下发Commit,数据库节点需要保证Commit幂等。

     

    2PC方案的问题:

    Question  4:

    ■ 同步阻塞;

    mysql有哪些索引类型:

    ■ 数据不一致;

    1. 数据结构角度上可以分:B tree索引,hash索引,fulltext索引(innodb,myisam都支持)

    2. 存储角度上可以分:聚集索引,非聚集索引

    3. 逻辑角度上可以分:primary key,normal key,单列,复合,覆盖索引

       

       

    ■ 单点问题。

     

    升级的3PC方案旨在解决这些问题,主要有两个改进

    Question  5:

    ■ 增加超时机制。

    mysql binlog有几种格式:

    ■ 两阶段之间插入准备阶段。

    1. statement

    但三阶段提交也存在一些缺陷,要彻底从协议层面避免数据不一致,可以采用Paxos或者Raft 算法。

        优点:不需要记录每一行的变化,减少了binlog日志量,节约了IO,提高性能

    2、eBay 事件队列方案——最终一致性

        缺点:当使用一些特殊函数的时候,或者跨库操作的时候容易丢失数据

    eBay 的架构师Dan Pritchett,曾在一篇解释BASE 原理的论文《Base:An Acid Alternative》中提到一个eBay 分布式系统一致性问题的解决方案。它的核心思想是将需要分布式处理的任务通过消息或者日志的方式来异步执行,消息或日志可以存到本地文件、数据库或消息队列,再通过业务规则进行失败重试,它要求各服务的接口是幂等的。

    注:在生产中不建议使用

    描述的场景为,有用户表user 和交易表transaction,用户表存储用户信息、总销售额和总购买额,交易表存储每一笔交易的流水号、买家信息、卖家信息和交易金额。如果产生了一笔交易,需要在交易表增加记录,同时还要修改用户表的金额。

    1. row

    论文中提出的解决方法是将更新交易表记录和用户表更新消息放在一个本地事务来完成,为了避免重复消费用户表更新消息带来的问题,增加一个操作记录表updates_applied来记录已经完成的交易相关的信息。

        优点:清晰记录每行的数据信息,不会出现跨库丢数据的情况

    这个方案的核心在于第二阶段的重试和幂等执行。失败后重试,这是一种补偿机制,它是能保证系统最终一致的关键流程。

        缺点:内容当记录到日志中的时候,都将以每行记录的修改来记录,但就会产生大量的binlog,对于网络开销也比较大

    3、TCC (Try-Confirm-Cancel)补偿模式——最终一致性

    注:生产中推荐使用

    某业务模型如图,由服务 A、服务B、服务C、服务D 共同组成的一个微服务架构系统。服务A 需要依次调用服务B、服务C 和服务D 共同完成一个操作。当服务A 调用服务D 失败时,若要保证整个系统数据的一致性,就要对服务B 和服务C 的invoke 操作进行回滚,执行反向的revert 操作。回滚成功后,整个微服务系统是数据一致的。

    1. mixed

    ▌实现关键要素:

        是mysql5.1的时候,一个过渡版本,DDL语句会记录成statement,DML会记录row。

    1.服务调用链必须被记录下来;

    注:生产中不建议使用

    2.每个服务提供者都需要提供一组业务逻辑相反的操作,互为补偿,同时回滚操作要保证幂等;

     

    3.必须按失败原因执行不同的回滚策略。

    Qusetion 6:

    ▌实现难点:

    mysql主从复制的具体原理是什么?

    补偿模式的特点是实现简单,但是想形成一定程度的通用方案比较困难,特别是服务链的记录,因为大部分时候,业务参数或者业务逻辑千差万别。

    主 服务器把数据更新记录到二进制日志中,从服务器通过io thread向主库发起binlog请求,主服务器通过IO dump thread把二进制日志传递给从库,从库通过io thread记录到自己的中继日志中。然后再通过sql thread应用中继日志中sql的内容。

    另外,很多业务特征使得该服务无法提供一个安全的回滚操作。

     

    4、缓存数据最终一致性

    Qusetion 7:

    在我们的业务系统中,缓存(Redis 或者Memcached)通常被用在数据库前面,作为数据读取的缓冲,使得I/O 操作不至于直接落在数据库上。以商品详情页为例,假如卖家修改了商品信息,并写回到数据库,但是这时候用户从商品详情页看到的信息还是从缓存中拿到的过时数据,这就出现了缓存系统和数据库系统中的数据不一致的现象。

    数据库中双一是什么?

    ▌要解决该场景下缓存和数据库数据不一致的问题我们有以下两种解决方案:

    sync_binlog=1

    为缓存数据设置过期时间。当缓存中数据过期后,业务系统会从数据库中获取数据,并将新值放入缓存。这个过期时间就是系统可以达到最终一致的容忍时间。

    innodb_flush_log_at_trx_commit=1

    更新数据库数据后同时清除缓存数据。数据库数据更新后,同步删除缓存中数据,使得下次对商品详情的获取直接从数据库中获取,并同步到缓存。

    innodb_flush_log_at_trx_commit和sync_binlog 两个参数是控制MySQL 磁盘写入策略以及数据安全性的关键参数

    选择建议

    innodb_flush_log_at_trx_commit设置为1,每次事务提交时MySQL都会把log buffer的数据写入log file,并且刷到磁盘中去。

    在面临数据一致性问题的时候,首先要从业务需求的角度出发,确定我们对于3 种一致性模型的接受程度,再通过具体场景来决定解决方案。

    sync_binlog =N (N>0) ,MySQL 在每写 N次 二进制日志binary log时,会使用fdatasync()函数将它的写二进制日志binary log同步到磁盘中去

    从应用角度看,分布式事务的现实场景常常无法规避,在有能力给出其他解决方案前,2PC也是一个不错的选择。

     

    对购物转账等电商和金融业务,中间件层的2PC最大问题在于业务不可见,一旦出现不可抗力或意想不到的一致性破坏,如数据节点永久性宕机,业务难以根据2PC的日志进行补偿。金融场景下,数据一致性是命根,业务需要对数据有百分之百的掌控力,建议使用TCC这类分布式事务模型,或基于消息队列的柔性事务框架,这两种方案都在业务层实现,业务开发者具有足够掌控力,可以结合SOA框架来架构,包括Dubbo、Spring Cloud等。

    Qusetion 8:

    以上由网易企业信息化服务提供商,湖南领先网络科技整理发布。

    如何监控mysql  replication复制延迟?

    网易企业服务(qiye163.co)是网易凭借其20年品牌优势与经验在企业邮箱的基础上,为进一步布局企业市场而打造的企业级产品矩阵,致力于提供一站式企业信息化解决方案。湖南领先网络科技是网易企业产品授权经销商,专业为企业提供网易企业邮箱、网易办公套件等一站式企业信息化专业解决方案。

    1. 可以通过第三方工具 业界中的瑞士军刀percona-toolkit中的命令,pt-heartbeat进行主从延迟监控。

    2. 传统方法,通过比较主从服务器之间的position号的差异值。

    3. 还可以通过查看seconds_behind_master估算一下主从延迟时间

       

     

    Qusetion  9:

    大表DDL语句,如何实施,才能把性能影响降到最低?

    1. 可以通过传统方法导入导出数据,新建一张与原表一样的表结构,把需要执行的ddl语句在无数据的新表执行,然后把老表中的数据导入到新表中,把新表改成老表的名字

    2. 通过第三方工具 业界中的瑞士军刀percona-toolkit中的命令,pt-online-schema-change进行在线操作

    3. 对于新版本的mysql(5.7)可以直接在线online ddl

     

    Qusetion  10:

    为什么要为innodb表设置自增列做主键?

    1.使用自增列做主键,写入顺序是自增的,和B 数叶子节点分裂顺序一致

    2.表不指定自增列做主键,同时也没有可以被选为主键的唯一索引,InnoDB就会选择内置的rowid作为主键,写入顺序和rowid增长顺序一致

    所以InnoDB表的数据写入顺序能和B 树索引的叶子节点顺序一致的话,这时候存取效率是最高

     

    Qusetion  11:

    如何优化一条有问题的sql语句?

    针对sql语句的优化,我们不要上来就回答添加索引,这样显得太不专业。我们可以从如下几个角度去分析

    1. 回归到表的设计层面,数据类型选择是否合理

    2. 大表碎片的整理是否完善

    3. 表的统计信息,是不是准确的

    4. 审查表的执行计划,判断字段上面有没有合适的索引

    5. 针对索引的选择性,建立合适的索引(就又涉及到大表DDL的操作问题)

     

    Qusetion  12:

    服务器负载过高或者网页打开缓慢,简单说说你的优化思路 ?

    1. 首先我们要发现问题的过程,通过操作系统,数据库,程序设计,硬件角度四个维度找到问题所在

    2. 找到瓶颈点的位置

    3. 制定好优化方案,形成处理问题的体系

    4. 体系制定好之后,在测试环境进行优化方案的测试

    5. 测试环境如果优化效果很好,再实施到生产环境

    6. 做好处理问题的记录

     

    Qusetion  13:

    接触过哪些mysql的主流架构?架构应用中有哪些问题需要考虑?

    1. M-S

    2. MHA

    3. MM keepalived

    4. PXC

    共同存在的问题:主从延迟问题的存在,在主库宕机,切换过程中要考虑数据一致性的问题,避免出现主从复制不一致

     

    Qusetion14:

    什么是死锁?锁等待?如何优化这类问题?通过数据库哪些表可以监控?

    死锁是指两个或多个事务在同一资源上互相占用,并请求加锁时,而导致的恶性循环现象。当多个事务以不同顺序试图加锁同一资源时,就会产生死锁。

    锁等待:mysql数据库中,不同session在更新同行数据中,会出现锁等待

    重要的三张锁的监控表innodb_trx,innodb_locks,innodb_lock_waits

     

    Qusetion  15:

    处理过mysql哪些案例

    我们可以简单从mysql四个知识模块跟他聊聊mysql体系结构,数据备份恢复,优化,高可用集群架构

    1. mysql版本的升级

    2. 处理mysql集群的各种坑和问题

    3. 根据公司业务类型,设计合理mysql库,表,架构。

    4. 定期进行灾备恢复演练

    5. 误删除数据之后,恢复数据

    本文由新葡亰496net发布于奥门新萄京娱乐场,转载请注明出处:新葡亰496net数据库面试葵花宝典,中跨库事务处

    关键词:

上一篇:新葡亰496netAPI函数大全,值得学习

下一篇:没有了