mysql数据安全

    技术2022-07-10  105

    mysql在保障数据安全 方面,提供了很多可配置的功能和特性,正确的使用这些功能和特性,是保障数据安全的根本。

    单机安全

    从单实例的角度来看数据落盘的安全要考虑mysql实例进程挂掉和mysql实例所在的操作系统挂掉的情况,类似于其他关系型数据库,mysql提供了undo log和redo log来保证数据库非正常重启后数据恢复的机制,同时mysql采用了热油的double write机制来保证写入磁盘数据的完整性和正确性,double write可以采用参数innodb_doublewrite来控制,而且日志刷盘的策略,有个非常重要的参数叫innodb_flush_log_at_trx_commit,这个参数取值的不同决定了日志刷盘策略的不同,也决定了mysql提供的数据安全级别的不同。

    集群安全

    在任何时候,都可能会出现数据库服务器硬件或操作系统故障,继而导致无锡服务器无法启动,操作系统不能正常加载,或者是mysql进程无法启动的情况,这时候,要保障mysql的数据库安全,需要借助mysql集群部署,并根据mysql的特性正确配置,在使用mysql集群的过程中,又有两种截然不同的处理思路。

    *使用mysql原生的replication来搭建基于master-slave脱坡结构的异步mysql集群,mysql开发者很早就意思到数据库复制的重要性,2000年左右就已经开始支持replication,随着mysql功能的不断健全,mysql对replication支持也越来越完善,binlog的存储优化及可控的刷盘策略,replication信息存储,半同步机制,多线程复制技术,多源复制技术等,最终都优化了mysql集群的搭建,为mysql数据安全提供了保障。

    备份安全

    如果碰到了极端的情况,我们提供线上服务的mysql主库宕机,同时这个集群的其他从库也不可用,那么,如果要保障数据安全,唯一可以依赖的就是数据库的备份了,正确及时有效的数据库备份时必不可少的,mysql是在生产中久经验证的,其支持备份的各种工具和方案也是层出不穷,比较流行的mysql备份工具由percona出品的percona xtrabackup,大厂一般用NBU备份恢复。

    mysql实例安全保证

    在mysql内部,有很多机制来保证数据库自身的数据安全,主要关注innodb引擎,从innodb管理机制原理说起,逐步深入,并且结合mysql的各种参数组合对数据库安全方面的影响。

     

    double write

    保证了数据页的正确性,虽然开启了double write之后,每个页面都写了两遍,这对数据库性能有一定的影响,但是由于所写的页面都缓存到内存中,每一部分的缓存空间慢了之后才真正写入到文件中,而且两次写入时将若干数量的页面组合起来形成连续的空间入到两次写的空间中,这样就形成了顺序写,对于磁盘来说,顺序写消耗的性能比较低,实际上经过测试,两次写使性能降低了10%左右,但是对于SSD来说,两次写已经不是问题,如果不开启此参数,可能导致页面写失败,那么mysql在宕机时可能导致数据库无法启动,丢失数据。

    REDO LOG

    REDO LOG是用来做数据库 crash recovery的,这时保证数据库安全非常重要的功能之一,redo日志记录了所有对innodb数据库的修改操作,在innodb存储引擎中,一般默认有两个日志文件,数据库创建之后,会自动新建两个名为ib_logfile0,ib_logfile1的文件,如果整两个文件不存在,innodb在启动的过程中,会根据配置的参数或默认值,重新创建redo log。

    REDO LOG刷盘机制

    当提交事务时,可以通过参数innodb_flush_log_at_trx_commit来控制REDO LOG写入的机制,参数不同,产生的行为不同。

    -innodb_flush_log_at_trx_commit=0:当事物提交时,mysql不会处理日志缓存区的内容,也不会去处理日志文件的刷盘操作,由mysql的后台master线程每个1秒将缓存区的文件刷新到日志文件中。

    -innodb_flush_log_at_trx_commit=1;事务提交时,会将日志缓冲区的日志写入到文件中,同时会刷新到磁盘中,保证数据库事务完全不会丢失。这种设置影响数据库性能。

    -innodb_flush_log_at_trx_commit=2:事务提交时,会将日志缓存区日志写入到文件中,但是不会刷新到磁盘中。由mysql后台master线程每隔1秒将系统缓存的日志文件刷新到磁盘中。

    宕机与innodb_flush_log_at_trx_commit的关系

    数据库宕机主要有以下两种情况。

    -数据库宕机,但数据库所在的服务器还在正常运行。

    -数据库所在的服务器宕机。

    关于数据丢失,涉及几个问题。在宕机发生时,已经提交完成的数据库修改,能否保住REDO日志真正写入到磁盘上,如果不能,就被认为是数据丢失;在宕机恢复后,提交的数据库修改是否还存在,如果不存在,则认为是数据丢失;如果事物提交了,但提交失败了,最终相关修改没有生效,这样的情况,就不能认为是数据丢失了,接下来以数据丢失量为主线,秒速宕机方式与参数配置之间的关系。

    -1,数据库宕机,服务器系统是正常运行。

         innodb_flush_log_at_trx_commit=0:由于事务提交时不刷新日志缓存区,即使事务已经提交成功了,缓冲区的日志也会全部丢失,所以最新的数据修改也都会丢失,master线程每秒刷新一次,所以一般只丢失最近1秒的事务。innodb_flush_log_at_trx_commit=1:如果数据库宕机,由于每次事务提交都会刷新到磁盘中,所以数据不会有任何丢失。innodb_flush_log_at_trx_commit=2:如果数据库宕机由于数据已经刷新到OS cache中,然而服务器系统并没有出现问题,这样日志还会被刷新到磁盘中,那么数据就不会丢失。

    -2,数据库所在服务器宕机

    innodb_flush_log_at_trx_commit=0:由于事务提交时,不刷新日志缓存区,即使事务已经提交成功了,缓存区的日志也会全部丢失,所以最新的数据修改也会丢失,master线程每秒刷新一次,所以最多丢失1秒的事物,这种情况与数据库宕机是一样的道理,有相同的影响。innodb_flush_log_at_trx_commit=1:由于每次事务都会刷新到磁盘文件中,所以即使是服务器宕机,数据页不会有任何丢失。innodb_flush_log_at_trx_commit=2:由于事务只是刷新到OS cache中,如果服务器系统出现问题,导致宕机,那么日志就没有被刷新到磁盘中,就会丢失最近1秒的数据。

    innodb_flush_log_at_trx_commit各参数值,宕机方式与数据丢失之间的关系,总结如下:

    innodb_flush_log_at_trx_commit数据库宕机OS宕机0丢失最多1秒数据丢失最多一秒数据1不丢数据不丢数据2不丢数据丢失最多一秒数据

     

    MYSQL及去吗安全保证

    一般在生产环境下,很少有MYSQL单实例支撑业务的情况,大部分的mysql应用都是采用搭建集群的方法,搭建mysql集群,进行数据层面的读写分离,负载均衡或数据备份。而mysql集群在本质上可以分为两类,一类是依赖mysql replication的传统集群,另一类是依赖插件的真正的mysql集群化解决方案。

    传统的主从模式如何保证数据库安全

    基于mysql原生的replication是最常见的保证数据库安全的机制,在数据库宕机后,其他节点还能快速提供服务,并且保证数据库的数据不丢失,那么如何保障数据库安全呢?在主从模式中又有哪些参数影响数据库的数据安全?从参数的配置方面来描述主从模式时如何保障数据安全的。主要通过参数sync_binlog,主从复制相关参数(master_inf_repository,relay_log_info_repository,relog_recovery等)来叙述主从复制保证数据库安全的方式。

    sync_binlog

    binlog是用于保存数据库修改的日志信息,传统的主从复制是基于binlog的,binlog的安全直接关系到主从复制的安全,而binlog的写入方式主要由参数sync_binlog来控制,参数值决定了其行为方式,主要参数值如下。

    -sync_binlog=0:事务提交时,mysql将binlog信息写入binlog文件(os cache)中,但是mysql不控制binlog的刷磁盘操作,由文件系统自己控制其缓存的刷新,这时最危险的,一旦操作系统宕机,在binlog cache中所有的binlog都会丢失,如果只是数据库宕机,而操作系统未宕机,那么数据库锁生成的binlog丢不会丢失。

    -sync_binlog=1:每一个事务提交时,mysql都会把binlog刷新到磁盘中,这样数据库的安全最高,但是性能损耗也是最大的,如果这样设置的话,数据库或者操作系统宕机的情况下,二进制日志中缺少的任何事务也只能处于准备阶段,那么导致服务器自动恢复时,会回滚这些事务,保证无数据丢失,虽然binlog是顺序IO,但是多个事务同时提交,同样会对mysql和IO的性能带来很大影响,不过mysql可以通过group commit来缓解这种压力。

    -sync_binlog=N:表示没N此事务提交,mysql调用文件系统的刷新操作将缓存刷新到磁盘中,如果数据库或操作系统在这个时候宕机,数据库可能会丢失一些事务。

    两阶段提交

    mysql开启binlog后,所有的事务都会产生binlog event,这些event会被看成事务数据的一部分,因此要保证事务的binlog event和innodb引擎中的数据一致性,所以mysql宕机重启后要保证如下四点。

    所有已提交的事务的数据仍然存在。所有没有提交的事务自动回滚。所有已经提交事务的binlogevent也仍然存在。所有未提交事务没有记录binlog event。

    如果数据库重启数据还在,但是binlog event没有了,就没有办法把这部分数据复制到其他节点上,如果重启后数据没有了,但是binlog event还在,那么不存在的数据就会复制到其他节点上,这都会导致主从数据不一致的情况,为了保证binlog的宕机安全,mysql内部使用了两阶段提交。

    mysql在开启binlog后,mysql内部会自动将普通事务当做一个XA事务来处理,在提交事务的过程中,mysql会自动为每个事务分配一个唯一的ID(XID),XID会被记录到binlog和innodb redo log中。事务在提交时会自动被分成prepare和commit两个阶段。

    prepare界断面:告诉innodb引擎做prepare,innodb更改事务状态,并将redo log刷入磁盘。commit阶段:举例binlog日志,然后告诉innodb引擎commit。

    在数据库宕机重启后,事务可能处于4种状态。

    innodb引擎已经提交。根据两阶段提交可知,binlog中一定记录了该事务的events,所有事务是一致的,无需处理。

    在innodb中已经完成了prepare阶段,binlog中已经有该事务的events,但是innodb引擎未提交,需要通知innodb引擎提交这些事务。

    在innodb中已经完成了prepare阶段,binlog中没有该事务的events,因为binlog没有记录,需要通知innodb回滚这些事务。

    innodb还未完成prepare阶段,根据两阶段的过程,binlog也没有该事务的events,需要通知innodb回滚这些事务。

    innodb_support_xa参数

    默认情况下,innodb_support_xa是开启的,如果将该参数关闭,事务提交可以以不同的顺序写入binlog,如果宕机恢复或从库应用这些binlog,就可能导致数据的不同,这时非常不安全的,建议在线上环境或主库中开启。innodb_support_xa在5.7.10中已经废除,并且将在未来的mysql版本中删除,这是因为在5.7.10中innodb支持XA事务中始终启用两阶段提交,所以已经没有必要再用这个参数了。

    主从复制参数的影响

    在replication的配置中,有一些参数会影响主从复制的行为,这些行为的配置会影响复制的数据一致性问题,进而影响到集群的数据安全。

    binlog_format

    binlog——format主要有三种格式:STATEMENT,ROW,MIXED.

     

    说说不同binlog格式与复制之间的关系。

    binlog_format=STATEMENT:MASTER写入执行的SQL语句到binlog中,从库读取这些SQL语句并且执行,这种基于语句的复制(SBR)是mysql最早支持的形式。

    局域STATEMENT格式的复制存在一些优势,如下

    -技术成熟

    -减少了binlog的写入量。

    -binlog包含了所有的修改语句,便于审计。

    但是也存在很多缺点如下。

    -基于STATEMENT的复制是不安去的,有些函数不能正确地在SLAV上复制。

    -基于ROW格式的复制吓你,insert...select需要更多的锁。

    -隔离级别必须要设置为RR,这是发生死锁的元凶之一。

    binlog_format=MIXED:将master的binlog_format配置成痛死使用STATEMENT和ROW两者的组合格式,它记录日志取决于修改的类型,选择最合适的格式来记录该修改,默认情况下,使用STATEMENT格式记录日志,在特定情况下装换为ROW格式。

    binlog_format=ROW:5.7.7版本之后,把binlog_format的默认值修改为ROW,master将修改的event写入binlog中,并且master将binlog信息发送到slave,slave重放binlog中的event,基于ROW格式(RBR)复制是最安全的复制,slave需要的行锁更少,但是也有一些缺点,基于ROW格式的复制,binlog会记录更多的数据,并且无法在slave上看从到master获取的语句,因为都是event,但是在row格式下,可以开启binlog_rows_query_log_events参数,这回让binlog在记录events的同时,也记录下原始的SQL语句,以方便后续的查询或审计。

    master_info_repository与sync_master_info

    master_info_repository有两个值,分别是FILE和TABLE,该参数决定了SLAVE记录MASTER的状态,如果参数是FILE,就会创建master.info文件,如果参数是TABLE,就在mysql库中创建slave_master_info的表。如果使用多源复制,将该参数设置为TABLE。

    sync_master_info参数决定slave刷新master的状态的方式,并且master_info_repository参数不同,刷新方式也不同。

    如果master_info_repository=FILE,sync_master_info=N,其中N>0,那么SLAVE就会在N个事件后,使用fdarasysnc()方式同步MASTER状态信息到maaster.info文件中。如果sync_master_info=N,其中N=0,那么MYSQL智慧将状态信息写入到OS cache中,需要等待操作系统同步。如果master_info_repository==TABLE,sync_master_info=N,如果N>0,那么SLAVE就会在每N个事件后,更新mysql,slave_master_info表,如果N=0,那么mysql.slave_master_info表将永远不会更新。

     

    relay_log_info_repository与sync_relay_log_info

    其中relay_log_info_repository用来决定SLAVE同步的位置信息记录到哪里,同样有两个参数。如果relay_log_info_repository=FILE,就会创建一个relay-log.info;如果relay_log_info_repository=TABLE,就会创建mysql.slave_relay_log_info表用来记录同步的位置信息。如果使用多源复制,请将该参数设置为TABLE。

    sync_relay_log_info参数用来控制SLAVE同步位置的刷新方式,受到relay_log_info_repository参数影响。

    relay_log_info_repository=FILE,sync_relay_log_info=N,如果N>0,SLAVE在N个事务之后使用fdatasync()方式将relay-log.info文件同步到磁盘中。如果N=0,mysql并不会同步relay-log.info文件到磁盘,而是让操作系统决定。relay_log_info_repository=TABLE,如果该表是支持事务的表,那么SLAVE 在每次事务之后,都会更新该表,忽略relay-log.info参数,如果该表是非事务表,sync_relay_log_info=N,当N>0,则SLAVE会在N个event后更新该表,当N=0时,则该表永远不会更新。

    sync_relay_log_info

    该参数默认是开启的,在数据库启动后立即自动relay log恢复,在恢复的过程中,创建一个新的relay log文件,将SQL线程的位置初始化到新的relay log,并将I/O线程初始化到SQL线程的位置。

    mysql在运行的过程中,从库可能会出现意味宕机的情况,那么在从库启动后,必须能够恢复到停止前的状态,I/O线程必须恢复到已经接受事务的位置,SQL线程必须恢复到已经执行事务的位置,该信息传统上是存储在文件中,那么久有可能存在不一致或损坏的风险。从mysql5.7开始,可以使用表来存储这些信息。可以配置参数master_info_repository=TABLE和relay_log_info_repository=TABLE使从库信息存储在表中,从库如何从宕机的状态恢复到正确的状态,取决于从库是单线程还是多线程,relay_log_recover参数的值,以及master_auto_position的使用方式。

    1.单线程的复制(5.7)

    当GTID模式复制的首,并且设置了master_auto_position参数和relay_log_recovery=0,使用该参数,其relay_log_info_repository和其他变量的设置都不会影响恢复。当机遇传统模式(基于file position)复制的情况下,请设置relay_log_recovery=1和relay_log_info_repository=TABLE.

    2.多线程模式的复制(5.7)

    当机遇GTID模式复制的时候,并且设置了master_quto_position和relay_log_recovery=0,使用该配置,其relay_log_info_repository和其他变量的设置都不会影响恢复。当基于传统模式复制的时候,请设置relay_log_recovery=1,sync_relay_log=1和relay_log_info_pository=TABLE.

    Semi_Sync Replication方式的复制

    基于传统复制,可能存在主从复制延迟的问题,那么当master宕机后,slave可能处于落后的状态,如果这时master无法恢复,只能使用slave来代替master,就会导致数据丢失。在mysql中可以通过办同步复制来解决部分问题。

    rpl_semi_sync_master_wait_point在mysql的版同步复制中,控制mysql在哪个阶段等待来自slave的ACK确认,在5.7中该参数主要有两个值,:AFER_COMMIT和AFTER_SYNC(默认)。

    rpl_semi_sync_master_wait_point=AFTER_COMMIT:master将自己的binlog写入到binlog文件并且sync,且向存储引擎提交事务,然后一直等待ACK。当至少一个slave接收到binlog后,写入relay-log并返回ACK确认信息,master在接收到从库ACK确认信息之后,master将结果返回客户端。rpl_semi_sync_master_wait_point=AFTER_SYNC(5.7新增):master将自己的binlog写入到binlog文件并且sync,之后会进入等待ACK。当至少一个slave接收到binlog后,写入relay-log并返回ACK确认信息,master在接收到从库ACK确认信息之后,master向存储引擎提交事务,最终返回客户端。 AFTER_COMMIT:在该模式下,每次提交一个事务后(包括存储引擎的提交),等待从节点ACK,所以MASTER上的其他session是可以看到这个提交的事务的,如果在等待ACK的过程中MASTER挂了,但此时SLAVE可能根本没有接受到相应的binlog,如果master永远也启动不了了,那么实际上master已经提交成功的事物在slave上便不会找到了,也就意味着数据丢失了。AFTER_SYNC:在该模式下,事务在引擎层提交之前,等待slave的ACK确认,如果这个时候master宕机了,那么slave可能已经接受到binlog并且已经应用,如果master永远也启动不了,那么这个事物在master上是不成功的,这时slave就会多出这部分数据,可能导致问题,但是在AFTER_SYNC中,可以保证的是在MASTER上commit成功的事物一定会同步到slave上,确保数据不丢失。

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Processed: 0.017, SQL: 12