Flume日志收集分层架构应用实践

大数据 Ansible 发表了文章 0 个评论 7244 次浏览 2016-03-19 18:54 来自相关话题

Flume作为一个日志收集工具,非常轻量级,基于一个个Flume Agent,能够构建一个很复杂很强大的日志收集系统,它的灵活性和优势,主要体现在如下几点: []模块化设计:在其Flume Agent内部可以定义三种组件:Source、Channe ...查看全部
Flume作为一个日志收集工具,非常轻量级,基于一个个Flume Agent,能够构建一个很复杂很强大的日志收集系统,它的灵活性和优势,主要体现在如下几点:
    []模块化设计:在其Flume Agent内部可以定义三种组件:Source、Channel、Sink[/][]组合式设计:可以在Flume Agent中根据业务需要组合Source、Channel、Sink三种组件,构建相对复杂的日志流管道[/][]插件式设计:可以通过配置文件来编排收集日志管道的流程,减少对Flume代码的侵入性[/][]可扩展性:我们可以根据自己业务的需要来定制实现某些组件(Source、Channel、Sink)[/][]支持集成各种主流系统和框架:像Hadoop、HBase、Hive、Kafka、ElasticSearch、Thrift、Avro等,都能够很好的和Flume集成[/][]高级特性:Failover、Load balancing、Interceptor等[/]

为什么要对Flume日志收集系统进行分层设计

基于Flume设计实现分层日志收集系统,到底有什么好处呢?我们可以先看一下,如果不分层,会带来哪些问题:
    []如果需要通过Kafka去缓冲上游基于Flume收集而构建的日志流,对于数据平台内部服务器产生的数据还好,但是如果日志数据是跨业务组,甚至是跨部门,那么就需要将Kafka相关信息暴露给外部,这样对Kafka的访问便不是数据平台内部可控的[/][]如果是外部日志进入平台内部HDFS,这样如果需要对Hadoop系统进行升级或例行维护,这种直连的方式会影响到上游部署Flume的日志流的始端日志收集服务[/][]如果数据平台内部某些系统,如Kafka集群、HDFS集群所在节点的机房位置变更,数据迁移,会使得依赖日志数据的外部系统受到不同程度的影响,外部系统需要相关开发或运维人员参与进来[/][]由于收集日志的数据源端可能是外部一些服务器(多个单个的节点),一些业务集群(相互协作的多节点组),也可能是内部一些提供收集服务的服务节点,这些所有的服务器上部署的Flume Agent都处于一层中,比较难于分组管理[/][]由于所有数据源端Flume Agent收集的日志进入数据平台的时候,没有一个统一的类似总线的组件,很难因为某些业务扩展而独立地去升级数据平台内部的接收层服务节点,可能为了升级数据平台内部某个系统或服务而导致影响了其他的接收层服务节点[/]
通过下图我们可以看出,这种单层日志收集系统设计,存在太多的问题,而且系统或服务越多导致整个日志收集系统越难以控制:
flume-without-layered-architecture.png
上图中,无论是外部还是内部,只要部署了Flume Agent的节点,都直接同内部的Kafka集群和Hadoop集群相连,所以在数据平台内部只能尽量保持Kafka和Hadoop集群正常稳定运行,也要为外部日志收集Flume Agent的数据流量的陡增和异常变化做好防控准备。再者,如需停机维护或者升级某一个集群,可能都需要通知外部所有Flume Agent所在节点的业务方,做好应对(停机)准备。
接着看,如果我们基于Flume使用分层的方式来设计日志收集系统,又有哪些优势,如下图所示:
flume-with-layered-architecture.png
上图中,Flume日志收集系统采用两层架构设计:第一层(L1)是日志收集层,第二层(L2)是数据平台缓冲层(汇聚层)。通过这种方式,使得日志收集系统有如下特点:
    []针对数据平台外部的业务系统,根据需要分析的数据业务类型进行分组,属于同一种类型的业务日志,在数据平台前端增加了一个Flume汇聚层节点组,该组节点只影响到它对应的L1层的业务数据[/][]如果Hadoop集群、Kafka需要停机维护或升级,对外部L1层Flume Agent没有影响,只需要在L2层做好数据的接收与缓冲即可,待维护或升级结束,继续将L2层缓存的数据导入到数据存储系统[/][]如果外部某个类型的业务日志数据节点需要扩容,直接在L1层将数据流指向数据平台内部与之相对应的L2层Flume Agent节点组即可,能够对外部因业务变化发生的新增日志收集需求,进行快速地响应和部署[/][]对于数据平台内部,因为收集日志的节点非常可控,可以直接通过L1层Flume Agent使日志数据流入HDFS或Kafka,当然为了架构统一和管理,最好也是通过L2层Flume Agent节点组来汇聚/缓冲L1层Flume Agent收集的日志数据[/]
通过上面分析可见,分层无非是为了使的日志数据源节点的Flume Agent服务与数据平台的存储系统(Kafka/HDFS)进行解耦,同时能够更好地对同类型业务多节点的日志流进行一个聚合操作,并分离开独立管理。另外,可以根据实际业务需要,适当增加Flume系统分层,满足日志流数据的汇聚需要。

应用整体架构

我们看一下,Flume日志收集系统,在我们这个示例应用中处于一个什么位置,我简单画了一下图,加了一些有关数据处理和分析的节点/组件,如下图所示:
flume-platform-overall-architecture.png
这里,简单了解一下上图即可,由于日志收集在整个应用系统中是很重要的一个环节,所以必须保证日志收集系统设计的可靠、可用、灵活、稳定,通过上面在日志收集系统收集日志之后,数据平台所做的大量分析处理,来凸显日志收集系统的重要性,这里其他内容不做过多说明。

Flume分层架构实践

这里,我们主要以实时收集日志为例,说明如何构建一个相对复杂的Flume分层日志收集系统。首先,简要说明一下日志收集需求:
    []手机客户端上报的用户行为事件(App User Event),通过数据平台内部定义好的接口格式,从Nginx日志里面实时流入数据平台,这对应于Flume日志收集系统L1层[/][]通过组织各种活动,来推广某些App的产品特性,会定向向用户推送通知,单独使用推送点击(Push Click)Agent来收集这些点击行为数据[/][]App所依赖的一些基础内容,会以服务的形式开放给外部第三方调用,对于由第三方App带来的用户的行为点击事件(Thirdparty Click),单独使用L1层Flume Agent进行收集[/][]第三方会在App中根据不同的内容,投放广告(Ad),对于广告曝光/点击行为的数据,与上述提到的数据收集单独分离出来,因为该日志数据后期可能会大规模推广,会有爆发性增长,在L1层进行收集[/][]在L2层主要是汇聚或缓冲L1层流入的日志数据[/][]同时,为了防止L2层Flume Agent因为故障或例行停机维护等,所以使用了Flume的Failover特性,亦即L1层每一个Sink同时指向L2层的2个相同的Flume Agent[/][]L1层的Flume Agent在收集日志的过程中应该不允许在Channel中累积过多数据(但是还要防止数据流速过慢导致内存Channel数据溢出),还要能够尽量降低读写磁盘的开销,所以使用内存类型的Channel[/][]L2层为了保证数据能够可靠地缓冲(在允许的一段时间内累积保存数据),如Hadoop或Kafka故障停机或停机维护升级,采用文件类型的Channel,还要尽量调大容量,也不能因为多应用共享磁盘而造成数据处理延迟,所以对于不同的Channel分别使用独立的磁盘[/]
详细分层设计如下图所示:
flume-layered-architecture.png
上图是从实际的整个数据平台中拿出来一部分,简单便于解释说明。有关上图中所涉及到的Flume Agent的配置详情,下面会根据Flume分层的结构(L1层、L2层)来详细配置说明。由于L1层的10.10.1.101和10.10.1.102节点上部署的Flume Agent是对称的,所以下面只拿出其中一个来说明配置,不同的是,这两个节点上Flume Agent的Sink使用Failover功能,分别交叉指向L2层Flume Agent,也能够起到一定的负载均衡的作用。

上游Flume日志收集层

下面,分别针对10.10.1.101节点上的3个Flume Agent的配置内容,分别进行说明如下:
    []L1层:App用户行为事件(App User Event)日志收集[/]
Flume Agent名称为a1,使用Exec Source、Memory Channel、Avro Sink,这里我们的Nginx日志文件始终指向/data/nginx/logs/app_user_events.log,即使日切或小时切文件,使用tail -F就能保证日志内容都被收集。具体配置内容如下所示:
a1.sources = s1a1.channels = mc1a1.sinks = k1 k2# Configure sourcea1.sources.s1.channels = mc1a1.sources.s1.type = execa1.sources.s1.command = tail -F /data/nginx/logs/app_user_events.log# Configure channela1.channels.mc1.type = memorya1.channels.mc1.transactionCapacity = 50000a1.channels.mc1.capacity = 100000# Configure sinksa1.sinks.k1.channel = mc1a1.sinks.k1.type = avroa1.sinks.k1.hostname = 10.10.1.122a1.sinks.k1.port = 44446a1.sinks.k2.channel = mc1a1.sinks.k2.type = avroa1.sinks.k2.hostname = 10.10.1.121a1.sinks.k2.port = 44446# Configure failovera1.sinkgroups = g1a1.sinkgroups.g1.sinks = k1 k2a1.sinkgroups.g1.processor.type = failovera1.sinkgroups.g1.processor.priority.k1 = 9a1.sinkgroups.g1.processor.priority.k2 = 7a1.sinkgroups.g1.processor.maxpenalty = 10000
    []L1层:推送点击事件(Push Click Event)日志收集[/]
a2.sources = s2a2.channels = mc2a2.sinks = k3 k4# Configure sourcea2.sources.s2.channels = mc2a2.sources.s2.type = execa2.sources.s2.command = tail -F /data/nginx/logs/push_click_events.log# Configure channela2.channels.mc2.type = memorya2.channels.mc2.capacity = 50000a2.channels.mc2.transactionCapacity = 100000# Configure sinksa2.sinks.k3.channel = mc2a2.sinks.k3.type = avroa2.sinks.k3.hostname = 10.10.1.121a2.sinks.k3.port = 44447a2.sinks.k4.channel = mc2a2.sinks.k4.type = avroa2.sinks.k4.hostname = 10.10.1.122a2.sinks.k4.port = 44447# Configure failovera2.sinkgroups = g2a2.sinkgroups.g2.sinks = k3 k4a2.sinkgroups.g2.processor.type = failovera2.sinkgroups.g2.processor.priority.k3 = 9a2.sinkgroups.g2.processor.priority.k4 = 7a2.sinkgroups.g2.processor.maxpenalty = 10000
    []L1层:第三方点击事件(Thirdparty Click Event)日志收集[/]
第三方点击事件通过统一的接口上传数据,那么配置起来也比较容易,如下所示:
a3.sources = s3a3.channels = mc3a3.sinks = k5 k6# Configure sourcea3.sources.s3.channels = mc3a3.sources.s3.type = execa3.sources.s3.command = tail -F /data/nginx/logs/thirdparty_click_events.log# Configure channela3.channels.mc3.type = memorya3.channels.mc3.transactionCapacity = 50000a3.channels.mc3.capacity = 100000# Configure sinksa3.sinks.k5.channel = mc3a3.sinks.k5.type = avroa3.sinks.k5.hostname = 10.10.1.121a3.sinks.k5.port = 44446a3.sinks.k6.channel = mc3a3.sinks.k6.type = avroa3.sinks.k6.hostname = 10.10.1.122a3.sinks.k6.port = 44446# Configure failovera3.sinkgroups = g3a3.sinkgroups.g3.sinks = k5 k6a3.sinkgroups.g3.processor.type = failovera3.sinkgroups.g3.processor.priority.k5 = 9a3.sinkgroups.g3.processor.priority.k6 = 7a3.sinkgroups.g3.processor.maxpenalty = 10000
    []L1层:广告点击事件(Ad Click Event)日志收集[/]
广告点击事件日志收集配置,如下所示:
a4.sources = s4a4.channels = mc4a4.sinks = k7 k8# Configure sourcea4.sources.s4.channels = mc4a4.sources.s4.type = execa4.sources.s4.command = tail -F /data/nginx/logs/ad.log# Configure channela4.channels.mc4.type = memorya4.channels.mc4.transactionCapacity = 50000a4.channels.mc4.capacity = 100000# Configure sinksa4.sinks.k7.channel = mc4a4.sinks.k7.type = avroa4.sinks.k7.hostname = 10.10.1.121a4.sinks.k7.port = 44448a4.sinks.k8.channel = mc4a4.sinks.k8.type = avroa4.sinks.k8.hostname = 10.10.1.122a4.sinks.k8.port = 44448# Configure failovera4.sinkgroups = g4a4.sinkgroups.g4.sinks = k7 k8a4.sinkgroups.g4.processor.type = failovera4.sinkgroups.g4.processor.priority.k7 = 10a4.sinkgroups.g4.processor.priority.k8 = 8a4.sinkgroups.g4.processor.maxpenalty = 10000

下游Flume日志收集汇聚层

    []L2层:App用户事件+推送点击事件日志合并收集[/]
这种业务需求是:把App用户事件和推送点击事件合并写入文件,最后都会写入HDFS,从而进一步在Hive中进行离线分析;同时又要使这两种事件分别独立地走实时计算的流程,App用户事件实时计算流程需要实时统计用户使用App过程中行为特征,而推送点击事件实时计算需要针对某一次活动来实时分析和展示用户的参与情况。具体配置内容,如下所示:
a1.sources = s1 s2a1.channels = fc1 fc2 fc3a1.sinks = kk1 fk2 kk3# Configure source:# Configure app user event source: s1 -> fc1+fc2a1.sources.s1.channels = fc1 fc2a1.sources.s1.type = avroa1.sources.s1.bind = 10.10.1.121a1.sources.s1.port = 44446a1.sources.s1.threads = 8# Configure source# Configure push click event source: s2 -> fc2+fc3a1.sources.s2.channels = fc2 fc3a1.sources.s2.type = avroa1.sources.s2.bind = 10.10.1.122a1.sources.s2.port = 44447a1.sources.s2.threads = 4# Configure file channel(/data1)# Configure app user event channel: fc1 ->kk1a1.channels.fc1.type = filea1.channels.fc1.checkpointDir = /data1/flume/channels/app_user_event/checkpointa1.channels.fc1.useDualCheckpoints = truea1.channels.fc1.backupCheckpointDir = /data1/flume/channels/app_user_event/backupa1.channels.fc1.dataDirs = /data1/flume/channels/app_user_event/dataa1.channels.fc1.transactionCapacity = 100000a1.channels.fc1.capacity = 500000a1.channels.fc1.checkpointInterval = 60000a1.channels.fc1.keep-alive = 5a1.channels.fc1.maxFileSize = 5368709120# Configure file channel(/data2)# Configure app user event + push click event: fc2 - > fk2a1.channels.fc2.type = filea1.channels.fc2.checkpointDir = /data2/flume/channels/offline_file_event/checkpointa1.channels.fc2.useDualCheckpoints = truea1.channels.fc2.backupCheckpointDir = /data2/flume/channels/offline_file_event/backupa1.channels.fc2.dataDirs = /data2/flume/channels/offline_file_event/dataa1.channels.fc2.transactionCapacity = 100000a1.channels.fc2.capacity = 500000a1.channels.fc2.checkpointInterval = 60000a1.channels.fc2.keep-alive = 5a1.channels.fc2.maxFileSize = 5368709120# Configure file channel(/data3)# Configure push click channel: fc3 ->kk3a1.channels.fc3.type = filea1.channels.fc3.checkpointDir = /data3/flume/channels/push_click_event/checkpointa1.channels.fc3.useDualCheckpoints = truea1.channels.fc3.backupCheckpointDir = /data3/flume/channels/push_click_event/backupa1.channels.fc3.dataDirs = /data3/flume/channels/push_click_event/dataa1.channels.fc3.transactionCapacity = 100000a1.channels.fc3.capacity = 500000a1.channels.fc3.checkpointInterval = 60000a1.channels.fc3.keep-alive = 5a1.channels.fc3.maxFileSize = 5368709120# Configure sink: RealtimeMessageSink(app user event)a1.sinks.kk1.type = org.shirdrn.flume.sink.RealtimeMessageSinka1.sinks.kk1.channel = fc1a1.sinks.kk1.metadata.broker.list = kafka01:9092,kafka02:9092,kafka03:9092a1.sinks.kk1.topic = json_user_eventa1.sinks.kk1.serializer.class = kafka.serializer.StringEncodera1.sinks.kk1.producer.type = asynca1.sinks.kk1.message.send.max.retries = 3a1.sinks.kk1.client.id = flume_app_user_event_2_1a1.sinks.kk1.event.decoder.count = 8a1.sinks.kk1.output.stat.event.batch.size = 2000a1.sinks.kk1.event.decoder.queue.size = 1000# Configure sink: RichRollingFileSinka1.sinks.fk2.type = org.shirdrn.flume.sink.RichRollingFileSinka1.sinks.fk2.channel = fc2a1.sinks.fk2.batchSize = 100a1.sinks.fk2.serializer = TEXTa1.sinks.fk2.sink.rollInterval = 60a1.sinks.fk2.sink.directory = /data/flume/rolling_filesa1.sinks.fk2.sink.file.prefix = eventa1.sinks.fk2.sink.file.suffix = .loga1.sinks.fk2.sink.file.pattern = yyyyMMddHHmmss# Configure sink: RealtimeMessageSink(push click)a1.sinks.kk3.type = org.shirdrn.flume.sink.RealtimeMessageSinka1.sinks.kk3.channel = fc3a1.sinks.kk3.metadata.broker.list = kafka01:9092,kafka02:9092,kafka03:9092a1.sinks.kk3.topic = json_push_click_eventa1.sinks.kk3.serializer.class = kafka.serializer.StringEncodera1.sinks.kk3.producer.type = asynca1.sinks.kk3.message.send.max.retries = 3a1.sinks.kk3.client.id = flume_push_click_2_1a1.sinks.kk3.event.decoder.count = 4a1.sinks.kk3.output.stat.event.batch.size = 2000a1.sinks.kk3.event.decoder.queue.size = 1000
上面,可以看到我们自己实现的org.shirdrn.flume.sink.RealtimeMessageSink,该Sink主要是使Flume收集的日志写入Kafka中,在Flume 1.5.0版本中还没有内置实现,所以我们自己实现了,并在其中加入了适合我们业务的处理逻辑,比如,将Nginx日志记录行解析,然后根据实时计算需要,过滤掉不需要进入Kafka(最终在Storm集群中处理)事件数据,最后转成JSON字符串的格式,写入到Kafka中的Topic里。通过上面的配置也可以看出,可以配置很多参数,例如解析线程数、队列大小等。
由于我们需要将写入本地文件系统的文件按照我们自己的方式来定义,所以基于Flume内置的file_roll实现进行修改,实现了自己的org.shirdrn.flume.sink.RichRollingFileSink,该Sink主要是对文件名字符串进行格式化,能够通过文件名来获取到文件生成的时间(人类可读格式)。
    []L2层:广告点击事件日志收集[/]
上面的图中,L1层可以根据需要扩展到更多的服务器节点,在L2层根据需要进行汇聚/缓冲,具体配置内容如下所示:
a2.sources = s3a2.channels = fc4a2.sinks = kk4# Configure source: s3 -> fc4a2.sources.s3.channels = fc4a2.sources.s3.type = avroa2.sources.s3.bind = 10.10.1.121a2.sources.s3.port = 44448a2.sources.s3.threads = 2# Configure channel(/data4)# Configure Ad channel: fc4 ->kk4a2.channels.fc4.type = filea2.channels.fc4.checkpointDir = /data4/flume/channels/ad/checkpointa2.channels.fc4.useDualCheckpoints = truea2.channels.fc4.backupCheckpointDir = /data4/flume/channels/ad/backupa2.channels.fc4.dataDirs = /data4/flume/channels/ad/dataa2.channels.fc4.transactionCapacity = 100000a2.channels.fc4.capacity = 500000a2.channels.fc4.checkpointInterval = 60000a2.channels.fc4.keep-alive = 5a2.channels.fc1.maxFileSize = 5368709120# Configure sinks: RealtimeAdKafkaSinka2.sinks.kk4.type = org.shirdrn.flume.sink.RealtimeAdKafkaSinka2.sinks.kk4.channel = fc4a2.sinks.kk4.metadata.broker.list = kafka01:9092,kafka02:9092,kafka03:9092a2.sinks.kk4.topic = json_ad_eventa2.sinks.kk4.serializer.class = kafka.serializer.StringEncodera2.sinks.kk4.producer.type = asynca2.sinks.kk4.message.send.max.retries = 3a2.sinks.kk4.client.id = flume_ad_2_1a2.sinks.kk4.event.decoder.count = 4a2.sinks.kk4.output.stat.event.batch.size = 2500a2.sinks.kk4.event.decoder.queue.size = 5000

实践总结

这里我们简单总结一些内容,如下所示:
    []Flume监控[/]
简单一点的监控,直接在启动的时候,开启一个Web端口,通过端口来获取Flume Agent服务的一些相关数据,命令类似:
bin/flume-ng agent -n a1 -c conf -f conf/config.conf -Dflume.monitoring.type=http -Dflume.monitoring.port=34545
这样便可以在Flume Agent服务节点上,浏览Web端口34545来查看,数据以JSON格式表示,比较重要的一些元数据,如channel容量、当前使用量等等,通过这些数据可以了解当前Flume的工作状态,是否需要升级扩容等等。 
另外,也可以通过Ganglia来收集并分析Flume Agent服务运行状态,能够更加详细地展示Flume Agent服务的状态,因为Ganglia配置相对复杂,这里就不做过多解释,感兴趣可以尝试一下。
    []Flume内存调优[/]
因为Flume使用Java实现的,所以就会遇到有关JVM调优的问题,这个也比较容易。默认情况下,Flume Agent进程的堆内存设置比较小,在日志数据量比较大的情况下就需要修改并调试这些参数,以满足业务需要。设置JVM相关参数,可以修改conf/flume-env.sh文件(也可以直接在启动Flume Agent服务时指定JVM选项参数),例如修改JAVA_OPTS变量,示例如下所示:
JAVA_OPTS="-server -Xms1024m -Xmx4096m -Dcom.sun.management.jmxremote -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:ParallelGCThreads=4 -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/data/flume/logs/gc-ad.log"
这样,可以方便地修改GC策略,一般由于Flume实时收集日志比较注重实时性,希望能够快速地响应,尽量减少GC导致暂停业务线程被挂起的时间,所以可以将GC设置为ParNew+CMS策略。将GC日志输出,在一定程度上能够更加方便地观察Flume Agent服务运行过程中JVM GC的详细情况,通过诊断来优化服务运行。
    []下游L2层接收消息调优[/]
通常,在开始部署Flume日志收集系统时,上游L1层服务节点比较少,在L2层汇聚时使用默认的配置可能效果也会不错,但是如果L1层Flume Agent越来越多,就能看到L2层处理速度慢下来。L2层的Flume Agent服务一般会远远小于L1层Flume Agent服务数,这种情况下,如果L2层Flume Agent服务使用Avro Source,可以调大Avro接收线程数,示例如下:
a1.sources.s1.type = avroa1.sources.s1.bind = 10.10.1.121a1.sources.s1.port = 44446a1.sources.s1.threads = 8
上面默认情况下threads参数的值1,可以将该值调大,否则的话,L1层就会堆积日志记录,严重可能导致数据丢失。
    []Flume处理业务逻辑约束[/]

Flume的易扩展性使得我们可以根据自己的业务特点来实现一些组件,那么我们在将实际业务逻辑掺杂进Flume中时,需要考虑是否非得必须这么做?如果这么做是否会影响Flume实时传输日志的速度和效率? 
Flume作为一个轻量级的日志收集工具,个人认为最好将相对复杂的业务逻辑(尤其是需要与一些存储系统,如MySQL、Redis交互时)后移,放在Storm集群中去处理,或者自己实现的业务处理集群中,而Flume就让它去做其擅长的事情——路由消息。
当然,有些业务场景可能必须在Flume日志收集层去做,如根据原始非结构化的消息,无法控制不同类型的消息路由到不同的目的地,那么可能需要在收集层做一个简单的解析或格式化,实际上这是在
Flume层做了一个简单的日志分发。无论如何,如果想在Flume层插入业务逻辑处理,尽量避免过于复杂的处理而影响整个日志传输速度,如果后端有实时推荐需求,日志中事件的实时性大大延迟,就会影响实施个性化推荐。


分享阅读原文:http://shiyanjun.cn/archives/1497.html
文章作者:时延军


如何让IT部门成为企业的价值中心

运维 cloudwise 发表了文章 0 个评论 1955 次浏览 2016-03-18 14:37 来自相关话题

如今的中国企业正处在传统生产、经营模式向互联网+转型的风口浪尖,企业业务对IT和互联网的依赖越来越重,IT部门在企业的价值也是水涨船高。而IT部门要为企业创造更大的价值,同样需要改变过去被动响应的工作模式,主动走在业务的前面,来引导业务需求,驱动业务改变。 ...查看全部
如今的中国企业正处在传统生产、经营模式向互联网+转型的风口浪尖,企业业务对IT和互联网的依赖越来越重,IT部门在企业的价值也是水涨船高。而IT部门要为企业创造更大的价值,同样需要改变过去被动响应的工作模式,主动走在业务的前面,来引导业务需求,驱动业务改变。

为什么要做业务数据监控
四川文轩在线是一家做多渠道出版物(图书、音像)销售的电子商务公司,公司有自建的官网、移动官网、移动APP,也依托天猫、京东、当当、亚马逊、微信等平台开设自营旗舰店,另外还跟各大图书电商及各地新华书店开展各种供货、代发等业务。

1.png



由于公司业务线繁多,过去往往是业务部门通过月底报表发现业务出现明显滑坡后,才知道相关平台的IT系统出现故障,这时可能已经对企业经营造成不小的影响。为了保障业务系统的高效运行,公司要求对所有业务平台纳入监控,需要监控的业务指标非常多,靠人工去盯并不现实。因此,技术部门在监控好IT系统各环节运行情况的同时,还需要提供自动化工具给业务部门实现业务指标都系统自动监控。
现在网上有各种开源的、收费的、本地部署的、云上的监控工具,大多都是针对纯技术部门提供系统功能、性能及运行环境的监控,基本没有看到针对业务数据的监控工具,估计大家都认为业务数据的监控应该由报表来提供吧,据我了解的一些报表,要么没有,要么做的太粗糙不适合大规模使用。
业务数据监控相比系统监控的特点在于业务数据监控各公司、各岗位差异性很大,定制化要求很高,并且随着公司业务地发展可能随时需要调整。通过精挑细选,四川文轩在线于2013年开始使用云智慧监控宝,在监控宝独家功能——自定义监控的基础上,灵活构建起适应公司业务发展需要的监控体系。

公司中哪些角色需要监控业务数据?
首先公司的总经理、部门经理、业务主管肯定不会随时去关注具体的业务指标,他们也没时间去关注那么多,他们更适合使用报表查询分析结果来支撑他们制定业务策略。
而一线的业务运营人员呢?他们就需要时刻关注各项业务指标了,上级已经制定好各种业务操作办法,他们根据各项指标照着做。下面这张图简单说了下我们网店运营人员需要经常监控的几个指标:

2.png

(图一)

图上只简单列了几个常用的指标,网店运营人员当然还需要关注网店流量、用户特征、商品转换率、支付率、上架品种数等等指标,如果我们系统能够获取相关数据也是可以做成自动监控的。
图中列了3个指标,这些数据在报表中都能查到,但靠人查报表来监控实在太落后了,下班、请假、放假了怎么办?就应该当指标出现异常时监控系统及时给与相关人员报警通知才对。具体怎样来设计这些指标的告警呢?

下面我们大致介绍下销售相关的三个指标监控:
1、销售额:
每个公司肯定都有报表可以查到每日、每周、每月等等时间维度的销售额的,对于网店运营人员可能需要关注的更细,往往需要关注每小时的销售情况。当某个时点销售额急剧下降,可能意味着系统或者业务规则出现问题了,需要马上召集相关环节一起排查,尽快恢复,否则销售就丢失了。下面是我们关于某网店销售额的监控截图(出于公司信息保密原则,屏蔽了一些信息,请见谅):

3.png

(图二)

图二中有三条线:
当前小时的销售额 : 例如当前是9:08,则获取8:08~9:08的销售额
前一个时点销售额 : 例如当前是9:08,则获取7:08~8:08的销售额
昨天同时段销售额 :例如当前是9:08,则获取前一天8:08~9:08的销售额
我们可以看到,每天时间段不同,销售额会有很大差异,貌似很难针对当前小时销售额来设置一个阀值,所以我们用跟前一小时环比及跟昨天同时段同比来设置告警阀值,如下图:

4.png

(图三)

图三中分别是同比和环比差额。最终监控告警策略为:环比差额、同比差额低于一定阀值则报警,那么凌晨2点左右可能会有告警通知,但那时候业务也完全不用去管了,正常销售高峰期应该差额都不大的。
通过监控宝的自定义监控能够轻松实现销售额监控告警,当然监控宝暂时不支持自定义报警时段设置,否则还可以针对不同时间段,针对销售额绝对值设置不同告警阀值。例如凌晨不告警,白天分成几个时段分别设置几个最低销售额阀值。

2、销售平均折扣、销售平均客单价
这两个指标都对营销费用有很大影响,业务需要时刻关注,当折扣或客单价大幅降低时,需要马上知晓,曾经不止一家电商都由于系统、人为、第三方平台等原因导致的价格错误,最后要么认亏要么得罪消费者。这两个指标监控很简单,低于某个特定阀值就报警,在此不上图了。但如果订单量非常大时,就算出现有异常折扣订单,可能对整体销售折扣影响不大,这就需要另外设置一个指标:低于3折订单数监控。
其次技术人员是否需要监控业务数据?答案当然是需要的。下面举个我们网店系统运维人员需要监控的两个指标:

5.png

(图四)

网店转单时效 :网店订单支付时间与订单转入作业系统时间之间时效是否达到要求。我们要求订单支付后半小时内必须进入作业系统占用库存并安排发货,我们无论怎么设计这个系统,怎样监控系统的可用性和性能,最终我们仍然需要知道到底是否有漏网之鱼超出时效的,那一定是我们系统设计之初没有预见的。
网店转单性能 :转单程序没分钟转单数量。

这些指标的监控方式都比较简单,关键在于怎么从后端业务系统获取数据。
无论是一线业务运营人员还是系统运维人员根据各自的职责、业务特性都可以设计出很多监控指标,方式都是雷同的,在此不再赘述了。现在问题来了,这么多数据怎么提供给监控宝?
监控宝自定义监控设计地非常灵活,有兴趣去试用下或者看看帮助文档都能轻松掌握,关键是我们后端系统如何提供数据给监控宝呢?下面大致讲下我们监控系统的设计。

6.png

(图五)

第一版的系统设计非常简单,监控宝的数据都通过monitor提供,monitor系统只需要一张表记录各监控指标查询语句,所有的业务数据都直接通过sql查询业务数据库。这个结构随着业务量增加,会导致业务数据库压力越来越大,有些复杂业务监控sql语句执行性能已经不能被接收了,从而演变成下面这种结构:

7.png

(图六)

在监控数据库中根据业务监控指标对销售、商品、库存等指标进行建模,这些数据由业务系统流转过程中抽离出影响指标数据提交给业务数据收集器汇总保存,例如:从网店转单时,将订单的金额、折扣、网店支付时间等数据通过AMQ异步提交给收集器,收集器累计一个时间单元后计算出该时间单元内的总销售额、品均折扣、平均客单价等信息记录在监控库中,为了方便收集器快速配置,需要预先设置几种计算模型:直接保存、汇总、求平均、取最小值、最大值等等。
监控宝作为云智慧面向业务的全栈性能管理解决方案中的一环,与面向业务的端到端应用性能管理平台透视宝,和基于真实业务场景的大规模应用性能测试平台压测宝一起,共同以全面提升企业业务流程为目标,解决用户体验前置和云计算的快速发展带来的系统架构变化的挑战,帮助企业致胜互联网+。

了解更多IT性能监控知识,请关注云智慧官方微信(cloudwise2014)

8.jpg

 

下一代分布式消息系统Apache Kafka

大数据 chris 发表了文章 0 个评论 3304 次浏览 2016-03-18 01:12 来自相关话题

一、开篇思考 消息语义:持久性 安全 淘汰 交付 路由 批量 消息过滤 排队标准 已收通知 IO: ...查看全部
ka1.png


一、开篇思考


ka2.png

消息语义:
持久性 安全 淘汰 交付 路由 批量 消息过滤 排队标准 已收通知
ka3.png

IO:
ka4.png

机械磁盘慢
现代操作系统优化 
    []使用read-ahead和write-behind技术,预读取成块数据,将微小琐碎的逻辑写入组织成一次较大的物理写入[/][]常用空闲内存用作磁盘缓存[/][]线性的访问磁盘,很多时候比随机的内存访问快得多[/]

JVM 2个事实
    []Java对象占用空间非常大,差不多要存储的数据的两倍甚至更高[/][]随着堆中数据量的增加,GC(垃圾回收)变得越来越困难[/]

JVM 1个假设
    []在64G内存的机器上,不得不使用到50G~56G的内存空间[/][]当系统重启的时候,又必须要将数据刷到内存中(每分钟1GB内存),即使冷刷新(在使用数据的时候发现没有再刷到内存)也会导致最初的时候性能非常慢[/]
图解零拷贝
lkb.jpg
lkb2.png
lkb3.png
设计常量复杂度的磁盘操纵B树的复杂度是O(logN),通常被认为就是常量复杂度但对于磁盘操作来说并非如此:磁盘进行一次搜索需要10ms,每个磁盘在同一时间只能进行一次搜索,并发处理困难 对树结构的性能的观察结果表明:其性能往往随着数据的增长而线性下降,数据增长一倍,速度就会降低一倍[list=1][] 线性访问减小磁盘寻道[/][] 压缩数据减小IO压力[/][] 使用零拷贝(zero copy)技术[/]

二、Kafka特性 & 原理

一个高性能分布式(Distribution),可分区(Partitioned),可备份(Replicated),基于Zookeeper协调的发布/订阅消息队列系统
快速持久化
以时间复杂度为O(1)的方式提供消息持久化能力
高吞吐率
在一台普通的服务器上可以达到10W/s级的消息处理
分布式负载均衡
Broker/Producer/Consumer 都支持分布式和负载均衡
水平扩展
支持在线平滑水平扩展
kafka名词解释:[list=1][]Broker & Controller & Producer & Consumer & Consumer Group 2. Topic & Partition & Segment & Offset[/][]Replication & Replication Leader & Replication Follower[/][]Assigned Replications & Preferred Replication[/][]Message & Message Set[/]
wltp.png
主题解析
topic.png
部分文件实现
sfile.png
Broker & Topic Partition
broker.png
消息交付
message.png
zk.png
同步语义[list=1][]每一个Broker节点必须维护和Zookeeper的连接Session,Zookeeper通过心跳机 制检查每个结点的连接 [/][]Follower Broker节点必须及时同步Leader Broker节点,不能落后Leader Broker 节点太多 [/]副本和提交log[list=1][]当且仅当Message被所有的Replication写入到Log中,才算"Committed"[/][]只有Committed的Message,才会被Consumer读取  [/]Persistence & Efficiency [list=1][]每一个Follower都只从Leader Pull数据[/][]每一个Follower收到数据后,立即向Leader发送ACK,而非等到数据写入Log后[/]Consumer  & Partition [list=1][]同一Consumer Group中Consumer竞争Partition,即队列语义 [/][]不同Consumer Group中Consumer共享Partition,即主题语义 [/]消息传递语义[list=1][]At most once - 消息可能会丢,但绝不会重复传输[/][]At least once - 消息绝不会丢,但可能会重复传输[/][]Exactly once - 每一条消息肯定会被传输一次且仅传输一次,理想状态 [/]Leader Election算法 [list=1][]Leader Election[/][]In-Sync Replicas Approach VS. Majority Vote[/][]某一个Partition所有Replication不工作[/]Controller思考 [list=1][]选举Broker Leader最简单最直观的方案[/][]该选举Broker Leader的方案引入了哪些问题 [/]Partition 思考[list=1][]Partition的数据结构,逻辑上/物理上的存储结构[/][]Broker&Topic&Partition关系[/][]Partition&Consumer&Consumer Group关系 [/]Producer思考[list=1][]Load balancing[/][]Asynchronous send[/]Consumer思考[list=1][]Push VS. Pull[/][]Offset归属,存储[/][]触发Partition Rebalance的条件及问题 [/][]减轻了Broker设计的复杂度[/]

三、Kafka设计 & 实现

Broker内部
brokerint.png
Broker故障转移
brokerfa.png
插件删除Topic
datopic.png
LeaderAndIsrRequest 响应
request.png
Partition重新分配案例
partionfp.png
Replication工具[list=1][]Topic Tool[/][]Replica verification Tool[/][]Preferred Replica Leader Election Tool[/][]Kafka Reassign Partitions Tool[/][]State Change Log Merge Tool[/]
Preferred Replica Leader Election Tool
在8个Broker的kafka集群上,创建topic为my_topic,replication-factor为3,partition-factor为8,Partition/Replica分布
etool.png

手动停止Broker 1/2/4,Partition/Replica分布
rptool.png

手动启动Broker 1,Partition/Replica分布
p1tool.png

运行该工具后,Partition/Replica分布
tttool.png

手动启动Broker 2/4,Partition/Replica分布
24tool.png

运行该工具后,Partition/Replica分布
jgtool.png

将Topic的所有Partition重新分配到Broker 4/5/6/7上,初始Partition/Replica分布
4567tool.png

将Topic的所有Partition重新分配到Broker 4/5/6/7上,最终Partition/Replica分布
zztool.png


分享作者:王先明


自动立体化运维监控理念

运维 push 发表了文章 0 个评论 3025 次浏览 2016-03-16 23:47 来自相关话题

场景 客户投诉有问题,于是研发测试运维开始投入定位和分析问题。A 研发去查日志,但是线上机器好多,一台一台的看, 日志文件太大,网速又慢,只能干等......B 研发同学觉得数据库可能有问题,但是自己又不能直接操作数据库,只能找DBA ...查看全部


场景


客户投诉有问题,于是研发测试运维开始投入定位和分析问题。
A 研发去查日志,但是线上机器好多,一台一台的看, 日志文件太大,网速又慢,只能干等......
B 研发同学觉得数据库可能有问题,但是自己又不能直接操作数据库,只能找DBA,但是DBA正好不在......
C 运维同学更头大,一边要应付研发和测试的各种问题,一边还要自己查机器CPU、内存、io、网络、程序 状态,而且还那么多机器


解决方案


这种情况就需要一套“立体化、自动化、可视化的监控”,具体实现如下:
1、立体化
将故障分析和定位时涉及的所有的相关信息都要监控起来,共分为5层
ywc.png

(1)业务层
收集和分析业务层的访问量、成功率等指标,例如当系统被刷的时候,业务层能够一目了然的看出访问量 会增加很多。
(2)应用服务层
以URI为维度的分析,可以看到某个URI的访问量、HTTP响应码分布、HTTP响应时间等指标
应用服务层与业务层并不是一一对应的关系,一个业务可能对应多个应用服务层的URI,一个URI也可能对应多个业务层的业务
(3)接口调用层
接口调用层指的是系统依赖的外部系统接口,收集的信息包括访问情况,包括时延、错误码、次数等,当外部系统故障导致我们的业务故障时,通过接口调用层就能够快速的定位具体问题
(4)基础组件层
基础组件层指系统依赖的底层组件,例如容器、数据库、缓存、消息队列
不同的组件收集的信息不一样,例如数据库MySQL的监控指标包括连接数、请求数、查询行数、更新行数等,而缓存包括 使用率、踢出率、命中率等
(5)基础设施层
基础设施层指操作系统状态、网络状态,收集的信息,包括cpu使用率、内存使用率、网卡流量、连接数等
2、自动化
不要再由人工去分析日志或者执行命令了,而是由程序自动完成这些动作
当故障定位的时候需要这些信息时,可以立即看到,节省故障定位时间
为此我们开发了一套数据收集和分析系统,这套系统可以从其它各个系统(包括业务系统、运维系统等)获取并分析数据,例如日志数据、状态数据等
数据自动化收集和分析系统的结构如下:
Logstash用于采集日志,redis用于缓存日志,elasticsearch用于存储和分析日志
logarch.png

3、可视化
故障定位所需要的信息能够通过图表和数字直观的展示出来
有了自动化的收集和分析作为基础,可视化只需要将数据做成图表展示即可
除此以外,同比、环比这类数据也可以通过系统直观的展示出来,方便快速判断问题所在
ksh.png


内容整理自"面向业务的立体化高可用架构设计"
作者李运华 阿里资深工程师


基于Zookeeper的服务注册与发现案例分析

大数据 空心菜 发表了文章 0 个评论 4238 次浏览 2016-03-16 17:22 来自相关话题

背景 大多数系统都是从一个单一系统开始起步的,随着公司业务的快速发展,这个单一系统变得越来越庞大,带来几个问题: []随着访问量的不断攀升,纯粹通过提升机器的性能来已经不能解决问题,系统无法进行有效的水平扩展[/][]维护 ...查看全部


背景


大多数系统都是从一个单一系统开始起步的,随着公司业务的快速发展,这个单一系统变得越来越庞大,带来几个问题:
    []随着访问量的不断攀升,纯粹通过提升机器的性能来已经不能解决问题,系统无法进行有效的水平扩展[/][]维护这个单一系统,变得越来越复杂[/][]同时,随着业务场景的不同以及大研发的招兵买马带来了不同技术背景的工程师,在原有达达Python技术栈的基础上,引入了Java技术栈。[/]

如何来解决这些问题?业务服务化是个有效的手段来解决大规模系统的性能瓶颈和复杂性。通过系统拆分将原有的单一庞大系统拆分成小系统,它带来了如下好处:
    []原来系统的压力得到很好的分流,有效地解决了原先系统的瓶颈,同时带来了更好的扩展性[/][]独立的代码库,更少的业务逻辑,系统的维护性得到极大的增强[/]

同时,也带来了一系列问题:
    []随着系统服务的越来越多,如何来管理这些服务?[/][]如何分发请求到提供同一服务的多台主机上(负载均衡如何来做)[/][]如果提供服务的Endpoint发生变化,如何将这些信息通知服务的调用方?[/]

最初的解决方案

Linkedin的创始人里德霍夫曼曾经说过:
成立一家初创公司就像把自己从悬崖上扔下来,在降落过程中去组装一架飞机。
这对于初创公司达达也是一样的,业务在以火箭般的速度发展着。技术在业务发展中作用就是保障业务的稳定运行,快速地“组装一架飞机”。所以,在业务服务化的早期,我们采用了Nginx+本地hosts文件的方式进行内部服务的注册与发现,架构图如下:
zknginx.png
各系统组件角色如下:[list=1][]服务消费者通过本地hosts中的服务提供者域名与Nginx的IP绑定信息来调用服务[/][]Nginx用来对服务提供者提供的服务进行存活检查和负载均衡[/][]服务提供者提供服务给服务消费者访问,并通过Nginx来进行请求分发[/]这在内部系统比较少,访问量比较小的情况下,解决了服务的注册,发现与负载均衡等问题。但是,随着内部服务越来愈多,访问量越来越大的情况下,该架构的隐患逐渐暴露出来:
    []最明显的问题是Nginx存在单点故障(SPOF),同时随着访问量的提升,会成为一个性能瓶颈[/][]随着内部服务的越来越多,不同的服务消费方需要配置不同的hosts,很容易在增加新的主机时忘记配置hosts导致服务不能调用问题,增加了运维负担[/][]服务的配置信息分散在各个主机hosts中,难以保持一致性,不便于服务的管理[/][]服务主机的发布和下线需要手工的修改Nginx upstream配置,修改的配置需要上线,不利于服务的快速部署[/]

如何解决

在谈如何来解决之前,现梳理一下服务注册与发现的目标:
    []服务的注册信息应该统一保存,方便于服务的管理[/][]自动通过服务的名称去发现服务,而不必了解这个服务提供的end-point到底是哪台主机[/][]支持服务的负载均衡及fail-over[/][]增加或移除某个服务的end-point时,对于服务的消费者来说是透明的[/][]支持Python和Java[/]
备选方案一: DNS
DNS作为服务注册发现的一种方案,它比较简单。只要在DNS服务上,配置一个DNS名称与IP对应关系即可。定位一个服务只需要连接到DNS服务器上,随机返回一个IP地址即可。由于存在DNS缓存,所以DNS服务器本身不会成为一个瓶颈。
这种基于Pull的方式不能及时获取服务的状态的更新(例如:服务的IP更新等)。如果服务的提供者出现故障,由于DNS缓存的存在,服务的调用方会仍然将请求转发给出现故障的服务提供方;反之亦然。
备选方案二:DubboDubbo是阿里巴巴推出的分布式服务框架,致力于解决服务的注册与发现,编排,治理。它的优点如下:[list=1][]功能全面,易于扩展[/][]支持各种序列化协议(JSON,Hession,java序列化等)[/][]支持各种RPC协议(HTTP,Java RMI,Dubbo自身的RPC协议等)[/][]支持多种负载均衡算法[/][]其他高级特性:服务编排,服务治理,服务监控等[/]缺点如下:[list=1][]只支持Java,对于Python没有相应的支持[/][]虽然已经开源,但是没有成熟的社区来运营和维护,未来升级可能是个麻烦[/][]重量级的解决方案带来新的复杂性[/]备选方案三:ZookeeperZookeeper是什么?按照Apache官网的描述是:
ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.
参照官网的定义,它能够做:[list=1][]作为配置信息的存储的中心服务器[/][]命名服务[/][]分布式的协调[/][]Mater选举等[/]在定义中特别提到了命名服务。在调研之后,Zookeeper作为服务注册与发现的解决方案;它有如下优点:[list=1][]它提供的简单API[/][]已有互联网公司(例如:Pinterest,Airbnb)使用它来进行服务注册与发现[/][]支持多语言的客户端[/][]通过Watcher机制实现Push模型,服务注册信息的变更能够及时通知服务消费方[/]缺点是:[list=1][]引入新的Zookeeper组件,带来新的复杂性和运维问题[/][]需自己通过它提供的API来实现服务注册与发现逻辑(包含Python与Java版本)[/]针对对上述几个方案的优缺点权衡之后,决定采用了基于Zookeeper实现自己的服务注册与发现。

基于Zookeeper的服务注册与发现架构

zkregsine.png
在此架构中有三类角色:服务提供者,服务注册中心,服务消费者。服务提供者服务提供者作为服务的提供方将自身的服务信息注册到服务注册中心中。服务信息包含:
    []隶属于哪个系统[/][]服务的IP,端口[/][]服务的请求URL[/][]服务的权重等等[/]
服务注册中心服务注册中心主要提供所有服务注册信息的中心存储,同时负责将服务注册信息的更新通知实时的Push给服务消费者(主要是通过Zookeeper的Watcher机制来实现的)。服务消费者服务消费者主要职责如下:[list=1][]服务消费者在启动时从服务注册中心获取需要的服务注册信息[/][]将服务注册信息缓存在本地[/][]监听服务注册信息的变更,如接收到服务注册中心的服务变更通知,则在本地缓存中更新服务的注册信息[/][]根据本地缓存中的服务注册信息构建服务调用请求,并根据负载均衡策略(随机负载均衡,Round-Robin负载均衡等)来转发请求[/][]对服务提供方的存活进行检测,如果出现服务不可用的服务提供方,将从本地缓存中剔除[/]
服务消费者只在自己初始化以及服务变更时会依赖服务注册中心,在此阶段的单点故障通过Zookeeper集群来进行保障。在整个服务调用过程中,服务消费者不依赖于任何第三方服务。

实现机制介绍​

Zookeeper数据模型介绍在整个服务注册与发现的设计中,最重要是如何来存储服务的注册信息。在设计基于Zookeeper的服务注册结构之前,我们先来看一下Zookeeper的数据模型。Zookeeper的数据模型如下图所示:
zluo.png
Zookeeper数据模型结构与Unix文件系统很类似,是一个树状层次结构。每个节点叫做Znode,节点可以拥有子节点,同时允许将少量数据存储在该节点下。客户端可以通过监听节点的数据变更和子节点变更来实时获取Znode的变更(Wather机制)。
服务注册结构
dd.png
服务注册结构如上图所示。
    []/dada来标示公司名称dada,同时能方便与其它应用的目录区分开(例如:Kafka的brokers注册信息放置在/brokers下)[/][]/dada/services将所有服务提供者都放置该目录下[/][]/dada/services/category1目录定义具体的服务提供者的id:category1,同时该Znode节点中允许存放该服务提供者的一些元数据信息,例如:名称,服务提供者的Owner,上下文路径(Java Web项目),健康检查路径等。该信息可以根据实际需要进行自由扩展。[/][]/dada/services/category1/helloworld节点定义了服务提供者category1下的一个服务:helloworld。其中helloworld为该服务的ID,同时允许将该服务的元数据信息存储在该Znode下,例如图中标示的:服务名称,服务描述,服务路径,服务的调用的schema,服务的调用的HTTP METHOD等。该信息可以根据实际需要进行自由扩展。[/][]/dada/services/category1/helloworld/providers节点定义了服务提供者的父节点。在这里其实可以将服务提供者的IP和端口直接放置在helloworld节点下,在这里单独放一个节点,是为了将来可以将服务消费者的消息挂载在helloworld节点下,进行一些扩展,例如命名为:/dada/services/category1/helloworld/consumers。[/][]/dada/services/category__1/helloworld/providers/192.168.1.1:8080该节点定义了服务提供者的IP和端口,同时在节点中定义了该服务提供者的权重。[/]

实现机制

由于目前服务注册通过我们的服务注册中心UI来进行注册,这部分逻辑比较简单,即通过UI界面来构造上述定义的服务注册结构。下面着重介绍一下我们的服务发现是如何工作的:
lj.png
在上述类图中,类ServiceDiscovery主要通过Zookeeper的API(Python/Java版本)来获取服务信息,同时对服务注册结构中的每个服务的providers节点增加Watcher,来监控节点变化。获取的服务注册信息保存在变量service_repos中。通过在初始化时设置LoadBalanceStrategy的实现(Round-Robin算法,Radmon算法)来实现服务提供者的负载均衡。主要方法:[list=1][]init获取Zookeeper的服务注册信息,并缓存在service_repos[/][]get_service_repos方法获取实例变量service_repos[/][]get_service_endpoint根据init构建好的service_repos,以及lb_strategy提供的负载均衡策略返回某个服务的URL地址[/][]update_service_repos通过Zookeeper的Watcher机制来实时更新本地缓存service_repos[/][]heartbeat_monitor是一个心跳检测线程,用来进行服务提供者的健康存活检测,如果出现问题,将该服务提供者从该服务的提供者列表中移除;反之,则加入到服务的提供者列表中[/]
LoadBalanceStrategy定义了根据服务提供者的信息返回对应的服务Host和IP,即决定由那台主机+端口来提供服务。
RoundRobinStrategy和RandomStrategy分别实现了Round-Robin和随机的负载均衡算法


未来展望


目前达达基于Zookeeper的服务注册与发现的架构还处于初期,很多功能还未完善,例如:服务的路由功能,与部署平台的集成,服务的监控等等。
当然基于Zookeeper还能做其它许多事情,例如:实时动态配置系统。目前,我们已经基于Zookeeper实现了实时动态配置系统。


分享原文地址:https://tech.imdada.cn/2015/12/03/service-registry-and-discovery-with-zk/
作者:杨 骏  达达CTO


学习python的几个好习惯

编程 being 发表了文章 0 个评论 2583 次浏览 2016-03-15 23:33 来自相关话题

随着Python在国内的发展,特别是在自动化运维领域,运维开发者99%使用python开发自动化运维平台;在软件行业里面使用python编程语言的公司会越来越多,那么在学习Python的过程中需要养成几个好习惯。下面我给大家分享几条: ...查看全部
随着Python在国内的发展,特别是在自动化运维领域,运维开发者99%使用python开发自动化运维平台;在软件行业里面使用python编程语言的公司会越来越多,那么在学习Python的过程中需要养成几个好习惯。
下面我给大家分享几条:


缩进


由于跟其他编程语言的区别性,缩进在python编程中显得十分重要;在Python的代码块中必须使用相同数目的行首缩进空格数,否则会造成脚本运行错误,提示你格式不正确之类的信息。因此,在使用python语言写脚本的时候,保证缩进的一致性相当重要。
sj.jpg


空格


虽然在python编程过程中,空行并不是Python语法的必需部分,但是,保持函数之间或类的方法之间用空行分隔,可以使得代码看起来更加清晰明了,也有利于后期的代码维护或重构。

kge.jpg


注释


注释相对经常使用编程语言的人来说应该不是很陌生吧,主要因为注释不仅使得阅读代码的人容易理解,也让代码作者更好地定位代码函数等。python跟其它语言一样,注释在一些该注释的地方,可以让效率事半功倍。
zs.jpg


源代码


python作为完全开源的语言,代码对于任何人都可以随意浏览。这种方式可以更好地帮助人们发现有利精简扼要的代码,在很多方面可以省去不必要的时间,因为觉得合适可以直接拿过来使用或者简单修改。经常看一下好的源代码,不仅会让你学习别人的编程方式,还在另一方面大大的帮助你更好地学习。


编程思想


使用任何一门编程语言,都需要保持很好的编程思想,对python来说也是一样的。学会创造使用适合自己的编程思想是至关重要的,因此,去多读一些讲解编程思想之类的书籍来充实自己吧。
bcsx.png


多实践


学习任何一门编程语言都需要多做多写多看,通过不同的项目,来让自己得到更好的锻炼,相信是一件很棒的事情。在业余时间,经常的去敲写一些代码,也是很有意思的。
jdit.png


兴趣


兴趣是成功的一半,兴趣促使你更好地去使用学习编程语言,而不单单为了忙碌的工作。很多创造出编程语言的人来说,正时因为兴趣的使然,才成就了如此好的一些编程语言。
xq.png

不懂编程的运维人员到底还能走多远?

科技前沿 空心菜 发表了文章 0 个评论 3738 次浏览 2016-03-12 23:33 来自相关话题

首先,可以肯定的说,未来的IT岗位需要的是综合能力强的人员,运维、开发、数据库、网络,技术岗位对上述知识体系都要会一些,才能很好的胜任对应岗位工作。  下面已经不是趋势,而是菜鸟及老鸟都必须要认真考虑的: []运维人员要会运维、开发、数 ...查看全部
首先,可以肯定的说,未来的IT岗位需要的是综合能力强的人员,运维、开发、数据库、网络,技术岗位对上述知识体系都要会一些,才能很好的胜任对应岗位工作。
 
下面已经不是趋势,而是菜鸟及老鸟都必须要认真考虑的:
    []运维人员要会运维、开发、数据库、网络,但侧重点是运维,[/][]开发人员要会运维、开发、数据库、网络,但侧重点是开发,[/][]数据库人员要会运维,开发,数据库,网络,但侧重点是数据库,[/][]网络人员要会运维,开发,数据库,网络,但侧重点是网络,最好侧重点转运维,[/][]硬件工程师(F5,存储设备等)建议趁早转岗linux运维,云计算已经把硬件给灭了,硬件集中化了。[/]

只会技术知识还不够,工作态度,做人素质,沟通表达,责任心都是具备核心竞争力的容易被忽略的资本!
技术知识和态度素质比例接近6:4,岗位越高对技术要求的比例越低!
互联网,移动互联网,甚至是物联网的时代对IT人才的综合能力要求越来越高!一些极其低端的工作大多数人的岗位会被自动化、虚拟化、云计算、甚至是机器人取代是毫不夸张的!
例如:IDC机房运维,低端网络工程师,各类硬件工程师。
新的时代对我们IT人员有了新的挑战,我们不能抱残守缺,而一定要快速学习,适应时代对我们的更多要求,不要本位主义,单纯的认为运维就不需要开发,开发就不需要运维,这些想法都是在重复掩耳盗铃的寓言故事。
就拿老男孩老师本人来说吧,除了会开发、运维、网络、数据库能力外,还要会讲课、教育学、心理学、销售、市场、领导、演讲,管理、财务、法律等技能,当然了,我给自己的定位是教育企业的老板,大家如果学习运维,给自己的定位是高级运维或架构师,就必须要会linux运维,python开发,linux集群架构。
另外,强烈建议,想从事linux运维的朋友一定要先掌握好运维岗位需要的本领后,然后再去蚕食开发领域。想从事开发的朋友一定要先掌握好开发岗位需要的本领后,然后再去蚕食运维等领域。
切记,一定不要太浮躁,人云亦云,一定不要边玩linux,边玩开发,一个时间点专注一点,你就可以更快找到工作,找到工作后再去利用周末去培训或自学,除非你参加脱产班的培训,或者时间真的很充裕。
掌握了一项岗位的知识能力后,如果你真的掌握了的话,再学其它岗位技术的也会轻松很多,因为学习的方法都是相通的。
一定要先掌握你想从事的本领域的岗位的基本本领,短时间千万不要样样都了解,会导致样样都稀松,最后找工作到处碰壁,短时间就是抓重点(记得我讲的浴室着火吧)!
虽然企业对运维的岗位要求趋势是越来越高了,但也不代表只学一种找不到工作。
对于新手,是无法再短时间内掌握运维和开发两项本领的,哪怕即使是运维知识也是海量,学了前面的,忘了后面的网友满地都是,最后厌学,能力没提升,给自己带来困扰。
例如你想从事运维,可以先学好linux运维,适当了解python开发,然后,找到工作后,再利用周末去学习。老男孩教育linux运维班新班会精讲shell和python开发基础,很多同学月薪可以达到12-13K,这个事实说明,先精通一门技术的重要性,但是一旦拿到offer,我们就会告诉学生要参加学习python开发以及高级架构师课程,说到这大家都明白了吧,linux运维,linxu架构,python开发,都是运维岗位需要的,打好linux基础,可以找到工作,但是要想立足和发展就必须要学习linux网站集群架构,python开发,这是现实的行业内的人都看得出的趋势,不这样努力这样做的,就算找到了工作可能也会丢失掉,谈不上立足和发展了。
如果你想从事开发工作也是一样,可以先学好开发,然后再去学linux运维+linux架构。(学历达不到本科的同学,如果选择纯开发一定要慎重,衡量下自己适合不适合,能不能下足功夫和高学历的去拼,开发领域的竞争者大把的本科、硕士的人群,而运维领域本科的同学基本上是凤毛麟角,这也是老男孩老师当初差异化发展的思想,虽然老男孩是本科双学士)。
新手一旦考虑学习开发,我建议可以学习python全栈开发,差异化发展,未来做开发做运维可以有更多的选择,而不是去选择PHP,JAVA等开发语言。
综上,解答开篇的不懂编程的运维还能走多远?
    []linux(含shell)已成为IT技术岗位的必备的技术(开发,数据库,网络等岗)。[/][]linux运维学好目前北上广的薪水可以到8-15K,但是如果不快速继续深入高级架构师和python开发,未来发展瓶颈十分大,时间久了,有可能上升空间就被会架构又会python开发的人堵死,刻不容缓。[/][]python已成为IT技术岗位发展提升竞争力的必备技术(开发,数据库,网络等岗)。[/][]linux高级架构师(大规模网站集群架构)也将成为IT技术岗位发展提升竞争力的必备技术(开发,数据库,网络等岗)。[/]

 
因此,linux运维+linux架构+python开发这三项技术是近3-5年运维人员必备的技术,也是纯开发提升竞争力最有利的武器。
掌握上述三项技术的先后顺序可以为:
linux运维+linux架构或linux运维+python开发,这三项技术是有紧密联系的,高级运维及架构师发展都得会!
有关运维人员的开发语言,做运维的人员一定要放弃小众语言的学习,例如perl,ruby,也不要选择偏离linux运维的php和JAVA。
linux+(shell/python)是当下最火的运维人员学习的组合,跟着趋势准没错!
如果学习纯开发可以选的语言有:python,php,java,但是这些开发岗位发展到1-2年后,还是需要学习linux运维+linux架构的,这就是所说的大一统的IT岗位技能要求趋势。
总结:
掌握了上述运维和开发本领后,将来还可以朝大数据、云计算等热门领域过渡,基础不牢地动山摇,没有运维和开发基础,大数据、云计算这样的空中楼阁,你就有看和想的份。


文章作者:老男孩教育创始人老男孩老师
分享原文:http://oldboy.blog.51cto.com/2561410/1749513


数人云-下一代DCOS

科技前沿 OpenSkill 发表了文章 0 个评论 3851 次浏览 2016-03-12 01:35 来自相关话题

公司简介 数人科技隶属于北京数字世纪科技有限公司,由原 Google 架构师王璞博士于2014年创立,其核心团队来自于 Google、RedHat 和 HP。数人科技致力于打造下一代 DCOS 数人云,将应用弹性做到极致。“数人云”是 ...查看全部


公司简介


数人科技隶属于北京数字世纪科技有限公司,由原 Google 架构师王璞博士于2014年创立,其核心团队来自于 Google、RedHat 和 HP。数人科技致力于打造下一代 DCOS 数人云,将应用弹性做到极致。
“数人云”是一款部署在公有云、私有云以及混合云之上的 DCOS(Data Center Operating System ),旨在帮助用户在云端快速建立并稳定运行一个高性能生产环境,将应用弹性做到极致,实现一站式的微服务架构集群系统。
基于领先的 Mesos 和 Docker 技术,数人云可为用户的业务系统带来高可用的服务质量,快速的性能伸缩,高效的资源利用以及便捷的可视化管理和监控;同时,数人云保证用户的计算资源和数据完全为用户私有可控。


数人Team


著名天使投资人徐小平曾经说过,有三种人他不会投资,其中就有一种就是没有"合作伙伴"的情况。因为在没有合伙人的情况下是创始人股权一家独大,而普通员工和领导是没有绝对的股权分配的,当创业公司遇到困难的情况下,这种没有合伙人的体制创业公司是很少有人和创始人一起度过难关的。而你拥有合伙人的创业团队,股权分配合理,当公司遇到一定困难的情况下,大家都是设法一起度过难关,为公司的发展做出贡献的,这样的创业公司更容易成功,相反没有创业合伙人的团队一般拿到投资后也撑不了多久!
datamanteam.png


公司产品


目前数人科技产品只有"数人云"。数人云是一套基于开源Mesos + Doker技术的DCOS(数据中心操作系统)。将应用弹性做到极致的轻量PaaS平台,使用数人云DCOS,可像用单机电脑一样管理集群和云端应用,一键伸缩,满足业务快速增长需求,一键部署Docker容器应用和Spark等分布式应用,快速搭建微服务和大数据生产环境。
产品特点如下:
一键伸缩
yjss.png

资源池化
zych.png

混合云管理
hhygl.png

一键部署
yjbsh.png

简化运维
jhywei.png

服务高可用
fwgky.png

产品Demo地址:https://dashboard.shurenyun.com/home
效果图:
demo.png


五大场景解决方案


高并发
大数据云计算时代,企业的生产环境都要求高并发处理业务,让用户体验达到极致。

gbfa.png

容器云
容器的诞生,提升了系统资源的高利用率和微服务架构的优越性发挥到极致,服务高效运转,让Auto Scaling变得更轻巧和简便。
rqy.png

持续集成
持续集成已经成为企业开发体制中一个快速迭代的先决条件,可以高效的促进开发者之间的合作开发效率和产品迭代速率。
cxjc.png

大数据处理平台
大数据时代,大数据处理平台的搭建、管理、维护给运维人员带来了很大的维护成本和学习成本,数人云可以快速部署和管理。
dsjclpt.png

企业应用平台
大数据应用的普及和分布式应用的架构深入企业中心,让企业平台的构建带来阻力,数人云完全Docker化应用,可以让你快熟Build。
dsjyy.png

解决方案:
数人云行业解决方案已经涉及:金融、互联网、生物信息、电商、运营商、能源。期待数人的发展和潜力,适配更多场景和行业为IT Worker、企业带来更多的便捷和利益!
行业解决方案详情介绍请转战:https://www.shurenyun.com/ 


融资情况和媒体报道


数人云获3000万元A轮融资,打造轻量级PaaS平台发挥应用弹性。
媒体报道如下:
http://36kr.com/p/5043988.html
http://tech.sina.com.cn/it/2016-03-02/doc-ifxpvysx1840192.shtml
http://tech.163.com/16/0302/15/BH5OJ7SN000915BF.html
http://www.techweb.com.cn/network/virtual/2016-03-02/2288655.shtml


招聘信息-期待你的加入


job1.png

job2.png

详情请转战拉钩:http://www.lagou.com/gongsi/j37868.html
刚融完资本,数人应该不差钱了,有找工作的伙伴可以投递你优秀的简历加入数人这个优秀的团队,数人值得你加入!


结语


在国家政治支持的创客时代,希望数人科技可以认准自己的方向一路向前,走在容器创业行列的前端,希望数人科技越来越好给行业带来更多推动力和正能量!

创客报:开源技术社区下面的一个子频道,每周给你推荐优秀的创业公司和团队,让你更了解互联网创业!

ZooKeeper架构设计及其应用

运维 chris 发表了文章 0 个评论 8961 次浏览 2016-03-11 23:45 来自相关话题

ZooKeeper是一个开源的分布式服务框架,它是Apache Hadoop项目的一个子项目,主要用来解决分布式应用场景中存在的一些问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置管理等,它支持Standalone模式和分布式模式,在分布式模式下 ...查看全部
ZooKeeper是一个开源的分布式服务框架,它是Apache Hadoop项目的一个子项目,主要用来解决分布式应用场景中存在的一些问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置管理等,它支持Standalone模式和分布式模式,在分布式模式下,能够为分布式应用提供高性能和可靠地协调服务,而且使用ZooKeeper可以大大简化分布式协调服务的实现,为开发分布式应用极大地降低了成本。


总体架构​


ZooKeeper分布式协调服务框架的总体架构,如图所示:
zk1.png
ZooKeeper集群由一组Server节点组成,这一组Server节点中存在一个角色为Leader的节点,其他节点都为Follower。当客户端Client连接到ZooKeeper集群,并且执行写请求时,这些请求会被发送到Leader节点上,然后Leader节点上数据变更会同步到集群中其他的Follower节点。
Leader节点在接收到数据变更请求后,首先将变更写入本地磁盘,以作恢复之用。当所有的写请求持久化到磁盘以后,才会将变更应用到内存中。
ZooKeeper使用了一种自定义的原子消息协议,在消息层的这种原子特性,保证了整个协调系统中的节点数据或状态的一致性。Follower基于这种消息协议能够保证本地的ZooKeeper数据与Leader节点同步,然后基于本地的存储来独立地对外提供服务。
当一个Leader节点发生故障失效时,失败故障是快速响应的,消息层负责重新选择一个Leader,继续作为协调服务集群的中心,处理客户端写请求,并将ZooKeeper协调系统的数据变更同步(广播)到其他的Follower节点。


设计要点


ZooKeeper是基于如下4个目标来进行权衡和设计的,我们从设计及其特性的角度来详细说明:
    []简单[/]
分布式应用中的各个进程可以通过ZooKeeper的命名空间(Namespace)来进行协调,这个命名空间是共享的、具有层次结构的,更重要的是它的结构足够简单,像我们平时接触到的文件系统的目录结构一样容易理解,如图所示:
zk2.png
在ZooKeeper中每个命名空间(Namespace)被称为ZNode,你可以这样理解,每个ZNode包含一个路径和与之相关的元数据,以及继承自该节点的孩子列表。与传统文件系统不同的是,ZooKeeper中的数据保存在内存中,实现了分布式同步服务的高吞吐和低延迟。
[list=1][]在上图示例的ZooKeeper的数据模型中,有如下要点:[/][list=1][]每个节点(ZNode)中存储的是同步相关的数据(这是ZooKeeper设计的初衷,数据量很小,大概B到KB量级),例如状态信息、配置内容、位置信息等。[/][]一个ZNode维护了一个状态结构,该结构包括:版本号、ACL变更、时间戳。每次ZNode数据发生变化,版本号都会递增,这样客户端的读请求可以基于版本号来检索状态相关数据。[/][]每个ZNode都有一个ACL,用来限制是否可以访问该ZNode。[/][]在一个命名空间中,对ZNode上存储的数据执行读和写请求操作都是原子的。[/][]客户端可以在一个ZNode上设置一个监视器(Watch),如果该ZNode数据发生变更,ZooKeeper会通知客户端,从而触发监视器中实现的逻辑的执行。[/][]每个客户端与ZooKeeper连接,便建立了一次会话(Session),会话过程中,可能发生CONNECTING、CONNECTED和CLOSED三种状态。[/][]ZooKeeper支持临时节点(Ephemeral Nodes)的概念,它是与ZooKeeper中的会话(Session)相关的,如果连接断开,则该节点被删除。[/
    []冗余[/]
ZooKeeper被设计为复制集群架构,每个节点的数据都可以在集群中复制传播,使集群中的每个节点数据同步一致,从而达到服务的可靠性和可用性。前面说到,ZooKeeper将数据放在内存中来提高性能,为了避免发生单点故障(SPOF),支持数据的复制来达到冗余存储,这是必不可少的。
    []有序[/]
ZooKeeper使用时间戳来记录导致状态变更的事务性操作,也就是说,一组事务通过时间戳来保证有序性。基于这一特性。ZooKeeper可以实现更加高级的抽象操作,如同步等。
    []快速[/]
ZooKeeper包括读写两种操作,基于ZooKeeper的分布式应用,如果是读多写少的应用场景(读写比例大约是10:1),那么读性能更能够体现出高效。

数据模型

ZooKeeper有一个分层的命名空间,结构类似文件系统的目录结构,非常简单而直观。其中,ZNode是最重要的概念,前面我们已经描述过。另外,有ZNode有关的还包括Watches、ACL、临时节点、序列节点(Sequence Node)。
    []ZNode结构[/]
ZooKeeper中使用Zxid(ZooKeeper Transaction Id)来表示每次节点数据变更,一个Zxid与一个时间戳对应,所以多个不同的变更对应的事务是有序的。下面是ZNode的组成结构,引用文档如下所示:[list=1][]czxid – The zxid of the change that caused this znode to be created.[/][]mzxid – The zxid of the change that last modified this znode.[/][]ctime – The time in milliseconds from epoch when this znode was created.[/][]mtime – The time in milliseconds from epoch when this znode was last modified.[/][]version – The number of changes to the data of this znode.[/][]cversion – The number of changes to the children of this znode.[/][]aversion – The number of changes to the ACL of this znode.[/][]ephemeralOwner – The session id of the owner of this znode if the znode is an ephemeral node. If it is not an ephemeral node, it will be zero.[/][]dataLength – The length of the data field of this znode.[/][]numChildren – The number of children of this znode.[/]
    []Watches(监视)[/]
ZooKeeper中的Watch是只能触发一次。也就是说,如果客户端在指定的ZNode设置了Watch,如果该ZNode数据发生变更,ZooKeeper会发送一个变更通知给客户端,同时触发设置的Watch事件。如果ZNode数据又发生了变更,客户端在收到第一次通知后没有重新设置该ZNode的Watch,则ZooKeeper就不会发送一个变更通知给客户端。
ZooKeeper异步通知设置Watch的客户端。但是ZooKeeper能够保证在ZNode的变更生效之后才会异步地通知客户端,然后客户端才能够看到ZNode的数据变更。由于网络延迟,多个客户端可能会在不同的时间看到ZNode数据的变更,但是看到变更的顺序是能够保证有序一致的。
ZNode可以设置两类Watch,一个是Data Watches(该ZNode的数据变更导致触发Watch事件),另一个是Child Watches(该ZNode的孩子节点发生变更导致触发Watch事件)。调用getData()和exists() 方法可以设置Data Watches,调用getChildren()方法可以设置Child Watches。调用setData()方法触发在该ZNode的注册的Data Watches。调用create()方法创建一个ZNode,将触发该ZNode的Data Watches;调用create()方法创建ZNode的孩子节点,则触发ZNode的Child Watches。调用delete()方法删除ZNode,则同时触发Data Watches和Child Watches,如果该被删除的ZNode还有父节点,则父节点触发一个Child Watches。
另外,如果客户端与ZooKeeper Server断开连接,客户端就无法触发Watches,除非再次与ZooKeeper Server建立连接。
    []Sequence Nodes(序列节点)[/]
在创建ZNode的时候,可以请求ZooKeeper生成序列,以路径名为前缀,计数器紧接在路径名后面,例如,会生成类似如下形式序列:
qn-0000000001, qn-0000000002, qn-0000000003, qn-0000000004, qn-0000000005, qn-0000000006, qn-0000000007
    []ACLs(访问控制列表)[/]
ACL可以控制访问ZooKeeper的节点,只能应用于特定的ZNode上,而不能应用于该ZNode的所有孩子节点上。它主要有如下五种权限:[list=1][]CREATE 允许创建Child Nodes[/][]READ 允许获取ZNode的数据,以及该节点的孩子列表[/][]WRITE 可以修改ZNode的数据[/][]DELETE 可以删除一个孩子节点[/][]ADMIN 可以设置权限[/]ZooKeeper内置了4种方式实现ACL:[list=1][]world 一个单独的ID,表示任何人都可以访问[/][]auth 不使用ID,只有认证的用户可以访问[/][]digest 使用username:password生成MD5哈希值作为认证ID[/][]ip 使用客户端主机IP地址来进行认证[/]
    []ZooKeeper Session[/]

当客户端连接到ZooKeeper集群时,建立了会话。会话过程中的状态变迁,如图所示:
zk3.png
建立连接过程中,会话状态为CONNECTING;当连接建立成功后,会话状态变为CONNECTED。会话过程中,如果正常的话,会话的状态只能是CONNECTING和CONNECTED二者之一。如果在会话过程中连接断开,则变为CLOSED状态。


应用陷阱


并非任何分布式应用都适合使用ZooKeeper来构建协调服务,我们根据ZooKeeper提供的文档,给出哪些情况下使用会出现问题,又是如何应对这种问题的。总结如下:
1、丢失ZNode上的变更通知
客户端连接到ZooKeeper Server以后,会维护一个TCP连接。在CONNECTED状态下,客户端设置了某个ZNode的Watch监听器,可以收到来自该节点变更的通知(后续会触发一定的逻辑执行流程)。但是,如果由于网络异常,客户端断开了与ZooKeeper Server的连接,在断开的过程中,是无法收到ZooKeeper在ZNode上发送的节点数据变更通知的。
所以,如果使用ZooKeeper的Watch,必须要寻找保持CONNECTED的Watch,才能保证不会丢失该Watch监控的ZNode上的数据变更通知。
2、无效ZooKeeper集群节点列表​
与ZooKeeper集群交互时,一般情况下客户端会持有一个ZooKeeper集群节点的列表,或者列表的子集,那么会存在如下两种情况:
一种情况是,如果客户端持有的列表或者列表子集,其中节点都处于Active状态,能够提供协调服务,那么客户端访问ZooKeeper集群没有任何问题。
另一种情况,客户端持有ZooKeeper集群节点列表或列表子集,如果列表中的某些节点因为故障退出了集群,如果客户端再次连接这一类失效的节点,就无法获取服务。
所以,我们在应用中使用ZooKeeper集群时,一定要明确这一点,或者跳过无效的节点,或者重新寻找有效的节点继续业务处理,或者检查ZooKeeper集群,使整个集群恢复正常。
3、配置导致的性能问题
如果设置Java堆内存(Heap)不合理,会导致ZooKeeper内存不足,会在内存与文件系统之间进行数据交换,导致ZooKeeper的性能极大地下降,从而可能会影响应用程序。
为了避免Swapping问题的出现,主要考虑设置足够的Java堆内存,同时减少被操作系统和Cache使用的内存,尽量避免在内存与文件系统之间发生数据交换,或者可以将交换限制在一定的范围之内。
4、事务日志存储设备性能​
ZooKeeper会同步事务到存储设备,如果存储设备不是专用的,而是和其他I/O密集型应用共享同一磁盘,会导致ZooKeeper的效率。因为客户端请求ZNode数据变更而发生的事务,ZooKeeper会在响应之前将事务日志写入存储设备,如果存储设备是专用的,那么整个服务以至外部应用都会获得极大地性能提升。
5、ZNode存储大量数据导致性能问题​
ZooKeeper的设计初衷是,每个ZNode只存放少量的同步数据,如果存储了大量数据,导致ZooKeeper每次节点发生变更时需要将事务写入存储设备,同时还要在集群内部复制传播,这将导致不可避免的延迟和性能问题。
所以,如果需要与大量的数据相关,可以将大量数据存储在其他设备中,而只是在ZooKeeper中存储一个简单的映射,如指针、引用等等。

 
参考链接:
http://zookeeper.apache.org/ 
http://zookeeper.apache.org/doc/r3.3.4/zookeeperOver.html 
http://wiki.apache.org/hadoop/ZooKeeper/PoweredBy 
http://www.ibm.com/developerworks/cn/opensource/os-cn-zookeeper/ 
http://zookeeper.apache.org/doc/r3.3.4/recipes.html 
http://zookeeper.apache.org/doc/r3.3.4/zookeeperProgrammers.html

创业公司技术架构详解

运维 Rock 发表了文章 0 个评论 3498 次浏览 2016-03-10 23:06 来自相关话题

提纲 []产品[/][]技术[/][]数据[/][]运维[/]创业核心:以产品为核心团队人数:初创团队人数控制在10人以下,最佳是5,6人左右 技术选型:成熟技术,简洁高效解决问题 目标:快速完成beta 版本上线产品中心[list= ...查看全部


提纲


    []产品[/][]技术[/][]数据[/][]运维[/]

创业

核心:以产品为核心
团队人数:初创团队人数控制在10人以下,最佳是5,6人左右 
技术选型:成熟技术,简洁高效解决问题 
目标:快速完成beta 版本上线

产品中心

[list=1][]Axure做产品原型;[/][]直接画草图 [/]
一切以简单为指标,能说明问题就行。

语言框架

[list=1][]linux+apache(nginx)+mysql+php(CodeIgniter ,Symfony...) [/][]uwsgi+python(Django,Tornado,Pyramid...) [/][]mongodb+nodejs(Express...)[/][]java[/]

十万级PV

二台机器部署系统,传统web系统,LAMP。
bw.png

百万PV

bbw.png

移动系统问题

[list=1][]与传统web相比,移动出现多版本(1.0,2.0,3.0...),以及版本升级问题[/][]网络不稳定(3g,wifi)[/]

开源软件

负载均衡:lvs、haproxy、nginx
前端缓存代理:squid、varnish、ATS
web server :apache、nginx、Tomcat
cache:memcached、redis 
关系型数据库:mysql、postgresql 
文档型数据库:mongodb 
nosql:Tokyo Cabinet、leveldb
全文检索:sphinx、lucene、solr 
分布式搜索引擎:elasticsearch 
中文分词:mmseg、ictclas
爬虫采集:scrapy
监控系统:nagios、cacti、zabbix 、Ganglia
推荐系统:mahout
消息队列:: zeroMQ、RabbitMQ、Kafka
异步作业队列:gearman 
分布式文件系统:fastdfs、moosefs 
项目管理:JIRA
知识共享:wiki、Confluence
代码管理:git、svn
移动统计数据:countly 
分布式计算存储:mapreduce、hadoop
还有好多好多,就不一一介绍了!

移动初始架构

mobarch.png
cd.png
insearch.png

统计数据可视化和推荐系统

view.png

监控

monitor.png

架构感悟

[list=1][]没有一层不变的架构,随着业务发展而变化 [/][]业务不同,架构不同,发现问题解决问题 [/][]保持简洁[/][]易于扩展,容错[/]