跑男灵异事件本文主要介绍兴业数金云数据库设计、优化、及运维实践,如何利用云数据库为企业创建核心价值,如何在云时代面对海量 MySQL、Oracle、Informix 服务的运维挑战。
林春,兴业数金首席DBA,曾任 Oracle WDP OCM ,给花旗总行、上海中行、光大总行、兴业总行提供过高质量的数据库培训。目前在兴业数金负责数据库管理工作;擅长 Oracle、DB2、Informix、MySQL 数据库性能调优、数据库迁移、数据库备份恢复。
兴业数金由兴业银行成立(占资51%),注册资本5亿。兴业数据主要有两项业务:持续研究和完善升级银银科技输出业务;把兴业银行集团的业务创新、管理思想和信息系统为可以输出的服务能力,与中小银行分享。
非银云:主要面向财务公司和金融租赁公司,提供财务公司核心业务系统云服务和金融租赁公司核心业务系统云服务;
兴业数金是金融行业最大的核心系统托管服务商,包括400项全方位的金融行业云服务,服务对象有城商行17家,村镇银行332家,民营银行7家,外资银行2家,其中213家已经上线个省。
兴业数金还在科技信息领域获得多项殊荣,包括各种权威的认证、知识产权等,同时获得监管和社会的高度认可,Gartner在2017年1月研究报告称:“兴业数据依托兴业银行,已经开展多年的金融行业云服务,是中国银行行业云服务的领导者。”
目前兴业数金在传统金融云方面的数据库主要是Informax,互联网金融云主要是基于云平台架构的MySQL数据库。不同可用域之间的资源相互隔离,应用和数据库可以部署在不同的可用域上,MySQL的数据库可以跨可用域基于高可用平台做半同步主从复制。高可用的组件可以对MySQL数据库的高可用做,在发生故障的时候可以自动提供从主存库到备库的切换。可以规避故障,对主从库之间的日志延迟以及最大连接数等做。
第二种情况就是,由于主库上数据量特别大,导致主库上大的DML操作产生大量日志,需要通过分库分表操作来进行应用优化、或者业务系统优化,对主库数据需要做清理。MySQL数据库是轻量级的数据库,一般来讲,单节点数据量不要超过1个T,否则就要考虑分库。例如:我们托管的一套合作行的消费信贷多渠道业务系统,数据量2T以上,一个实例,一套数据库,不同渠道通过表名yewu1_ 、yewu2_ 类似区分,跑批批量延迟超过万秒。定位到DML操作产生最大的三张表,用mydumper工具导出,对业务进行了优化,将监管报送功能分离到大数据平台解决了这个问题。
第三种情况是,在做DML操作的时候,假如索引建的不合适,也会额外的产生日志。所以要筛选出不必要的索引,对它做清理,降低日志的影响。在MySQL里面,咱们可以筛选出重复的日志;在Oracle里面,传统是打开所有的,查看在一段时间之内没用到的索引,可以把它清理掉。除此之外,还有一个更轻更小开销的方式,可以访问v$segment_statistics视图,如果很长一段时间之内,索引从来没被使用过,这个可以作为清理索引候选的目标。同样的思在informax和DB2里面也适用。另外还需要考虑存储的性能和网络传输的性能,都有可能会引发瓶颈。
MySQL数据库是一个轻量级的数据库,它的服务非常标准也非常适合云化,契合度非常高。兴业数金采用的高可用管理的平台非常成熟可靠,数据库服务也非常方便,可以提供给用户。
数据库的管理主要是在云内实现,实现了HA的切换、备份、等等。指标也是经过精心的设置,我们在实践过程当中发现效果非常好。这样就解决了传统数据库运维当中60%到80%的工作量。
对于客户来讲,精力主要在SQL的开发,对于不熟悉MySQL的客户可以提供快速的上线服务。在这里面切换的时候需要注意的是,假如由于主库的问题,比如说最大连接数达到max_connection,平台没法访问主库,这个时候就需要访问备库,它需要切换到备库上去。需要注意的是,我们可以直接切换到从库,而不是把故障主库关闭掉。在实际生产当中的高可用平台上,假如主库故障,关闭主库耗费时间比较长,大致在30秒左右。我们可以先直接切换到从库,再手工把主库做一个处理,这样可以把主从库切换时间从大致43秒左右切换到秒级别。
MySQL天生适用于云的架构,非常适用于横向的扩展。我们可以很方便实现读写分离。在主库写,在从库上读。但是需要注意,在从库上读的时候,它不能满足读写强一致性的需求,因为在备库上读到的数据不能满足这个事务。所以有读写强制性需求的时候,这些读可以放在主库。这些就需要业务人员根据特点,做相应的。
此外分库分表,一般来讲都是通过应用层面实现或者中间件实现,这个需要人力的调研,没办法做云服务的标准化。
兴业数金服务的企业比较多,核心系统主要是informax,还有大量Oracle数据库。此外互联网金融有很多MySQL数据库,客户还有一些DB2数据库,我们也提供支持。这对于运维来讲其实要求非常高,所以我们每种数据库都选了几个场景来做。
Oracle相比其他数据库来讲最好的是什么?我认为它的时间模型做得最好。在Oracle9i,的时候它就引入了一个统计信息叫DB time。一般来讲,银行传统的架构一般是三层的架构,当发生问题的时候,可以快速地定位到这个问题是在数据库层面,而不是在网络层面或者在应用服务器层面。Oracle数据库引入的DB time指标对我们调优服务其实非常重要。DB time实际上是服务器进程消耗的cpu加上非空闲等待的时间,假如我们这里可以把数据库比作饭店,有四个cpu,相当于这个饭店里面有四个服务员。一个小时内,四个服务员可以给多少客人提供服务?他们服务的时间,大致就是60分钟再乘以四,再稍微小一点,因为后台进程也要消耗少量的cpu。假如这个饭店有四个服务员,一下子涌进8个顾客,这个时候同时能给几个顾客提供服务?很明显只能给4个顾客提供服务,还有4个顾客在等待状态,这就叫做非空闲等待。
所以,假如系统非空闲等待越长,系统遇到的瓶颈就越严重。我们可以拿DBtime除以elapsed time,就可以得到一个黄金般的指标,这个叫平均活动会话数。可以利用这个指数快速定位数据库层面是否存在瓶颈,假如平均活动会线之间,数据库层面就不存在瓶颈;假如它介于1到CPU个数之间,这个系统还有可用资源,但是不排除单个CPU跑一个SQL百分百跑满;假如我们的平均活动会话数大于cpu的个数,这时系统一定遇到瓶颈了。这个值越大,瓶颈就越厉害。这样可以帮助我们快速地定位问题是否出现在数据库层面。
图中的DBtime除以elpased time大致三点几,数值说明比较高,也就是说数据库层面确实是遇到了故障。
还有另外一个问题是,用户给你反馈的时间不一定是故障真正发生的时间。用户感到不正常,这个时候可能故障已经发生了,反馈给应用人员的时间有滞后,应用人员反馈的时间又滞后。所以当我们碰到故障的时候,非常有必要定位到故障发生的精确时间。这里举一个例子,像Oracle里有一个ash缓存,保存了活动会话的历史,我们可以通过v$active_session_history。这里为什么用dba_his_active_sess_history呢?用户反馈的故障问题,其实超过了4天,那会话历史就会放到dba_hist_active_sess_history。这个时候我们按照系统时间做一个group by分组操作,可以得到每次它的平均活动会话数,这个是一个非常好的指标。非常适合把这个指标加在系统里面,假如平均活动会话数一下子飚上去了,数据库就一定是遇到了瓶颈,这个时候就要去进行分析。
从图中看,顾客反映时间是9:30到45分之间,我们根据这个做了一个活动会话,做了汇集以后,发现实际上故障发生时间在9:30到33分之间。
在三分钟时间内对等待事件做个聚合,会发现最主要的事件是log file sync,这是什么事件?应用在做了提交或者回滚的时候,把日志从log buffer写到日志文件里面,这时候就会产生这种事件,产生这种事件有哪几种可能性?
第二种可能性:由于配了data guard,主备之间采用了sync的同步方式,但是网络性能也比较差或者磁盘性能也比较差,对主库有拖累;
第四种可能性:数据库所在存储链性能存在瓶颈,由于磁盘性能差造成的log file sync事件时间比较长。另外log file sync平均等待时间也会比较长,在这个事件排在前面的时候,最主要关注的指标是它平均等待的时间。一般来讲,等待时间在1到2毫秒之内。
此外,用发生问题时间段awr报告跟正常时间awr报告可以做个比对。Oracle提供这样的功能,以一个正常时间段的awr报告跟问题时间段的awr报告,拼成了一个很方便的报告,可以看出异常时间段跟正常时间段的指标差多少。因为有些指标高,可能有问题,但是也可能是正常。假如在之前,一直都是正常,但是在发生问题的时候有些指标异常,那往往就是我们需要关注的对象。这个可以用Oracle自带的awrddprt脚本生成这样的报告,拿正常时间段跟异常时间段做个比对,比对以后可以一目了然地发现在异常时间段,log file sync时间大致在159毫秒,正常时间段它是九毫秒,正常时间段数据库所在存储性能也不是特别好。
Oracle的DBMS_RESOURCE_MANAGER包提供了检测存储io性能功能,它是基于数据库层面,相对更加准确,这个包里面有个叫CALIBRATE_IO的存储过程。它可以帮助我们在延迟10毫秒的情况下算出它最大的IOPS和最大的bps。我们可以通过这个数据快速定位是存储的链造成的问题,之后对它相应的存储做一个优化,来解决这个问题。所以在发生问题的时候,快速定位常重要的。
informix在很多银行、保险和其他行业里面的很多重要的业务系统方面去用。因为数据库核心要是迁移的话,工作量还常大的,特别对存储过程或很多业务逻辑的。
图中是某个业务系统的阻塞,这个磁盘繁忙率达到百分之百。这里,其实是对Oracle、informix、MySQL都做了。在此脚本里面调用了onstat -g wai、onstat –u、onstat -g sql几条命令做了组合,把条件等待排除掉,这样可以迅速抓取等待的SQL。抓取发现是一条打印往来帐报表的SQL,这个消耗了大量的IO资源。定位到问题以后,相应地对它做一个优化,建立索引,把它单条SQL从原来执行670秒,优化以后执行时间不到一秒钟。左边是优化前消耗的io,右边是优化以后消耗的io,可以看到优化效果常明显的。onstat这个命令在informix里面非常强大,在IBM收购了informix以后,db2pd工具带有onstat工具的影子。
以上几点中,在碰到问题时最重要的是第七点:了解系统投产后查询返回多少数据量。在测试,通常在数据量很少的时候,选择一个很低效的经营计划,跑得飞快。但生产以后,随着数据量的增加,特别是中间又采用了几张表的关联以后,会产生成倍放大的效率,所以这个时候常常会产生性能的问题。
DB2从10开始可以支持函数索引,它其实有个非常漂亮的用法,就是在建索引的时候可以用case语句,当然在Oracle里面也可以用case语句。
这里我列出了一个场景,生产历史数据表包括上一条数据,P状态的有几亿条,D状态的几千万条,V状态几百万条,查询status=v的记录。正常情况下建这个索引,几亿条数据大致需要四层,而且索引量占非常庞大的一个空间。现在我可以只建立状态为V的索引,建索引的时候可以加case语句,对它做判断,当status等于V的时候,就把它记录到索引里面,否则就丢弃,这个时候就不会把记录记入到索引里面,这样可以节省索引大量存储空间,而且索引层高可以从四层变成三层。
在使用以上方法优化的时候需要注意,因为它是一种函数索引,我们写SQL语句的时候,你也必须要把status=v这个结构包进去,跟函数索引一模一样,不然就用不上这个函数索引。
MySQL方面,InnoDB表必须有主键或唯一索引,避免大的事务。曾经我们有个合作银行,cpu耗的特别厉害,后来发现一张有12条记录,频繁的插入。它有12个sequence的需求,结果把它变成了一张表,插入记录,而且自己去做。这样很难它逻辑的一致性。在这里把这个字段定义成auto_increment自增长就可以,我们要尽量用到数据库里面内建的功能。
这里还有一个案例,有一条SQL开发效率很低,大概400秒。在配置相似的情况下,另一个执行特别快。经过检查,实际上发现没有锁等待。后面发现原因是应用开发人员曾经为了满足某个测试,把操作系统时间从2018改成2020,之后又调回2018。MySQL数据库的信息依赖于操作系统信息,所以这个时候,统计信息收到的信息就是2020年的统计信息状态,当时间回调的时候,统计信息还是错误的,导致算基数产生了很大的偏差。所以在操作系统改时间的时候,需要注意对数据库的影响。发现问题之后,我们把它改成了正确的信息,又重新手工收集统计信息,最后使执行的时间从400秒下降不到1秒钟。英国留学办理申根https://www.liuxue.com/lxnews/03074I2365/!