随着中国民生银行的IT业务系统的迅速发展,主机、设备、系统、应用软件数量不断增多,业务资源访问、操作量不断增加,对于应用整体系统智能分析与处理的要求不断提高,在解决分布式大数据搜索、日志挖掘和可视化的过程中,需要考虑实现一套完整并适用于民生银行的日志文件智能分析与处理的解决方案。基于此天眼实时智能日志管理分析平台应运而生,通过日志的收集、传输、储存,对海量系统日志进行集中管理和实时搜索分析,帮助运维人员进行业务实时监控、故障定位及排除、业务趋势分析、安全与合规审计等工作,深度挖掘日志的大数据价值,提升了应用整体系统智能分析与处理效率,达到了汇总、检索、展示应用日志和串联事件、快速定位问题等全方位功能要求。
目前日志平台纳管的服务器超过1000台,覆盖了民生银行所有操作系统类型:SuSE Linux(11/12)、AIX(7)、HP_UX(11)和RedHat(5.5),除了应用日志以外,系统软件日志类型覆盖DB2、Oracle、Mysql、Redis、Weblogic、Activemq、Kafka、Tomcat等等,同时采集存储、操作系统、管理口相关指标日志。每天接入日志量在10T到20T之间,平均日接入量在15T左右。在如此量级的日志接入下,对平台本身吞吐量、端到端全链路的写入延迟、查询响应时间等都提出了比较高的要求,因此对于ES集群本身的参数调优成为了一项持续进行的长期性工作,这时ES物理节点过多导致的配置文件分散、角色参数差异、版本管理混乱、配置监控缺失等问题就集中暴露了出来。而使用脚本或者文件分发管理又不够直观和友好,出现问题排查困难,易用性较差,也不具备分布式和高可用功能。
为了能够界面化、集中化管理ES集群不同角色、不同类型的配置并且在配置修改后能够在ES中实时生效,所有配置信息的修改具备规范的权限、流程治理等特性,民生银行天眼ELK日志平台最终采用携程开源的Apollo(阿波罗)作为技术选型,本篇以民生银行天眼日志平台实际需求为中心,逐步展开介绍我们是如何通过Apollo+ES源码改造构建民生银行天眼ELK日志平台配置管理中心。
Apollo目前在github的Star数量超过10000,社区活跃度和版本更新效率都比较高,首先简单介绍一下Apollo本身的功能点和其在天眼ELK日志平台配置管理中心中的实际运用。
Apollo是携程的开源配置管理中心,可以从应用、环境、集群、命名空间4个维度集中的管理配置,并能够够实施的推送至客户端,优点如下:
Apollo提供了一个统一界面集中式管理不同环境(environment)、不同集群(cluster)、不同命名空间(namespace)的配置。同一份代码部署在不同的集群,可以有不同的配置,通过命名空间(namespace)可以很方便地支持多个不同应用共享同一份配置,同时还允许应用对共享的配置进行覆盖。
由于民生银行开发、测试、生产环境均是网络隔离的,所以在进行Apollo部署时我们去掉了4个环境标识DEV、FAT、UAT、PRO中的后面3个,只保留了DEV环境,测试和生产均完整的部署一套Apollo环境。另外运用集群(cluster)实现了ES角色配置文件分离,运用namespace实现了ES不同种类配置文件分析,这些在后面Apollo+ES设计中会详细讲到。
用户在Apollo修改完配置并发布后,客户端能实时(1秒)接收到最新的配置,并通知到应用程序。
这个功能比较诱人,我们在其它项目中也使用到了热发布,但是在ES中没有配置,一方面是由于ES读取的很多配置的模式都是读且仅读一次,热配置无法生效。另一方面ES代码较复杂,其在读取配置文件前后都需要初始化很多参数,很多配置参数是扩散到整个项目代码中的,核心代码、插件代码可能都会有涉及,一些如监听端口配置修改需要重起相关线程模块,实现热配置风险太高,最后热配置在ES源码改造过程中我们只是用于配置参数变化的日志输出打印,完成配置生效还是需要重起节点进程。
所有的配置发布都有版本概念,从而可以方便地支持配置的回滚。
这个是配置中心基本功能,在日志平台进行ES参数优化我们依赖Apollo进行版本管理,使用起来比较方便。
支持配置的灰度发布,比如点了发布后,只对部分应用实例生效,等观察一段时间没问题后再推给所有应用实例
在日志平台实际应用中我们经常使用灰度发布的功能去验证某些通用参数是否可以配置在角色节点或者数据节点可以单独生效,在default集群参数中让某些参数的发布推送到特定的master节点或者data节点,不过最后根据默认参数全部配置一致原则会将default中修改过的参数配置推送到全部的ES节点当中。
应用和配置的管理都有完善的权限管理机制,对配置的管理还分为了编辑和发布两个环节,从而减少人为的错误。所有的操作都有审计日志,可以方便地追踪问题。
在权限控制上生产环境要求必须日志平台A岗负责人有最终的发布权限,ES参数修改对集群整个的稳定性影响比较大,必须将风险降到最低。另外目前日志平台配置管理中心也承担着一些项目组自己开发的工具的配置管理工作,所以单独也进行了权限的划分和处理。
可以在界面上方便地看到配置在被哪些实例使用。
这个功能在日志平台中某种程度上也起到了实例心跳检测的功能,同时根据角色的划分可以清楚地看到这个ES的逻辑节点配置位置,比如default参数肯定是所有节点都会读取,而单独的master、hot、warm、client节点只有相关的角色节点才会读取其配置。值得一提的是由于有缓存的功能,可以看到ES相关节点读取配置的时间实际上是参数改变后节点第一次读取配置的时间,如果ES节点单独重起但是相关参数没有发生变化和发布,那么界面上看到的配置参数读取时间是不会发生改变的。
提供了Java和.Net的原生客户端,方便应用集成,同时提供了Http接口,非Java和.Net应用也可以方便地使用。
ES本身就是通过Java语言编写的,所以通过修改ES源码可以比较方便地将Apollo客户端集成到ES中去。后续我们打算将Logstash处理的配置文件也通过Apollo纳管,由于Logstash是用ruby语言,所以可能就会用到其提供的Http接口。
Apollo自身提供了比较完善的统一配置管理界面,支持多环境、多数据中心配置管理、权限、流程治理等特性。不过Apollo出于通用性考虑,不会对配置的修改做过多限制,只要符合基本的格式就能保存,不会针对不同的配置值进行针对性的校验,如数据库用户名、密码,Redis服务地址等。对于这类应用配置,Apollo支持应用方通过开放平台API在Apollo进行配置的修改和发布,并且具备完善的授权和权限控制。
目前天眼ELK日志平台主要是还是使用Apollo本身提供的配置管理界面进行管理,不过后续可以考虑通过其API将部分功能在大数据集中的管控平台上去实现。
配置中心作为基础服务,可用性要求非常高,这就要求Apollo对外部依赖尽可能地少,目前唯一的外部依赖是MySQL,所以部署非常简单,只要安装好Java和MySQL就可以让Apollo跑起来。Apollo还提供了打包脚本,一键就可以生成所有需要的安装包,并且支持自定义运行时参数。
日志平台基本按照官方文档进行标准部署,稍微有一点改动的地方是Apollo本身的日志路径存放地址是以进程号为目录层级的,不太直观,通过修改源码将其增加adminservice、configservice和portal目录,使得不同模块的日志路径比较清晰易区分。
在日志平台生产实际使用Apollo之前,必须对其架构进行深入了解和剖析,在架构设计的过程中有一个基本点必须明确,那就是Apollo的某个服务异常不应该影响整个配置管理中心的服务,Apollo所有模块的异常不应该影响ES集群的正常运行。Apollo的基础模型如下:
关于Apollo各个组件的相关作用和实现原理不是本文的重点,我就不在这里过多赘述了,感兴趣的同学可以去Apollo的github进行详细了解。在实际部署中我们是将Apollo部署在三台服务器上做高可用和负载均衡,每台服务器上都会启动独立的config Service、Admin Service和Portal三个模块进程,后端连接统一的mysql数据库,通过修改数据库中serverconfig字段使得Eureka注册服务构成三节点的集群,client端和portal统一配置3台服务ip地址进行连接。下面就开始介绍我们构建天眼ELK日志管理平台的两块核心工作:Apollo ES架构设计和ES源码改造。
在Apollo ES架构设计这块其实包含了两部分工作,一部分工作是通过Apollo的集群分离功能将通过ES中的角色将配置进行拆分,方面统一管理;另一部分工作是根据实际需求将elasticsearch需要频繁修改的配置文件进行分类并分别实现客户端开发。这两部分工作都包含了一个共有的工作内容——页面配置设计实现以增加功能使用体验。
日志平台目前在生产环境使用的ELK版本是5.5的,在进行ES集群设计部署时data节点采用了冷热数据分离技术,引入了SSD来提升ES的读写性能。单台ES存储有2块SD盘和若干SATA盘,所以每台ES server都启动了3个ES节点,2个hot节点和1个warm节点。Indexer中指配置了hot节点的端口,通过ES中的模板定义保证实时数据只写入hot节点。通过ES官方推荐的curator工具定时将数据从hot节点搬迁到warm节点,SSD数据保留周期为一周。同时本身ES集群我们启动了3个master节点和3个client节点,那么实际上ES集群中一共是4种:master,client,hot和warm,节点类型都是通过配置文件elasticsearch.yml的参数进行区分的。
我们知道ES主要的配置参数都是在elasticsearch.yml中进行定义的,最开始设计时我们计划是通过主机名的方式进行配置文件区分,Apollo本身也提供了通过hostname定义不同的namespace的内置方法,但是最后达到的效果非常不理想。日志平台生产集群物理节点目前是28个,总节点数为90个,当需要修改参数时需要每个节点的namespace配置都在界面上进行修改并发布,重复工作太大;另外namespace过多也导致管理页面特别冗长,下拉很久也拖不到页面底部,用户体验很差,当时就想这样还不如直接脚本分发修改配置文件来的快些,失去了日志平台配置管理中心建设的初衷。
于是就想能不能通过角色进行配置拆分,相同的角色的配置是否可以放到一个namespace中去处理。Apollo本身在DEV的生产模式下提供创建多集群的配置方式,由于在日志平台中不存在多集群的情况,于是我们就将集群模式的功能来区分ES中的节点角色。最终在角色中实际上创建了5种角色参数分类:default、hot、warm、master和client。
除了elasticsearch.yml配置文件以外,ES每个节点的jvm.options文件我们也经常需要修改,最基本的就是通过-Xms和-Xmx来调整ES节点分配的堆内存大小。根据冷热分离需求和节点角色的特性,hot、warm、master、client分配的内存都是不一样的,所以很自然的-Xms和-Xmx就单独放到了每个角色的专有属性当中,其他的配置参数都放到default集群中。
Apollo ES架构设计结束之后就可以进行ES源码改造这块的工作了,实际上在我们在ES源码改造这块的所花费的时间远远没有设计的时候多,一旦设计定型源码改造就比较容易。结合Apollo客户端进行ES源码改造主要分为两部分工作:elasticsearch配置源码改造和jvm配置功能开发。
ES读取jvm.options配置文件是在启动脚本中直接实现的,所以无法通过直接修改ES源码来进行Apollo客户端开发。如果直接修改elasticsearch启动脚本来读取jvm配置比较复杂,而且这样修改对原来的启动脚本改造较大,不是我们所想要的。但jvm参数本身对于ES来讲还是具有一定的调优价值,尤其是内存分配上,在单台物理机上启动多个不同角色节点可能需要频繁的调整。最后我们在实现上采用了单独开发一个jar包在elasticsearch启动脚本之前执行,读取Apollo配置如果有key值不同在文件中进行替换。Apollo客户端上的处理逻辑与elasticsearch.yml完全一样,优先级都是角色配置>default配置>配置文件,区别就是配置文件不一致就直接替换,最终落地还是以配置文件中的参数配置为准。代码就不粘了,启动命令如下:
java -jar /logger/Apollo/Apollo-jvm.jar -DApollo.cluster=$APOLLO /logger/elasticsearch/config$APOLLO_PATH/jvm.options
这里有几点需要特殊说明一下,首先jvm参数在jvm.options配置文件中是有两种格式的,一种就是传统的以冒号分隔的key-value键值对,这种在Apollo中直接properties方式处理就好,还有一种参数既是key值也是value值,如-Xms2g,这种类型参数我们想了好几种解决方案,如把key值设置成和value值一样、对数字进行特殊处理、对特殊参数单独命名等等,但是最后一旦多次修改就会产生一些逻辑bug,最终我们采取了一种折中的方式,首先如果是key-value键值对类型那么正常处理,如果是单一键值的话那么采用前缀字符串匹配的方式实现,也就是说比如-Xms2g这种参数实际上在Apollo配置的是-Xms:-Xms2g,当Apollo客户端进行文件扫描时如果是非key-value且符合字符串前缀的就进行参数值覆盖,这就要求这种配置参数在进行Apollo jvm录入时保证是唯一的,这种方案的优势是一方面jvm参数一般value值直接做key值或者前缀到数字之前就可以保证唯一性,另一方面这种方式避免了自己命名参数导致含义不清,前缀+注释的方式在页面上显示清晰,有较好的用户体验。
其次因为我们在一台服务器上实际上是启动了多个ES实例的,所以在Apollo启动命令中是通过环境变量来区分角色集群和jvm配置文件路径的,环境变量通过进程管理工具supervisord来进行传递的。
最后需要提到的就是在jvm的启动实例列表中经常显示为0,原因是我们单独开发的一个jar包在ES启动脚本前执行,执行后这个客户端就退出了,前面提过Apollo的客户端和服务端回保持一个长连接,这个长连接可以保证服务端获取客户端的心跳信息,一旦客户端退出了Apollo默认只展示最近一天访问过Apollo的实例,那么一天之后数据库就会清空对应字段,jvm启动实例列表就会显示为0。
进行ES Apollo客户端改造后我们发现了一个问题:在源码中按照ES的方式输出的日志无法打印到ES的系统日志中。这个问题困扰了我们很久也找不到原因,只能一点点去梳理源码。通过ES入口方法类找到了读取配置文件的EnvironmentAwareCommand中的执行方法,该方法是一个抽象方法,其对应的实现方法如下图:
[program:elkwarm]
environment=ES_JVM_OPTIONS=%(ENV_ELK_WARM_JVM_OPTIONS)s,APOLLO=%(ENV_APOLLO_WARM)s,APOLLO_PATH=%(ENV_APOLLO_WARM_ONE)s
command = /logger/elasticsearch/bin/elasticsearch -Epath.conf=/logger/elasticsearch/configwarm
username = logger
autostart=true
autorestart=false
startsecs=3
priority=1003
stdout_logfile=/loggerfiles/elasticsearch/log/warm/cmbc_elk_warm.log
stdout_logfile_maxbytes=10MB
stdout_logfile_backuups=10
stdout_events_enabled=true
如上所示,在配置中需要将elasticsearch和jvm的Apollo角色环境变量传递进去,这样才能区分出同一台服务器不同ES实例的集群角色和配置文件路径,并且由于hot节点单台服务器上有两个实例环境变量还需要数字来区分一下。
此外,为了方便管理我们还使用Supervisord-monitor开源工具将ES集群所有服务器集成到一个页面上进行统一管理,除了具备启停功能之外还可以通过页面以tail -f的方式来查看我们单独生成的cmbc_elk_warm.log日志文件。
这是我们民生银行大数据团队对Apollo和ES两种开源产品的一次深入学习和探索,在业界没有相关案例的前提下,我们团队摸着石头过河,没有盲目地为了使用而使用,而是根据在生产环境中ES集群运行的实际情况有针对性的进行了Apollo架构设计和ES源码改造。在构建天眼ELK日志平台配置管理中心的整个过程当中,Apollo架构设计实际上要比ES源码改造花的时间多的多,无乱多么优秀的开源产品、多么牛逼的技术框架都不能脱离实际应用场景而存在,设计的合理必然会导致开发模块内部的高聚合和模块之间的低耦合,从而提高程序开发的效率,减少改造风险和增加落地的可行性。后续我们一方面会推进日志平台本身配置集中工作,设计出比较合理的模式接入日志平台其他组件配置信息,如Logstash,另一方面大数据产品均有服务器数量多、配置文件多难以集中管理的问题,如何让其满足更多的大数据产品是我们下一步所面临的挑战,最终目标是天眼ELK日志平台配置管理中心能够推广成为整个大数据平台的集中配置管理中心。
文章转自微信公众号“民生运维”
作者:生产运营大数据产品组
编辑:民生运维文化建设小组
如果觉得我的文章对您有用,请点赞。您的支持将鼓励我继续创作!
赞5
添加新评论1 条评论
2019-03-17 17:31