zoukankan      html  css  js  c++  java
  • 一个轻client,多语言支持,去中心化,自己主动负载,可扩展的实时数据写服务的实现方案讨论

    背景

    背景是设计一个实时数据接入的模块,负责接收client的实时数据写入(如日志流,点击流),数据支持直接下沉到HBase上(兴许提供HBase上的查询),或先持久化到Kafka里。方便兴许进行一些计算和处理,再下沉到文件系统或做别的输出。


    在设计中,对于client和服务端有这么些目标。

    client须要支持多语言(Java。C++),做得尽量轻量级。仅仅要连上服务端的ip:port。以RPC的形式调用简单的write就能够把数据写出去。client不承担不论什么逻辑的处理。服务端的负载均衡对client是透明的。

    服务端想要做的是一个去中心化的节点集群,节点之间汇报各自的负载情况,每一个节点能知道全局的负载情况,在接收client的连接请求的时候。能返回负载合适的节点让client往目标节点写。另外,服务端能容忍高并发的写入操作。某节点挂掉后要能让client选择新的低负载节点,不影响client的数据写入。

    服务端对业务系统的接入配置记录在DB里,能选择合适的处理逻辑,把数据写到HBase或kafka里。


    设计

    client与服务端使用Thrift来通信,由.thrift来约定写数据的接口和结构。client所要做的是从初始配置里选择一个可用服务节点。向其询问眼下负载最低的节点进行数据写入。或者client本身选择服务节点的时候就是以偏随机和均衡的方式。这两种方式在后面讨论服务端实现的时候都会涉及到。


    以下说说服务端的几种方案。

    事实上在规划的时候,服务端是往p2p大量节点的方向设计的,兴许我又提出了些自己的看法,做了一些讨论。所以以下先介绍比較复杂些的实现方案。


    一致性哈希+p2p广播 方案

    如上图所看到的,绿色FeedsGroup是每一个服务节点,详细是一个JVM进程。一台实体机器上能够部署多个。主要思路是通过Chord算法来维护和管理网络结构。通过类gossip的实现来广播节点的负载信息。Chord是一致性哈希的一种实现,是p2p里比較重要的一个算法。一致性哈希保证了整个网络结构和可扩展性。且client能够通过hash的方式比較随机分散地分布到整个哈希环上,让各个节点上的连接数比較平均。此外,Chord算法的每一个节点维护了一个全局的Finger Table,这个Finger表是每一个节点对整个网络的"全局视图"。本身是用来做类二分的节点查找的,我们在这把它当作一个路由表。除了client能够通过訪问一个节点找到自己落在环上的位置外,这个路由表还用来让节点们做gossip通信。

    gossip是p2p网络里在无中心情况下广播自己信息和获得其它节点信息的协议。实现方式有非常多,在以下介绍纯gossip的实现方式的时候再详细介绍。

    关于chord算法的一些内容,能够參考我之前写的这篇文章

    后半部分是不同Sink目标,通过DB配置的方式为不同业务系统绑定不同的处理逻辑和数据下沉方案,包含详细schema的设计。


    纯gossip广播 方案


    纯gossip方案实现參考了Cassandra的实现方式,为每一个FG进程配置了几个种子节点,即每一个FG起来之后都会与种子节点交换自己的信息和其它节点的信息。然后通过种子节点维护的节点列表,再随机选取两个或三个节点进行通信。

    种子节点的设定避免的信息孤岛。Cassandra内gossip通信协议的实现说明能够參考DataStax的文章

    事实上纯gossip实现和上面第一种实现相比,少了DHT(Distributed Hash Table)这一块,对于client来说。每次连接须要节点返回一个全局负载最低节点给他来进行数据写入。


    小规模集群 基于zk实现方案

    以上实现方式。归根究竟是为了能承受client高并发的连接和写入需求,并且要做到可扩展,负载均衡和去中心化。且上面两种方案在成千上万个节点以下可能会比較有优势,由于chord和gossip本身的一些网络开销和信息维护都是适合于p2p网络以下大量节点的管理和维护。

    在实际开发中。可能我们最多起到上百个节点,甚至几十个节点。我考虑了简化的实现方式,只是本身也存在争议 :)。


    最简单的情况下。事实上我们仅仅有数据的写,没有第二次来同节点进行查询的请求。所以场景并不太像一致性哈希本身的数据存取场景,要简单非常多。单纯是一个服务节点列表,不须要不论什么哈希环。也能够解决我们的写入需求。只是这样可能就没啥设计可言了。

    我考虑在节点数目比較少的情况下,能够把节点在哈希环上的大整数值记录在zk上,如此就会在zk上维护一个相似哈希环的节点列表,且按顺序排列。节点之间维护一致哈希环也不须要额外的互相通信开销,而是直接从zk上进行读取操作,或者在zk上设置watch通知已有节点变更情况。

    以此换来的代价是,在zk上会有比較多的读请求,写请求非常少,zk充当了一个可靠的节点列表存储的地方,把网络通信的开销转移到了zk上面。

    在节点数目比較少的情况下,通过zk维护全局列表的方式能够完毕哈希环的管理、client对节点的选取、节点之间互相广播通信的事情。


    总结

    在设计之初。我们也有考虑直接拿kafka来做写入的事情,client做个producer,让kafka来承担并发写和负载的事情也全然能够事实上。只是考虑到实时接入场景的多样性,本文的实现满足的是直接同步写入的场景以及先持久化后计算的场景。

    第一种方案在设计上比較优雅,并且会非常适合大量节点数目的场景。

    另外一种方案产生的原因事实上是,我们的写需求事实上并不符合一致性哈希的场景,所以没有环这个东西也没啥问题。所以纯广播的方式照样是能够保证的。

    第三种方案是我自己YY的,只是也是比較鸡肋,比較奇怪,既然写zk了,就算没有环这个概念。直接把存活节点记录在上面,通过让client取余或别的随机方案选择目标节点也全然能够。好像也没有必要搞成一个哈希值什么的了。

    我感觉假设单纯是一致性哈希算法的实现的话,基于zk上的这样的实现方式在节点规模比較小的情况下应该还是可行的,仅仅是通信量级会与节点数目成正比,在合理的设计下。感觉还是简单可行的一种实现方案。


    全文完 :)

  • 相关阅读:
    Python自动化开发从浅入深-进阶(Twisted、Reactor)
    Python自动化开发从浅入深-进阶(socketServer)
    Python自动化开发从浅入深-进阶(select,poll,epoll学习)
    Python自动化开发从浅入深-进阶(进程)
    Python自动化开发从浅入深-语言基础(一些心得)
    Python自动化开发从浅入深-语言基础(常用模块)
    PSSH 批量管理服务器
    linux常用命令大全
    Why is 0[0] syntactically valid in javascript?
    免费为王(一)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5175769.html
Copyright © 2011-2022 走看看