最近公司要求对公共平台的接口,进行监控。对于用户敏感信息、用户登录信息,以及用户其他的附属信息的访问,做实时统计,例如敏感信息,按每小时统计访问了多少用户的敏感信息;ip访问敏感信息量TopN排行等。
数据来源于项目打印的debug日志,这些日志是由核心框架打印的标准日志,其中大概包含了原始ip,当前用户id与类型,访问接口的客户端,访问时间,接口入参等信息。
日志采用flume收集,并放入kafka中。
我们的系统接入kafka,消息日志数据。
刚开始定方案时,是将kafka中的数据直接放入MySQL数据库中,由于日志量大,对不同业务日志,做不同的分表处理,有的按天分表,有的按小时分表。
当系统上线时,数据库的写瓶颈就表现出来了。由于数据库是单点的,因此所有的写压力都集中在一个点上。首先暴露的问题是表锁。即日志消费线程在写数据的同时,统计线程还做了一些校正数据的事情,这导致在相同表上的竞争。我们的解决方案是,把需要校正的这些数据,单拎出来放到另一个表中,这样,就只有日志消费线程在插入数据库。
之后又遇到问题,有个业务日志量特别大(正常非高峰期,每小时数据量在1.4G/18,000,000),由于数据量特别大,导致写线程相对于日志有较大的延迟,而且越拉越大。通过检查发现,写入数据库速度跟不上,我们首先尝试,先停止统计线程去查数据,只写,但速度还是不行。接着,我们把该表的唯一一个索引去掉,结果速度马上就上来了,由于没有了索引,就得全表查,因此分表不能再是一天一张表,改为一小时一张表。
数据库写性能上来以后,有一个更大的问题出现了,数据库所在的服务器,硬件能支持的IOPS大概为500ps左右,而我们大概的峰值竟然达到15k,大大超出了硬盘的吞吐,直接导致MySQL卡死宕机(具体是硬件的限制还是MySQL自身原因导致服务宕机未知)。MySQL卡死不仅仅因为写的量太大,还在于对这么大的表进行复杂的sum、count、group查询导致的锁表和内存开销。我们的数据库是主从复制的,那为什么统计是在主库而没有去从库呢?因为这样大批量数据的写入,从库的同步延时将变得非常大,我们当时看的延时是一天,这主要是因为主库的插入是多线程并行的,而从库是根据主库的日志,串行进行的。
总之,由于MySQL在分布式方面的弱点,导致它不合适于做大批量数据插入的场景。