2

SysLog个人经验总结和分享

 2 years ago
source link: https://blogread.cn/it/article/276?f=hot1
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

SysLog个人经验总结和分享

浏览:2709次  出处信息

写这篇文章算是对我来淘宝平台架构组实习的一个总结吧。

开始接手SysLog的时候,那时候SysLog是比较粗糙的,一天只有几万条数据,显示图的曲线都是一路往上涨的,数据的值是直接累加,很难看出某个时间点的值,只能从曲线的曲率上大概判断现在是不是增长的很快。开始的时候需求很简单,毕玄只是让只是要让曲线按照每一分钟的实际值显示就行了。

还记得当时改的时候真的是一步三回头,在学校的时候哪有这种经历,自己做的东西马上要给别人用了。那次是查了又查,还是担心。虽然真的就改了一点点东西。这感觉相信每个从学校刚出来的人都会经历的:紧张,激动,兴奋&&担忧。

其实当时的结构还是比较简单直接的。数据库中一个月才一张表,就是原始数据表,那时候一个一天才几万的数据量。

实现方案

接收到客户端数据  解析直接入库

获取参数  从原始数据表取数据  处理数据  展示

这时候没学到多少技术,学到最多的是就是debug,其实就debug的步骤没什么好说的:设置断点,单步跟踪,运行到返回,运行到下一个断点…更重要的是在debug之前,造成错误结果的可能的原因在哪,先找到原因再下断点。当然肯定会有无从下手的时候,那没办法,从开始就下断点,一步步的跟踪,每一步对比跟是不是预期值,这个要是错过了一步可能就得从头再来,比较恶心。

=================================下面是历史的改进==============================

问题一:如何让用户更快速的查看历史或当前的数据?

当数据量开始增大的时候,从每天几万条增长到几十万条,程序不做优化,mysql有点开始有点吃力了。

记得某天早上,华黎师兄过来跟我说:“小伙,现在访问一个页面要10分钟才能刷出来,都不敢刷新啊。”我大囧。然后黎叔给我了一些建议,说用缓存吧,以至于我建的表名都是listCachexxx(其实就是把中间结果存起来)

优化一:对已经入库的数据定时的进行计算,将计算结果存放至另外的表中。用户请求数据直接返回计算好的结果

实现方案:

接收到agent的数据  解析直接入库

接受更新请求  取出原始数据中需要更新的数据  处理原始数据放入“缓存”表

获取参数  从“缓存”表取数据  展示数据

优化结果:请求响应的速度比原来的提高了10倍左右。这个其实不仅仅是10倍的概念,随着数据量的不断增长,已经是一个可用性的问题。

=============================================================================

问题二:一个天的数据都在一张表里,有一天某个应用的数据量猛增的话,现在的SysLog的性能跟不上,有什么办法SysLog仍然能继续运行?

处理过程多出来一步更新,请求响应的速度比原来的提高了好几倍。但是问题还是随之而来,记得是因为HC应用某一天的数据量猛增到500w+,当时更新的是把需要更新的数据从数据库一下子都取出来,内存一下子就被撑爆了@_@。

这下SysLog是完全不能查看了,一更新就内存溢出。而且因为HC的原因,导致N应用和HP等应用都不能查看数据。

优化二:按照应用,日期分表。按时间段更新,一次更新最多取出n分钟的数据,防止取出数据太多,内存溢出

技术演变:

按照应用将不同应用,不同的日期的数据写入不同的表中

更新分时间按段更新,每次更新从原始数据表中最多只会取出n分钟的数据

优化结果:不会因为一个应用的异常而导致所有的应用都不能使用,这是当时数据分表的导火索,后来证明分表的作用不仅仅是这些。

问题三:分时间分表更新,速度会比原来的程序更新的效率比较低,如何补偿?

按时间段更新,对数据库的更新操作会更多一些,效率比先前的低了。

优化三:使用线程池,利用多线程分表更新。

多线程终于出场了。在应用里自己写多线程,在学校里的时候用的不多,心里自然没什么底,只能是走一步算一步了。

不过这次的多线程是很简单的多线程运用,没有线程之间共同需要修改的资源,那这个原理上就跟每个线程System.out.println(“hello taobao”)一样了。不过到底从这是开始引入了多线程(servlet自身的多线程不算)

技术演变:

每个应用启动一个线程去更新

优化结果:多用多线程分表更新,由于应用与应用之间是没有依赖的,使用多线程后,更新速度反而比以前效率更高了

=============================================================================

终于SysLog暂时稳定了一段时间。这段时间毕玄新提了一些需求,丰富了报表的种类,SysLog提供:日趋势报表,周趋势报表,季度趋势报表,年度趋势报表,历史最高最低对比报表,同期对比报表,分机器查看报表,还有一个日趋势对表报表。

这期间没有什么技术上的变化,基本上是代码结构上的变化和功能的扩展。

值得一提的是在服务端有个变化,数据入库和原始数据的处理分为了两台机器,数据库是单独的一台服务器。在一个tomcat上的时候如果应用刚好在更新,那么查看报表会明显缓慢。分开之后,即使正在更新应用,查看报表的响应也会很快。这个虽然不是难理解的变化,但是对于我这个初出茅庐的实习生还是有一种醍醐灌顶的感觉,原来还可以这么做。

=============================================================================

问题四:数据量继续往上飙,数据入库都成了瓶颈,数据库load很高,如果降低数据库的load

在上面一段时间的安逸之后,真正的挑战渐渐来临。随着数据量的与日递增,数据库服务器的load有了不小的增长。这时候至道师兄加入进来一起优化SysLog了。

优化四:接收到请求暂时不入库,先将数据写内存。N分钟后写数据库

数据库的load变高,主要原因是数据库连接的资源不够。这时候每天的数据量已经达到了1000w了。有请求过来数据直接入库那对数据库连接的争夺必然是很厉害,优化入库就成了势在必行的任务。不过这次的入库优化,过程还是比较曲折的。

这里涉及到高并发控制同步的问题,如何更快速的响应客户端入库的请求?我选择的是ReentrantLock,其实有很多选择可以用,只是我觉得这个用起来比较爽。不过用锁的时候要搞明白lock(),tryLock()的区别。tryLock()是立即返回的,意思就是能锁就锁,不能锁就不锁(当然tryLock()还有一个定时的方法,有兴趣可以去看下)。Lock()看方法就是一根经,不等到锁就是不返回。用的时候一定要注意两者的使用环境,搞不好结果就会出乎意料之外。我的感觉是设计方案时能没有并发最好……

ConcurrentHashMap:concurrent包里提供的这个HashMap还是很实用的,所有的操作都是线程安全的,迭代的时候也不会抛出令人烦恼的ConcurrentModificationException,对我这种新手来说,已经是觉得很方便了。比普通的HashMap多出了一个putIfAbsent()方法,可以看下。

此次改变之后,在压测的时候发现有内存泄漏的问题,每次在压测一刻钟左右的时候TPS就开始慢慢减为零。检查了好久的代码,还是没有找到原因,很郁闷,当时。过了好几天才发现是没有流量控制,内存被loadrunner的数据给撑满了。不过这期间,我学到了不少关于内存泄漏的定位工具:JProfiler和JDK自带的jmap,jhat的用法(这个很强大,详情请见贴吧之大话架构http://soft.taobao.ali.com/Post/ShowTopic.aspx?t=2d8396b5-1201-4790-b0ee-145ebc28e2c3)

技术演变:

接收到请求暂时不入库,先将数据写内存。N分钟后写数据库

优化结果:n分钟一次入库请求,数据库的load明显的降低了很多。

问题五:在修改入库策略后,n分钟只有一次请求写数据库,数据入库的速率有下降的迹象,如何提高入库速度?

修改之后数据库load降下来很多,但是入库的速度成了瓶颈。原因在于n分钟才有一个连接去写数据库,比之前的多连接写肯定慢了一些。

优化五:多线程入库。使用可控数量的线程执行入库动作,每个应用分得一个线程去入库。

分表的强大的优势开始体现出来。入库任务启动时,每个应用用一个线程去写数据库。由于是按照应用分表的,各线程之间插入数据是没有锁的。效率一下子提高了狠多。

Mysql引擎:我用过的两个引擎一个是MYISAM,一个是InnoDB。SysLog数据库的效率是至关重要的环节,所以数据表引擎的选择毋庸置疑的很重要。

MYISAM特点是:不支持事务,执行效率相对比较高,对并发的支持不是很好,读写都是串行的,只有读读锁是兼容的,其他的读写锁不兼容,写写锁不兼容,不支持行锁,要锁直接锁表。

InnoDB特点是:支持事务,支持行锁,对并发支持的比较好。处理大容量的数据时性能能达到最大化,CPU的利用是最有效率的。类似于oracle的数据库

技术演变:

数据由内存写入数据库的时候,多线程入库。

优化结果:数据库入库的速度能达到3000+/秒的速度,比原先提高了有5倍左右的样子。

问题六:按照时间段更新的策略,一直有一个不是很严重的bug:更新的任务可能会漏掉其中的一些数据。

原来的更新是按当前时间作为取数据的条件:如果数据的时间在上一次更新至当前时间之间,那么认为这部分数据是新数据。这样其实有个问题,因为数据入库的延时是未知的,按照这种更新的方法可能是会漏掉一些数据。

优化六:按照原始数据的dataId来更新,保证不会丢数据。

这次修改遇到的困难,更多的是压力。因为修改了这个之后,把一个有问题的版本发上去了,发现总是会内存耗尽,导致SysLog好久不能使用。修改这里最多的还是更DBA的沟通,感谢一直被我骚扰的陶方。

Mysql的索引:只要索引的最左字段被包含在查询语句里面,就会走索引,否则是不会走索引的。例如很简单的一个建立了索引key(a,b,c),查询语句会有索引的情况只有三种,即where a = ? , where a = ? and b = ? ,where a = ? and b = ? and c = ?。其他的例如where b = ? and c = ? 是不会走索引的。

还有一个平时看起来没什么用,但是出问题的时候很有用的技巧:打好日志。线上的应用出了问题,不可能给debug的机会。开始总是内存耗尽的状况,我线下怎么也压不出来,后来经毕玄师兄提醒,才通过打日志发现了问题。只打有用的日志,是建立在对程序理解很深刻的情况下。第一次发现打日志的重要性,不仅是手段也是技术……

实现方案:

按照原始数据的dataId来更新,保证不会丢数据。

优化结果:这次更新优化后,线下测试的效率比修改之前提高了4倍,但是线上超大的数据量的更新还是不进理想的,尤其是key很多的应用,更新的速度还是比较缓慢的。如何更高效的更新,仍旧需要继续思考

问题七:入库的速度按照DBA的说法一张表可以压到1w/秒,为什么我的只有2k -3k?

优化七:一条sql插入多个值。

继续的插入优化,插入经过上次的优化之后,又开始了下一轮的优化。这次着重在如何提高数据库的写入速度。开始我们为了加快插入速度,使用的是iBATIS的批量提交,从理论上讲应该会比一条条的插入快,因该是常识吧。但是这次事实上告诉我,仅仅是把批量提交去掉就已经提高了3倍多,更牛B的在后面。

陶方建议一个sql插入多个值,形如insert into tableName (x,xx,xxx) values(x,xx,xxx),(xx,xxx,xxxx)…,经过这样修改之后,在我看来,速度已经很疯狂了.

优化结果:线上曾经粗略的跟踪过入库速度:可以达到70000w/,捕捉到的可能不是最高峰。这种速度对线上的现在的压力足够支撑了.

( http://dev.mysql.com/doc/refman/5.0/en/insert-speed.html这个文档讲如何提高mysql的插入速度,很不错)

SysLog其实还有很多地方可以优化:如何支撑应用的水平扩展?如何提高更新的计算速度?期待全网监控小组能把SysLog做的更好。

=======================================特别感谢===============================

华黎,毕玄,至道,天狐,平台架构的师兄们,给我传授知识.让我眼界大开

还要特别感谢不厌其烦被我骚扰的DBA:陶方.

=======================================全篇终=================================

建议继续学习:

QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK