精华内容
下载资源
问答
  • Chord:一个用于网络应用的可扩展的P2P查询服务 Ion Stoica*, Robert Morris, David Karger, M. Frans Kaashoek, Hari Balakrishnan MIT Laboratory for Computer Science chord@lcs.mit.edu ...

    Chord:一个用于网络应用的可扩展的P2P查询服务

    Ion Stoica*, Robert Morris, David Karger, M. Frans Kaashoek, Hari Balakrishnan
    MIT Laboratory for Computer Science chord@lcs.mit.edu
    http://pdos.lcs.mit.edu/chord/

    摘要

    P2P(peer-to-peer)系统面临的一个根本问题就是如何有效的定位到存储特定数据项的节点。本文提出了Chord,一个分布式查询协议来解决这个问题。Chord专为一种操作提供支持:给定一个key,它将key映射到对应的节点上。基于Chord,通过把key和每个data item(数据项)关联起来,并把该key/data item对存储到key映射到的节点上,很容易就可以实现数据定位。Chord可以有效的适应节点加入、离开系统,并且可以在系统持续变动的状态下应答查询。理论分析、模拟和实验结果表明,Chord是一个可扩展的协议,并且通信代价和每个节点状态信息维护的代价都是系统中Chord节点个数的对数。

    1 介绍

    P2P系统和应用都是没有中心控制节点或者层次化组织结构的分布式系统,系统中的节点在功能上都是相同的。近来,许多P2P应用都具有冗余存储(redundant storage)、持久化(permanence)、临近服务器选择(selection of nearby servers)、匿名访问(anonymity)、搜索(search)、认证( authentication)和分级命名(hierarchical naming)等许多特征。然而绝大部分P2P系统中,最核心的操作是高效的数据定位。本文的贡献就在于提出了一个能为节点频繁加入、离开的动态P2P系统提供有效查询操作的可扩展协议。
    【译注:数据定位(data location)、查询(query、lookup)都是一回事】
    实际上Chord协议仅支持一种操作:把一个给定的key映射到一个节点(node)上。 依据基于Chord协议的应用而定,目标节点可能负责存储关联到key的一组数据。Chord使用了一致性hash算法[11](consistent hashing)的变体把Chord网络中的节点关联到特定而唯一的key上。一致性hash算法可以解决负载平衡(load balance)问题,因为它能保证系统中的每个节点都能接收到数量相当的key,并且当节点加入、离开系统时,减少数据的迁移。【译注:实际上一致性hash算法可以保证:当节点离开时,仅需要迁移离开节点上的数据;当节点加入时,仅将加入节点的后继节点的部分数据迁移到新节点上;而不涉及到其它的节点和数据,这在理论上已经是最小化的数据迁移了】
    【译注:一致性hash算法的快速入门可以参见我的另一篇blog——一致性Hash算法 ,浅显易懂】
    在以前对一致性hash算法的研究中,都假设每个节点都关注系统中的大多数节点,因此难以扩展应用到有很多节点的大规模系统中。相反,在Chord系统中,节点仅需要路由信息(routing information),关注少数其它节点。因为路由表是分布式的,一个节点执行查询时,需要和少数的其它节点通讯,稳定状态下,在一个有N个节点的系统中,每个节点仅需要维护O(logN)的节点信息,并且执行查询时仅需要和其它节点交互O(logN)的信息。当有节点加入、离开系统时,为了维护路由信息,Chord保证系统中节点之间的交互消息不会超过O(logN*logN)个。
    Chord具有区别于其它P2P查找协议的3个特征:简单、正确性已经被证明和性能已经被证明。Chord简单有效,将key传递到目的节点仅需要路由O(logN)个节点。为了实现有效的路由,每个节点仅需要维护系统中O(logN)个节点的信息,并且在路由信息过期时,性能会优雅降级。这在实际中是很重要的,因为节点会随意的加入、离开系统,很难维持在O(logN) 的事件状态一致性。Chord协议中,每个节点仅有部分数据正确就能保证查询路由的正确性(尽管会变慢)。Chord具有简单的算法,能在动态的环境中维护路由信息。
    文章其余部分的结构:第二节比较了Chord和其它的相关研究,第三节介绍了促进Chord协议的系统模型。第四节介绍了基本的Chord协议,并且证明了Chord协议的几个性质,第五节描述了能够处理多个节点同时加入、离开系统的扩展协议。第六节仿真和在实际部署的原型上的实验,论证了我们关于Chord性能的声明。最后,第七节列举了将来的工作,并在第八节总结了本文的成果。

    2 相关工作

    Chord将key映射到节点上,而传统的名字和定位协议提供从key到value的直接映射。value可能是地址、文档或者任意的数据项。Chord可以很容易的实现该功能,只需要把每个key/value对存储到由key映射到的节点上即可。因为这个原因并便于更明确的对比,本节的其它部分假设一个基于Chord、提供从key到value映射的服务。
    DNS [15]提供从主机名到IP地址的映射,Chord也能提供相同的服务,以名字作为key,以IP地址作为关联到key上的value。Chord不需要专门的服务器,而DNS要依赖一组root域名服务器机。DNS域名是结构化的数据,以反映管理边界,Chord则没有命名结构。DNS是专门为查找命名主机或服务而设计的,而Chord还能用来查找没有绑定到特定主机的数据。
    Freenet P2P存储系统 [4, 5],类似于Chord,具有去中心化、对称、节点加入和离开时的自适应性等特点。Freenet不会把文档权限分配到特定的服务器上,而是以查找缓存的副本的形式来实现查询。这使Freenet可以提供一定程度的匿名性(anonymity),但是也使Freenet不能保证一定可以获取(retrieval)到现有的文档或者保证获取操作的时间下限。Chord不提供匿名性,但是它的查询操作能在可预见的时间内完成,并且返回结果只有成功和确定失败两种情况。
    Ohaha系统 采用了类一致性hash算法来把文档映射到节点上,和类Freenet风格的查询路由[18],因此它也具有Freenet的某些缺点。Archival Intermemory采用了离线计算树把逻辑地址映射到存储数据的节点上[3]。
    Globe系统 [2]具有广域定位服务(wide-area location service),把物体标识符(identifier)映射到移动物体的位置上。Globe把因特网作为一个具有地理、拓扑或者管理域的层次关系组织起来,从而有效的构建了一个静态的世界范围的查找树,很像DNS。物体的信息被存储在一个特定的叶子域[12]【译注:leaf domain,翻译真别扭】中,指针缓存(pointer cache)提供了快捷的搜索路径。Globe通过使用类hash技术把物体划分到多个根物理服务器中,以达到在逻辑服务器上的高负载处理能力。Chord很好的实现了hash方法,因此可以在不引入任何层次结构的情况下达到可扩展性,Chord也没有像Globe一样利用网络位置信息。
    由Plaxton等人开发的分布式数据定位协议 ,可能是与Chord最接近的算法,该协议的一个变体被应用于OceaStore中。它提供了比Chord更强的保证:和Chord一样,它保证查询能在对数级的跳数内完成,并且key的分布是平衡的,但是Plaxon协议还保证:以网络拓扑为准,查询所经过的网络距离,绝不会远于存储key的节点的距离。Chord的优势在于它更简单,并能更好的处理节点的并发加入、离开的情况。Chord还和PAST[8]中使用的定位算法Pastry相似,然而Pastry是一个基于前缀的路由算法,在其它细节方面也和Chord有所不同。
    CAN 用一个d维的笛卡尔坐标空间(d是固定的)实现一个把key映射到value的分布式hash表。每一个节点维护O(d)的信息,查询复杂度为O(d*N^1/d)。因此,对比Chord,一个CAN网络中的节点维护的信息不依赖于网络规模N,而且查询复杂度增长速度比O(logN)高,如果d=logN,那么CAN的查询复杂度和信息维护的空间复杂度都和Chord相同。但是在CAN的设计中,d不能随着N而动态改变,因此这仅出现在当N恰好和d匹配时。CAN需要一个额外的维护协议以周期性的把key重新映射到节点中,Chord的另一个优势在于,当存在部分不正确的路由信息时仍具有健壮的正确性。
    Chord的路由过程可以被看作是Grid定位系统[14](Grid location system)的一维模拟。Grid依赖于真实世界的地理位置信息来路由查询,Chord把节点映射到一个模拟的一维空间中,其中的路由被一个和Grid相似的算法来执行。
    Chord可以被用作查询协议来实现不同的系统,就像第三节中所描述的那样。特别的,它可以用来预防Napster[17]中的单点故障(single points of failure)或控制,以及像Gnutella[10]那样广泛因使用广播(broadcast)而造成的缺乏扩展性。

    3 系统模型

    通过处理下面的这些难题,Chord简化了P2P系统和应用的设计:
    负载均衡(Load balance) :Chord像一个分布式hash函数,最终将key散布在所有的节点上,这就在一定程度上提供了的天然的负载均衡能力。
    去中心化(Decentralization) :Chord是完全分布式的,没有哪个节点是更重要的,这增强了健壮性,并使得Chord适合于松散组织的P2P应用。
    可扩展性(Scalability) :Chord查询的复杂度随着节点数目N的log级别而增加(注:即O(logN)),因此适合应用在大规模系统中,并且不需要调整参数来达到这种可扩展性。
    可用性(Availability) :Chord会自动调整内部表来反映新近加入节点和节点失效的情况,确保除了底层网络的严重失效外,负责key的节点总是可以查询到。这甚至在系统处于一个持续改变的状态时也是正确的。
    灵活的命名规则(Flexible naming) :Chord对于要查找的key的结构没有施加任何的限制:Chord的key空间是扁平的(flat)。这就给应用程序与极大的灵活性来决定如何将他们自己的名字映射到Chord的key空间中。
    Chord软件采取library的方式与使用它的客户端和服务端程序连接。应用程序和Chord主要在两个方面交互。1 Chord提供一个lookup(key)算法,返回负责key(存储key以及与key关联的数据)的节点的IP地址(注:即节点必要的信息)。2 每个节点上的Chord通知应用程序该节点所负责的key的变动。这允许应用程序执行一些操作,例如,在一个新节点加入时移动相应的数据到新节点上。
    使用Chord的应用程序负责提供任何需要的认证、缓存、复制,和用户友好的数据命名。Chord的扁平key空间使得这些功能易于实现。比如一个程序可以验证数据d,这通过将d存储在一个来源于d的加密hash的Chord key下。类似的,应用程序可以复制数据d,这通过把d存储在两个不同的来源于d的应用层标识符的Chord key下。
    下面就是一些Chord可以提供良好基础的应用例子:
    协同镜像(Cooperative Mirroring) ,在一个近期的论文中描述[6]。设想有一组软件开发人员,每个人都希望可以提交发布。发布之间的需求可能差异巨大,从相当流行到不太流行【译注:这里看起来应该是影响的范围,有些发布可能影响很多人,有些发布影响范围比较小,原文:from very popular just after a new release to relatively unpopular between releases.】。一个有效的方法就是让开发人员之间相互镜像另一个人的发布。理想情况下,镜像系统可以提供服务器之间的负载平衡,复制、缓存数据,并且保证真实性。为了可靠性,这样一个系统应该完全的去中心化,而且也没有一个天然的中心管理组织。
    时间共享存储(Time-Shared Storage) ,用于断续连接的节点。如果希望一些数据总是可用的,但是他们的机器只能是偶尔可用,那么当机器可用时,他们可以相互存储其它人的数据,反过来,他们的数据也存储在了另外的机器上【译注:这样当他们的机器不可用时,也可以从其它活动的机器上取得数据】。数据的名字可以用作key,在任何时候定位负责存储的(活动的)Chord节点。这里有很多问题和协同镜像应用是相同的,尽管这里的焦点是可用性而不是负载均衡。
    分布式索引(Distributed Indexes) ,支持类似于Genutella或者Napster的关键字查询。本类应用中,key可能来自于要求的keyword,value可能是存储包含这些keyword的文档的机器列表。
    大规模组合查询(Large-Scale Combinatorial Search) ,比如密码破解。这种情况下,key是问题(比如密钥)的候选解决方案;Chord把这些key映射到负责测试它们执行破解任务的机器上。
    图1显示了协同镜像系统的一个可能的3层软件架构。最高层为用户提供一个类似文件系统的接口,包括用户友好的命名和认证机制。这个“文件系统”层可能实现命名文件夹和文件,并将对它们的操作映射到底层的块操作。下面一层是一个“块存储”层,实现需要的块操作。它负责块的存储、缓存和复制。“块存储”层将使用Chord来识别负责存储一个块的节点,然后联系节点上的块存储服务器来读写块。


    图1 基于Chord的分布式存储系统结构图

    4 基础Chord协议

    Chord协议明确说明了如何查找key的位置,新节点如何加入到系统中,以及如何从节点失效中恢复。本节描述了一个没有处理并发的节点加入、失效的简化版协议。第五节描述了对该基础协议的增强来处理节点的并发加入和失效情况。

    4.1 概述

    Chord的核心就是提供了一个hash函数的快速的分布式计算,该hash函数把key映射到负责key的节点。Chord使用了一致性hash算法[11, 13],它具有几个很好的性质。该hash函数能在很大概率上实现平衡负载(所有的节点接收到大概相同数量的key)。并且在很大概率上,当一个节点加入(或离开)网络时,仅有一小部分key会被移动到另外的位置——显然这是为了维持负载平衡所需的最小移动了。
    通过避免让每个节点知道其它所有节点的信息,Chord提高了一致性hash算法的可扩展性。在Chord网络中,每个节点仅需要知道包含少量其它节点的路由信息(routing information)。因为这个路由信息是分布式的,一个节点需要通过和少数其它节点通信来解答hash函数【译注:完成hash查询】。在一个具有N个节点的网络中,每个节点只需要维持O(logN)的节点信息,并且一次查询只需要O(logN)的交互信息。
    Chord必须在节点加入、离开网络时更新路由信息,一次加入或离开更新需要O(logN*logN)的交互信息量。

    4.2 一致性hash算法

    一致性hash算法使用一个hash算法比如SHA-1[9]为每个节点和key分配一个m-bit的标识符。一个节点的标识符通过节点的IP地址的hash结果得到,而一个key的标识符通过hash这个key而得到。我们将使用术语key来同时指原始的key和hash后的结果,因为在上下文中它的含义是清晰的。相似的,术语“节点”也会同时指节点本身和节点hash后的标识符。标识符的长度必须足够长,以使得两个节点或key具有相同标识符的可能性可以忽略不计。
    一致性hash算法采用如下的方式将key分配到节点上。标识符Identifier以Identifier mod 2^m【译注:mod为取模运算】的顺序排列到标识符环上。Key k被分派到标识符环上的第一个标识符等于或者紧随k(的标识符)的节点上。这个节点就是key k的后继(successor),记作successor(k)。如果标识符是从0到2^m-1的一圈数字,那么successor(k)就是在环上从k出发顺时针遇到的第一个节点。
    图2是一个m=3的标识符环,上面有0、1、3这3个节点。标识符1的后继就是节点1,key 1将被定位到节点1上。同样的,key 2将被定位到节点3上,key 6将被定位到节点0上。


    图2 一个有3个节点的标识符环的例子

     

    一致性hash算法设计的目的就是在节点加入、离开网络时做最小的数据分裂操作。为了维持正确的hash映射,在节点n加入网络时,最初分配给n的后继的key需要重新分配给n;当节点n离开网络时,n上所有的key将被分配给n的后继。除此之外不会再有key重新分配的情况。在上面的例子中,如果一个标识符为7的节点加入网络,那么标识符为6的key将被从节点0重分配到节点7上。
    一致性hash算法的论文[11, 13] 证明了下面的结果:
    定理1 对于任意N个节点和K个key的集合,在很大概率上(with high probability):
    1 任何一个节点最多负责(1+cta)K/N个key;
    2 当第N+1个节点加入或离开网络时,O(K/N)个key需要重新分配(并且仅是分配给加入的节点或从离开的节点上分配出去);
    当一致性hash算法按照上面的描述实现时,定理可以保证cta=O(logN)。论文还证明了通过把每个节点以O(logN)个“虚拟节点”的方式运行,cta可以被降低到一个任意小值。
    术语“很大概率上”需要一些讨论。一个简单的解释就是节点和key都是随机选择的,这在一个非对抗性的世界里貌似是可信的【译注:non-adversarial,看下面两句可理解】。概率分布是建立在随机选择的key和节点上的,因此这样的一个随机选择是不可能产生一个不平衡的分布的。然而,有人可能会担心,一个对手估计选择映射到相同标识符的key,来破坏其负载平衡的特性。一致性hash论文使用了“k-universal hash functions”来保证出现非随机选择的key的情况。
    我们选择使用标准的SHA-1算法作为基本的hash算法,而不是使用“k-universal hash function”。这使得我们的协议是确定性的,因此“很大概率上”的声明也不再具有意义。但是使用SHA-1生成一组有冲突的key,或者破解SHA-1算法,被认为是极其困难的。因此,我们称协议具有“基于标准的强度假设”的性质(based on standard hardness assumptions),而不是“很大概率上”。
    为了简单性,我们没有使用虚拟节点。在这种情况下,很大概率上(或者基于标准的强度假设)一个节点的负载可能会超出平均值一个系数。避免虚拟节点的一个原因是所需的虚拟节点个数由系统中的节点个数决定,而难以选择。当然,你可以在系统中选择使用一个预定义的虚拟节点上限,比如我们可以要求一个IPV4地址最多只能运行一个Chord服务,这样一个物理节点作为32个虚拟节点运行将会提供较好的负载平衡性。

    4.3 可扩展的key定位

    少量的路由信息有助于在一个分布式的环境中实现一致性hash算法。每个节点仅需关注它在环上的后继节点。一个给定标识符identifier的查询可以在环上沿着后继进行,直到第一次遇到identifier的后继,它就是要查询的节点。Chord协议维护了这些后继指针,以保证能正确的解决每次查询。然而,这种解决方法是低效的:它可能需要遍历所有的节点来找到合适的映射。为了加速查找,Chord还维护了额外的路由信息,这些额外的信息并非为了正确性,当然只要后继的信息是正确的,它们的正确性就能得到保证。
    和前面一样,设key和节点的标识符都是m-bit的。每个节点维护一个有m项(最多)的路由表,又称为finger table。节点n的第i个表项存储了节点s,并且s是在标识符环上距离n至少为2^(i-1)的第一个节点,即s=successor(n+2^(i-1),其中1<= i <=m(所有的计算都基于模2^m)。我们称s为n的第i个finger,并标记为n.finger_t[i].node(见表1)【译注:为了不至于混淆finger和finger table,本文将原文中代表finger table的变量finger都改为finger_t】。finger table中的项包括相应节点的IP和端口信息。注意到节点n的第一个finger就是n在环上的后继,方便起见,我们经常称它为后继(successor)而不是第一个finger。

    表1-1 节点n的变量定义(finger table在下表列出)

     

    【译注:为避免混淆,本文将原文中的一个表分成了两个表项,并加上了说明列,做简单的必要补充说明】
    如图3(b)中的例子所示,节点1的finger table将指向 (1 + 2^0) mod 2^3 = 2,(1 + 2^1) mod 2^3 = 3和(1 + 2^3) mod 2^3 = 5等3个标识符的后继。分别的,标识符2的后继是3,因为3节点紧跟标识符2的第一个节点,标识符3的后继是3,而标识符5的后继是0。

    表1-2 节点的finger table表定义,对应于m-bit的标识符

     

    【译注:根据定义,Finger table中的第一个finger,即第一个大于等于finger_t[1].start的节点,就是节点n的后继,n.successor = n.finger_t[1].node】
    该模式有两个重要的性质:第一,每个节点只需存储少量的其它节点信息,并且在标识符环上,它知道的距离较近的节点比较远的节点更多;第二,一个节点的finger table通常并不包括足够的信息来确定任意key的后继。比如图3中的节点3并不知道标识符1的后继,因为1的后继(节点1)并不在节点3的finger table中。
    如果一个节点n不知道key k的后继,它会怎么做呢?如果n能够找到一个标识符比自己更接近k的节点t,t将会比n知道更多的k区域的信息【译注:上面的性质1】。因此n查找它的finger table找一个标识符在k前面并且最接近k的节点j,并问j它知道谁的标识符更接近k。通过重复这个过程,n就会知道越来越接近k的节点。


    图3 (a)节点1的finger区间 (b)节点0,1,3和key1,2,6,finger table和key位置

     

    搜索的伪代码如图4所示【译注:代码中添加了响应的注释】。符号n.foo()表示函数foo()在节点n上执行。远程调用和变量引用前有远程节点标识,本地的调用和变量引用略去了本地节点标识。因此n.foo()代表了一个在节点n上的远程调用,而不带“()”的n.bar,则表示在节点n上查找变量bar的远程调用。
    函数find_successor查找给定indentifier的直接前驱n,于是n的后继肯定也是identifier的后继。我们将实现函数find_predecessor,因为在后面的jion操作中也会用到(4.4小节)。
    当节点n执行find_predecessor(id)时,它沿着Chord环上的一系列节点接近id。如果n联系到了节点n’,并且id落在了n’和n’的后继之间,find_predecessor将结束并返回n’。否则n询问n’知道的最接近id并在id之前的节点。因此算法将一直向着id的前驱执行。
    比如,考虑图3(b)中的Chord环。假设节点3要查询标识符1的后继。因为1属于环形区间[7, 3),即3.finger_t[3].interval,因此节点3检查其finger table的第三项,就是0。因为0在1之前,节点3将向节点0查找1的后继。作为应答,节点0从推断出1的后继就是节点1本身,因此返回1给3。


    图4 查找伪代码

    finger指针的倍增前进使(节点)和目标标识符的距离在find_predecessor中的每次迭代中减半。从这种直觉我们可以导出下面的定理:
    定理2 在很大概率上(或者基于标准的强度假设),在一个N个节点的网络中,查找一个后继所需要联系的节点个数为O(logN)。
    证明:假设节点n希望查询k的后继,且p是k的直接前驱结点,我们将分析到达p的步数。
    回忆如果n != p,那么n将把查询转交给在finger table中最接近k的前驱。假设p在n的第i个finger区间中,因此该区间是非空的,n将在该区间找到节点f。节点n和f之间的(标识符)距离至少是2^(i-1)。但是f和p都在n的第i个finger区间中,因此n和f之间的距离最大是2^(i-1)。这意味着f距p比n近,或者说,从f到p的距离最多是从n到p的距离的二分之一。
    如果在每次迭代时,接手查询的节点和p的前驱的距离以1/2递减,并且最初距离有2^m,那么在m步内距离将会减到1,意味着我们已经到达p。
    实际上,像上面所讨论的,我们假设节点和key的标识符都是随机的,因此在很大概率上,查询的转交次数是O(logN),经过O(logN)转交之后,当前处理节点和key之间的距离将会降到2^m/N,我们期望落在该范围内的节点个数是1,很大概率上可能是O(logN)。
    【译注:如果节点分布完全均衡,则2^m/N的范围仅含有一个节点,根据前面一致性hash的定理可知,有一个不均衡因子cta,在Chord的hash算法中,cta的取值很可能就是O(logN),在概率意义上节点间的距离最小可能是2^m/(N*O(logN)+1),因此在2^m/N的范围内可能会含有O(logN)个节点】
    因此即使在剩下的步骤中每次只前进一个节点,遍历整个区间并达到key所需要的步骤数也在O(logN)之内。证毕
    在第六节的实验结果报告中,我们将看到查询的平均时间是1/2logN。

    4.4 节点加入

    在动态网络中,节点可以在任何时候加入(离开)网络。实现这些操作的主要挑战就在于要保持网络根据key定位数据的能力,为了保持这种能力,Chord需要保证两个不变性:
    1 每个node的后继都被正确的维护;
    2 对于任意的key k,节点successor(k)是负责k的节点;
    为了快速的查询,Chord也要求finger table是正确的。【译注:从后面可以看到,finger table并不总是正确的】
    本节描述了如何在单个节点加入网路时如何维护这些不变性,我们将在第五节描述多个节点同时加入网络的情况,同时还描述了节点失效时的处理。在描述节点加入操作前,我们先总结它的性能(定理的证明参见合作技术报告[21]):
    定理3 在很大概率上,节点加入、离开N各节点的网络时将需要O(logN*logN)的消息来重建Chord的路由不变性和finger table。
    为了简化加入、离开机制,Chord中的每个节点都维护着一个predecessor指针,它包含节点直接前趋的Chord标识符和IP地址,因此可以逆时针的遍历标识符环。
    为了保证上面声明的不变性,当节点n加入时Chord必需执行下面的3个任务:
    1 初始化n的前驱结点指针predecessor和finger table
    2 更新已存在节点的finger table和predecessor指针,以反映n的加入
    3 通知上层软件,让它知道n的加入,以把n负责的状态(比如values)转移到n上
    我们假设新节点通过一些外部机制可以获取一个Chord中的节点n’的标识符。节点n通过n’来初始化自己的状态信息,并且加入到Chord网络中,如下面所示的那样。
    初始化predecessor和finger table:节点n请求n’在网络中查询它的predecessor和finger table,已完成初始化,使用的是init_finger_table,图6是它的伪代码。为finger table的m个表项依次执行find_successor来完成初始化,需要的时间是m*O(logN)。为了减少时间,对每个i,n都检查第i个finger是否和和第i+1个finger是相同的。这在finger_t[i].interval不包含任何节点时是成立的,因此finger_t[i].node >= finger_t[i+1].start。可以证明这个改进在很大概率上可以使需要执行查询的finger数目减少到O(logN),从而将总时间减少到O(logN*logN)。
    一个实践上的优化,新加入的节点n可以请求复制一个邻居的完整finger table和predecessor指针。n可以使用这些表的内容给自己的finger table设置正确的值,因为n的表和它邻居的是相似的,可以证明这可以把设置finger table的时间减少到O(logN)。


    图5(a) 节点6加入后,finger table和key位置的变化情况,变化部分用黑色标记
    译注:为了便于对比,译文一并给出了前后两幅图

     
    图5(b) 节点1离开后,finger table和key位置的变化情况,变化部分用黑色标记
    译注:为了便于对比,译文一并给出了前后两幅图

     

    图6 节点加入操作的伪代码

    更新已存在节点的finger:节点n需要加入到一些已存在节点的finger table中,比如在图5(a)中,节点6成为节点0和1的第三个finger,成为节点3的第一和第二个finger。
    图6描述了更新已有finger table的update_finger_table函数的伪代码。节点n将成为节点p的第i个finger,当且仅当:(1)p在n前至少2^(i-1)的距离,(2)p的第i个finger在n的后面。
    【译注:n=p.finger_t[i].node >= finger_t[i].start = (p+2^(i-1)) mod 2^m => n >= (p+2^(i-1)) mod 2^m;因为n更靠前,于是需要更新p的第i个finger】
    能够满足上面两个条件的节点p是n-2^(i-1) mod 2^m的直接前驱。因此给定n,算法从n的第i个finger开始,然后逆时针方向遍历环,直到遇到一个第i个finger在n前面的节点。
    我们在技术报告[21]中证明了,在很大概率上,当节点加入到网络时需要更新的节点个数是O(logN)。查找和更新这些节点需要的时间是O(logN*logN)。一个更复杂的机制可以把时间减少到O(logN);然而,我们不准备描述它,因为我们将在后面的章节中使用该算法。
    Key的转移:n加入网络时最后需要执行的一个操作就是把所有后继为n的key转移到n上。毫无疑问,细节取决于基于Chord的上层应用程序,但是典型的操作将会涉及到把这些key关联的数据转移到新节点n上。节点n仅仅会成为原先被紧接着n的节点【译注:n的后继】负责的部分key的后继,因此n只需要联系它并把相应的key转移过来就行了。

    展开全文
  • 1 获得地图服务中的几何网络 2 接受前台传来的数据以点标记为例 3 自定义IPointToEID所具备的功能 4 使用自定义的方法得到点标记id 5 设置网络的各种参数 6 将分析的结果转换成json字符串 7 将结果返回给客户端 8 ...

    1.引言

          在看博客之前,首先重点说明,本博客中使用的软件版本:

    • ArcGIS Server10.2
    • ArcGIS Object10.2

          如果你的版本是10.0,本博客中的代码肯定不可以用(10.0版本到10.1版本是一个大的提升)
          如果你的版本是10.1,本博客中的代码需要稍微修改(10.1版本到10.2版本会有小部分的修改)

          在本篇博客中主要以几何网络分析为例,介绍一下如果使用SOE来扩展我们的WebGIS应用。想要使用SOE扩展我们的WebGIS应用,需要对ArcGIS Object有一定的掌握。

    2.在ArcGIS Object中进行几何网络分析。

    在SOE扩展几何网络之前,先回顾一下如何使用ArcGIS Object来进行几何网络分析。

    • 首先在MapControl中绘制四类点(点标记listJunctionFlags,线标记listEdgeFlags,点障碍listJunctionBarrier,线障碍listEdgeBarrier)。

    这里写图片描述

    • 使用IPointToEID接口,将我们的点转换成网络中的节点(其实就是寻找网络中满足容差最近的节点),转换成功之后的数组为:junctionFlags,edgeFlags,junctionBarrier,edgeBarrier
    • 然后设置网络的四个参数(点标记,线标记,点障碍,线障碍),选择合适的方法分析,比如我们使用公共祖先分析(FindCommonAncestors),分析之后得到结果,得到的结果是网络中的节点id(有节点id,也有线id)
    • 通过网络中的节点id获得相应的Feature,然后就可以在地图中显示。

    3.SOE扩展几何网络分析难点

          在上面我们用文字简单的介绍了一下如何使用ArcGIS Object去分析几何网络,如果你熟悉AO,那么上面的过程你应该非常熟悉了。接下来我们就说一下在SOE中扩展WebGIS会遇到哪一些难点。

    • 难点一:假设我们要设置点标记(json数组),前台传来的是一个json数据,我们需要将json数组转换成List<IPoint>,然后通过IPointToEID,去查找网络中与改点最近的节点(在一定容差内)
    • 难点二:前面我们曾经说过,在ArcGIS 10.1之后,SOE开发中不可能获得IMap,ILayer对象,但是呢?IPointToEID这个接口需要传入IMap对象,所以IPointToEID这个接口在ArcGIS Server10.1之后不能使用了(SOE开发中不能用,AO中是可以使用的),但是这个接口的功能是我们必须要用到的,所以这个功能需要我们自己写代码实现。
    • 难点三:我们查询出来的结果,需要传给前台显示,这就需要我们将查询出来的结果序列化成json字符串,然后传给前台。

    4.SOE扩展几何网络分析

          在前面我们说了,自己扩展几何网络分析会遇到哪一些困难,接下来,我们就扩展一个几何网络服务,然后解决掉上述遇到的问题。

    4.1 获得地图服务中的几何网络

    IMapServer3 mapServer = this.serverObjectHelper.ServerObject as IMapServer3;
    IMapServerDataAccess dataAccess = (IMapServerDataAccess)mapServer;
    IFeatureClass featureclass = (IFeatureClass)dataAccess.GetDataSource(mapServer.DefaultMapName, 0);
    IFeatureDataset ds = featureclass.FeatureDataset;
    INetworkCollection2 networkCollection2 = ds as INetworkCollection2;
    //获得所需要的几何网络
    IGeometricNetwork geometricNetwork = networkCollection2.get_GeometricNetwork(0);
    

    4.2 接受前台传来的数据(以点标记为例)

    //定义一个点标记数据
    object[] listJunctionFlags;
    //读取前台传来的数据(json数组)
    operationInput.TryGetArray("listJunctionFlags", out listJunctionFlags);
    //我们要将json数据转换成List<IPoint>对象
    List<IPoint> junctionFlags = new List<IPoint>();
    foreach (JsonObject jo in listJunctionFlags.Cast<JsonObject>().ToArray())
    {
                    IPoint location = Conversion.ToGeometry(jo, esriGeometryType.esriGeometryPoint) as IPoint;
                    junctionFlags.Add(location);
    }
    

    4.3 自定义IPointToEID所具备的功能

    
    /*
    searchTolerance:搜索容差
    point:搜索的点,也就是上面我们转换得到的 List<IPoint> junctionFlags
    elementType:搜索的类型,(搜索节点,还是搜索线)
    geometricNetwork:搜索哪一个网络?
    EID:搜索得到的节点id
    geometry:搜索得到的几何形状
    */
    public void GetEIDFromPoint(double searchTolerance, IPoint point, esriElementType elementType, IGeometricNetwork geometricNetwork, out int EID, out IGeometry geometry)
            {
                EID = -1;
                geometry = null;
                IEnumFeatureClass enumFeatureClassSimple = null;
                IEnumFeatureClass enumFeatureClassComlex = null;
                if (elementType == esriElementType.esriETEdge)
                {
                    enumFeatureClassSimple = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTSimpleEdge);
                    enumFeatureClassComlex = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTComplexEdge);
                }
                else if (elementType == esriElementType.esriETJunction)
                {
                    enumFeatureClassSimple = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTSimpleJunction);
                    enumFeatureClassComlex = geometricNetwork.get_ClassesByType(esriFeatureType.esriFTComplexJunction);
                }
                double distance = double.PositiveInfinity;
                int featureClassID = -1;
                FindNearestDistance(enumFeatureClassSimple, point, searchTolerance, ref distance, ref featureClassID, ref geometry);
                FindNearestDistance(enumFeatureClassComlex, point, searchTolerance, ref distance, ref featureClassID, ref geometry);
                if (featureClassID == -1)
                {
                    EID = -1;
                    return;
                }
                IProximityOperator proximityPoint = geometry as IProximityOperator;
                IPoint p = proximityPoint.ReturnNearestPoint(point, esriSegmentExtension.esriNoExtension);
                if (elementType == esriElementType.esriETEdge)
                {
                    EID = geometricNetwork.get_EdgeElement(p);
                    return;
                }
                else if (elementType == esriElementType.esriETJunction)
                {
                    EID = geometricNetwork.get_JunctionElement(p);
                    return;
                }
    
                return;
            }
            private void FindNearestDistance(IEnumFeatureClass enumFeatureClass, IPoint point, double searchTolerance, ref double distance, ref int featureClassID, ref IGeometry featureGeometry)
            {
                enumFeatureClass.Reset();
                IFeatureClass featureClass = enumFeatureClass.Next();
                while (featureClass != null)
                {
                    string shapeFieldName = featureClass.ShapeFieldName;
                    ITopologicalOperator topologicalOperator = point as ITopologicalOperator;
                    ISpatialFilter spatialFilter = new SpatialFilterClass();
                    spatialFilter.Geometry = topologicalOperator.Buffer(searchTolerance);
                    spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                    spatialFilter.GeometryField = shapeFieldName;
    
                    IFeatureCursor featureCursor = featureClass.Search(spatialFilter, true);
                    IFeature feature = featureCursor.NextFeature();
                    while (feature != null)
                    {
                       IProximityOperator proximityOperator = feature.ShapeCopy as IProximityOperator;
                       double distanceCurrent = proximityOperator.ReturnDistance(point);
                       if (distance > distanceCurrent)
                       {
                         distance = distanceCurrent;
                         featureClassID = featureClass.FeatureClassID;
                         featureGeometry = feature.ShapeCopy;
                       }
    
                       feature = featureCursor.NextFeature();
                    }             
                    featureClass = enumFeatureClass.Next();
                }
            }
    

    4.4 使用自定义的方法得到点标记id

    			int eid;
                IGeometry geo;
                //points 是我们在4.2中转换得到的List<IPoint>对象
                for (int i = 0; i < points.Count; i++)
                {
                    GetEIDFromPoint(tol, points[i], esriElementType.esriETJunction, this.geometricNetwork, out eid, out geo);
                    if (geo != null)
                    {
                        INetElements netElements = geometricNetwork.Network as INetElements;
                        int userClassID = 0;
                        int userID = 0;
                        int userSubID = 0;
                        netElements.QueryIDs(eid, esriElementType.esriETJunction, out userClassID, out userID, out userSubID);
                        INetFlag junctionFlag = new JunctionFlagClass() as INetFlag;
                        junctionFlag.UserClassID = userClassID;
                        junctionFlag.UserID = userID;
                         //jFlags类型为List<IJunctionFlag>,是我们分析真正用到的节点id
                        jFlags.Add(junctionFlag as IJunctionFlag);
                    }
    
                }
    

    4.5 设置网络的各种参数

    //几何网络分析的具体接口
    traceFlowSolverGEN = new TraceFlowSolverClass();
    netSolver = traceFlowSolverGEN as INetSolver;
    //设置几何网络
    netSolver.SourceNetwork = geometricNetwork.Network;
    //设置几何网络的点标记
    IJunctionFlag[] arrayJunctionFlag = new IJunctionFlag[jFlags.Count];
    for (int i = 0; i < listJunctionFlags.Count; i++)
         arrayJunctionFlag[i] = listJunctionFlags[i];
    traceFlowSolverGEN.PutJunctionOrigins(ref arrayJunctionFlag);
    //同理设置线标记,点障碍,和线障碍
    //进行几何网络分析(以公共祖先为例)
    //junctionEIDs是分析结果的 节点id
    //edgeEIDs是分析结果的 线id
    traceFlowSolverGEN.FindCommonAncestors(esriFlowElements.esriFEJunctionsAndEdges,
                            out junctionEIDs, out edgeEIDs);
    

    4.6 将分析的结果转换成json字符串

    INetElements netElements = geometricNetwork.Network as INetElements;
    int userClassID = -1;
    int userID = -1;
    int userSubID = -1;
    int eid = -1;
    IFeature feature;
    IFeatureClass featureClass = null;
    objectJson = new JsonObject();
    //没有查找到线
    if (edgeEIDs.Count == 0)
    {
            objectJson.AddArray("edges", (new List<JsonObject>()).ToArray());
    }
    else
    {
    		//如果有查询到线,将线的geometry和属性封装成json对象
            JsonObject[] featureSet = new JsonObject[edgeEIDs.Count];
            for (int i = 0; i < edgeEIDs.Count; i++)
            {
                   eid = edgeEIDs.Next();
                   netElements.QueryIDs(eid, esriElementType.esriETEdge, out userClassID, out userID, out userSubID);
                   featureClass = GetFeatureClassByUserID(userClassID);
                   if (featureClass != null)
                   {
                          feature = featureClass.GetFeature(userID);
                          featureSet[i] = new JsonObject();
                          featureSet[i].AddJsonObject("geometry", Conversion.ToJsonObject(feature.Shape));
                          JsonObject[] arr = new JsonObject[feature.Fields.FieldCount];
                          for (int j = 0; j < feature.Fields.FieldCount; j++)
                          {
                                 IField field=feature.Fields.Field[j];
    				             arr[j] = new JsonObject();
    			                 arr[j].AddObject(field.AliasName, feature.get_Value(j));
    					  }
                                    featureSet[i].AddArray("attr",arr);
    
                   }
             }
             objectJson.AddArray("edges", featureSet);
    }
    //没有查找到点
    if (junctionEIDs.Count == 0)
    {
           objectJson.AddArray("junctions", (new List<JsonObject>()).ToArray());
    }
    else
    {
    		  //如果有查询到点,将点的geometry和属性封装成json对象
              JsonObject[] featureSet = new JsonObject[junctionEIDs.Count];
              for (int i = 0; i < junctionEIDs.Count; i++)
              {
                eid = junctionEIDs.Next();
                netElements.QueryIDs(eid, esriElementType.esriETJunction, out userClassID, out userID, out userSubID);
                featureClass = GetFeatureClassByUserID(userClassID);
                if (featureClass != null)
                {
                  feature = featureClass.GetFeature(userID);
                  featureSet[i] = new JsonObject();
                                featureSet[i].AddJsonObject("geometry", Conversion.ToJsonObject(feature.Shape));
                  JsonObject[] arr = new JsonObject[feature.Fields.FieldCount];
                  for (int j = 0; j < feature.Fields.FieldCount; j++)
                  {
                      IField field = feature.Fields.Field[j];
                      arr[j] = new JsonObject();
    	              arr[j].AddObject(field.AliasName, feature.get_Value(j));
                  }
                  featureSet[i].AddArray("attr", arr);
    
               }
           }
           objectJson.AddArray("junctions", featureSet);
    }
    //GetFeatureClassByUserID方法
    private IFeatureClass GetFeatureClassByUserID(int userClassID)
    {
         IMapServer3 serverObject = this.serverObjectHelper.ServerObject as IMapServer3;
         IMapLayerInfos mapLayerInfos = serverObject.GetServerInfo(serverObject.DefaultMapName).MapLayerInfos;
    
         for (int i = 0; i < mapLayerInfos.Count; i++)
         {
              IMapLayerInfo mapLayerInfo = mapLayerInfos.get_Element(i);
              if (mapLayerInfo.IsFeatureLayer)
              {
                  IFeatureClass featureClass = this.GetFeatureClass(mapLayerInfo.ID);
                  if (featureClass.FeatureClassID == userClassID)
                      return featureClass;
              }
         }
         return null;
    }
    

    4.7 将结果返回给客户端

    return Encoding.UTF8.GetBytes(objectJson.ToJson());
    

    4.8 运行结果

    这里写图片描述

    5.数据及代码下载地址

    展开全文
  • 扩展你的无线网络

    千次阅读 2012-01-12 18:30:29
     随着网络的日渐普及,网络资费的不断下降,使人们的生活对网络的依赖越来越强。但是对家庭和中小公司来说,传统网络的布线是个很头疼的问题。过多的布线既影响美观,又显得杂乱无章,维护起来也很费力气。无线网络...

    一、引言

        随着网络的日渐普及,网络资费的不断下降,使人们的生活对网络的依赖越来越强。但是对家庭和中小公司来说,传统网络的布线是个很头疼的问题。过多的布线既影响美观,又显得杂乱无章,维护起来也很费力气。无线网络的出现,让这一切变的简单了起来。

        无线网络有很多种标准,常见的如蓝牙,WiMax802.11 (Wi-Fi)等,这里我们讲述的是802.11 无线网络。所以以下所说的无线网络,如无特殊说明,均指802.11无线网络。

        说起无线网络,就不得不提起无线路由器/AP,正是这些小小的设备把你的无线终端,如笔记本、手机、PDA等,连接起来,让它们可以彼此自由的通信。但是每个无线路由器/AP的信号覆盖范围都是有限制的,怎么才能扩充它们的信号覆盖范围,让更多的无线网络终端连接起来呢?本文就旨在让你全面了解无线网络无线网络的连接方式以及如何有效的扩展无线信号的覆盖范围。

        我这里不会对一些无关的无线网络参数作过多的解释和阐述,只介绍跟扩展无线网络覆盖范围相关的知识,有兴趣的朋友可以自行了解。在进一步讲述无线网络扩展之前,有些概念需要先说明一下。

        无线网络模式:无线网络有两种组网模式,分别是结构式(infrastructure)和点对点式(Ad Hoc)。结构式属于非对等模式,无线网络终端设备之间需要连接到一个无线网络接入点(AP),通过该接入点实现彼此之间的通信,这也是我们最常使用的工作模式;点对点(ad-hoc)模式则用于实现两个无线网络终端之间的直接通信,没有数据转发,就如在有线网络中两台计算机可以通过交叉线直接相连一样。

        无线分布式网络(WDSWDS是实现无线网络扩展的关键技术,通过WDS可以很容易的扩展无线网络的覆盖范围,实现共享上网,无线漫游等功能,这也是我们实现无线网络扩展的重点和基础,下文会有详细阐述。

        无线路由器与无线AP无线路由器本身具有AP功能,所以也可称无线路由器为“胖AP”,根据应用场合不同,无线路由器可以具有更多更全面的网络控制功能;而无线AP专指“瘦AP”,它通常只具备简单的无线转发功能,因此它在转发性能上可能会优于无线路由器。

        无线信道/频道无线网络通过电磁波传输数据,所以它们需要工作在某一频段才能互相通信。与蓝牙的自动跳频技术比较,802.11无线网络显得有些呆板,所以你需要为它指定一个有效的频段,也就是常说的信道或频道,只有工作在相同频段的无线设备才能彼此通信。需要注意的是,不同国家对无线通信的频段都会有法律限制,所以有些频段在某些地区可能是不可用的。

    术语说明

        通过前面简单的阐述和说明,我们就要开始无线网络扩展之旅了,但在进入下一节之前,我们最好把一些术语说明一下。

        无线网络:如无特殊说明,则专指802.11无线网络;

        信道:无线网络频率或频道,以数字表示;

        无线AP接入点,它是一个概念,根据上下文,可能是指路由器,也可能是指“瘦AP”;

        无线客户端/无线终端用于连接无线网络的终端设备,如笔记本、手机、PDA等,也可能指无线网卡;

    感谢

        本文的完成离不开朋友和家人的理解与支持,所以在这里我要对他们表示感谢。首先要感谢的是深圳市乙辰(JCG)科技发展有限公司的朋友,是他为我提供了用于测试的路由器和网卡等,没有他的协助,我也无力完成本文中的实验与测试;其次要感谢我的老板,他没有给我太多的加班机会,否则我也没有时间完成本文;最后还要感谢我的老婆,她主动承担了洗碗和打酱油的义务,让我能安心的折腾。

    声明

        本文所有实现方案的网络设备均由JCG提供,如有需求,请与JCG联系。为尽可能保证兼容性,建议使用同一厂家的产品组网。

        本文为原创作品,转载请保持原文,感谢您的配合与理解。


    二、点对点(Ad-hoc)连接

        建立无线点对点连接可以有两种方式:

        其一是网络共享模式,我这里不做详述,详情可参见微软技术服务文章:http://www.microsoft.com/china/windowsxp/expertzone/columns/bowman/02april08.mspx

        其二是使用网桥模式实现共享上网,下面我们就来讨论第二种模式,如下图所示。

        两台笔记本电脑通过ad-hoc组网,其中一台笔记本的有线网络连接互联网,在没有AP的情况下,通过无线点对点连接实现共享上网。下面我们就来看该如何实现。

        首先在PC2中按照上述微软官方技术文章中的指导建立ad-hoc服务:

        1. 在【无线网络连接属性】->【无线网络配置】->【高级】中选择【仅计算机到计算机】

    建立计算机到计算机的连接

        2. 【无线网络连接属性】->【无线网络配置】->【添加】来添加无线网络,设置SSID,加密参数等。注意:在添加前,最好删除列表中之前所设定所有无线网络。

    设置网络安全参数


        3. 设置完成后如下,你可以看到网络配置中左侧小图标变成了一个小网卡标识,如果没有连接,上面还会有个小红叉。

    Ad-hoc无线网络连接


        4. 要实现共享上网,最后还需要建立一个网桥,以实现无线到有线网络之间的数据转发。在网络连接中,选择要桥接的两个网络,如选择我们要桥接的有线网络和无线网络(可以按住【Ctrl】选择多个网络),然后在右键菜单中选择【桥接】,系统就会自动建立一个虚拟的网桥,如下图所示。

        我这里使用的Windows XP系统,如果你的操作系统是Windows VistaWindows7,就更简单了,可以参照下文的方式建立Ad-hoc点对点连接服务。创建网桥的情况和Windows XP大同小异,这里就不作赘述了。

        好了,下面我们就可以设置PC1上的无线网络了。在Windows7上实现无线网络共享会比Windows XP简单很多,我们只需要在【网络和共享中心】中使用【设置新的连接或网络】向导即可轻松完成无线网络共享设置。

        首先,打开【设置新的连接或网络】向导,选择【设置无线临时(计算机到计算机)网络】,进入下一步。


      然后设置无线网络的安全参数,如SSID、安全类型和密钥等,这些参数须和之前设置的保持一致。


    一路点击【下一步】完成向导后,Windows就可以自动的识别并连接共享网络了,见下图所示。



        注意,这里的无线网络都不用配置IP地址,所有IP地址均由上级有线网络的路由器自动分配。如果你的上级网络不会分配IP地址,比如你的有线网络没有连接路由器,而是直接使用的PPPoE拨号等,可以参照新浪博友的文章,通过配置共享网络以及网桥的IP地址实现共享上网。http://blog.sina.com.cn/s/blog_53f716d40100krdj.html

        Ad-hoc点对点连接只能为你提供最简单的暂时性的网络共享服务,对无线网络的扩展并没有太大的作用,而接下来我们要重点讨论的才是真正的无线网络扩展技术。


    三、淘个网卡当AP

        你是否觉得无线路由器太贵,而上文中说的的点对点Ad-hoc连接方式又太麻烦?呵呵,如果我告诉你有无线网卡可以当个AP使用,你是否会怦然心动?没错,市面上有些无线网卡就同时具备了无线AP的功能!JCG送测的JHL-N132R就是其中的一款,新颖又阳光的造型,加上大功率设计,用它来做AP实现无线网络共享是再合适不过了!下面我们就来看看怎样用它来当AP吧。

        首先你需要安装随网卡一起附送的光盘中的驱动程序,并且不要使用Windows自带的Zero Configuration作为无线网络管理工具,而是使用光盘中附送安装的无线网卡配置工具,它能提供比Windows更多更方便的控制功能。关键是,它可以让你的网卡摇身一变,成为一台无线AP!(在进一步设置之前,请确保你的电脑已经可以通过另外一张网卡上网,否则AP没有出口,也就无从谈起共享上网了,呵呵。)

        然后右键点击右下角托盘里的无线网卡配置工具,选择【切换至AP模式】,网卡就会自动切换到AP模式。需要注意的是,在模式切换时,某些安全软件可能会提示警告或者阻止某项动作,请注意设置为放行,否则你的无线网卡可能无法正常工作。


    切换为AP模式


        如果有多于一张其它网卡,会提示选择哪张网卡作为出口。


    自动配置ICS

     

        需要注意到是,在Windows XPWindows Vista下,需要ICS支持,Windows7则不需要。启动AP模式后的配置工具。


    AP配置工具

        通过此配置工具,你可以很方便的设置AP的无线网络名称(SSID)、工作频道、访问控制,以及查看访问者列表、设置安全参数等。


    网络安全设置

        设置完成之后,其它无线设备就可以像连接AP一样连接到你的无线网卡上了,连接成功后,此AP会自动为其分配一个私有的IP地址。遗憾的是,我们并不能通过该工具为AP设置分配的IP地址范围,只能在【关于】选项卡里看到IP地址信息,不知道如果有线网络使用了同样的IP地址,会不会产生冲突,希望JCG在后续版本里能够改善。

    当前访问列表


    驱动及配置程序版本信息

        经笔者试用,效果非常不错,另外据官方消息,该工具同样支持Windows Vista和最新的Windows7,有兴趣的朋友们可不要错过了哦。


    四、瘦AP扩展的星形网络

        使用AP扩展无线网络覆盖范围是最早期使用的,也是最常用的组网方式之一,该方案运行稳定,吞吐量好,能够有效的利用有线和无线的网络带宽,是早期低速无线网络的理想选择。但是这种组网的局限性在于,它需要有线网络布线才能实现扩展,其典型的网络拓扑示意图如下:

        从上图我们可以看到,AP通过有线网络连接中心路由器或交换机,它们接收无线网络终端的连接,然后通过有线网络转发出去,实现无线网络范围的扩展。

        为了避免网络之间的IP地址冲突,我们首先需要把IP地址组织好,所以我把实验环境IP地址列出如下:


        设置好各个设备的IP地址之后,把除主路由器之外的其它路由器都切换到AP模式。JCG无线路由器只需要在设置页面把工作模式切换为【网桥模式】就可以了。


    设置为网桥模式(AP

        关于漫游:如果你想实现网络之间的漫游功能,还需要在无线设置中为路由器和AP设置相同的无线网络信道和网络名称(SSID)。同时还需要在无线网络终端中设置允许网络切换/漫游功能,如何设置,详见各网卡或设备中的设置工具。


    设置SSID和频道

        至此,用有线把AP连接到主路由器的LAN接口上就可以实现无线信号覆盖与漫游了,应该算很简单吧?

    五、使用WDS扩展

        无线分布式系统WDSWireless Distribution System),在无线网络扩展中扮演着最重要的角色,它可以帮你轻松的实现无线到无线的扩展,而中间不必使用任何有线的连接,这在看中美观的家庭中和不适合做有线连接的特殊场合中都显得非常重要。但是由于无线网络的普及速度远远超过了无线网络知识的普及速度,导致很多用户甚至是有过多年IT管理经验的企业用户都对WDS无线网络扩展有过或多或少的困惑。下面我们就来详细了解一下WDS的详细功能。

        WDS有三种工作模式:自学习模式(Lazy Mode)、桥接模式(Bridge Mode)和中继模式(Repeater Mode)。我们先讲自学习模式。

        自学习模式属于被动模式,也就是说它能自动识别并接受来自其他APWDS连接,但其本身不会主动连接周围的WDS AP。所以这种WDS模式只能用于主接入点路由器或AP上,只能用于被扩展的主AP上,而不能用于通过WDS扩展其它AP


        上图向我们展示了WDS的一种连接方式,AP1作为主AP采用了自学习模式,AP2作为从AP采用了中继模式。那什么又是WDS中继模式呢?

        中继模式是功能最全的WDS模式,在此模式下,AP既可以通过WDS实现无线网络范围的扩展,同时也具有AP的功能,接受无线终端的连接,如上图中的xPad就是通过内置的Wi-Fi无线网络直接连接到工作在WDS中继模式下的AP2的。从上图中,你可能看不出WDS中继模式和自学习模式的区别,事实上它们确实也没有太多的区别,唯一不同的就是自学习模式不能工作在从AP上,因为它只能被动的接受连接,不会主动的根据BSSIDAPMAC地址)连接到扩展AP。因此我们可以推断:中继模式可以工作在任何AP上,无论是主AP还是从AP,但是自学习模式只能工作在主AP上,它只能用来被扩展。

        知道了自学习模式和中继模式之间的区别,如何设置WDS就变得没有那么困难了。首先从上图中我们可以看到两个APIP地址设置。你可能已经发现,为什么AP1Router使用的是同样的IP地址192.168.1.1呢?呵呵,这是我为了能够更清晰的为你展示WDS是如何工作的,而特意在示意图中把一个无线路由器拆分成RouterAP1的,实际上它们就是一台具有APWDS功能的无线路由器,别搞混了哦。

        根据上图设置好APIP地址之后呢,我们就可以设置WDS了。首先,进入AP1的无线网络设置页面,以自学习模式启用WDS


    AP1设置为自学习模式


        然后设置AP2,进入AP2的无线网络设置页面,以中继模式启用WDS,注意这里要填入AP1MAC地址哦。如果记不住怎么办呢?幸好还有【基点扫描】功能,通过自动扫描,我们很容易就能找到AP1MAC地址了,只是扫描结果不能自动选择填入,JCG在人性化方面还有待加强啊!


    AP2设置为中继模式

        这就算大功告成了吗?你可能要问,为什么我的PC连接到AP2上,却无法访问AP1,也不能上网呢?别急,在上图的设置页面截图中看到右侧帮助栏的红字提示了吗?对了,所有的从AP都需要关闭DHCP服务器功能,从主AP也就是路由器那里获取IP地址才可以哦。关闭DHCP很简单,进入【网络设置】->【局域网】,关闭DHCP服务器就可以了。


    关闭DHCP服务器

        等等……等等……,为啥我还是上不了网呢?哦,my dear,你真的认真阅读我上面的描述了吗?通过无线互联的AP必须使用相同的信道哦,往前翻翻吧,有图有真相,呵呵!

        好了,说完了WDS的自学习模式和中继模式,下面就来讲讲WDS的桥接模式吧!简单来说,桥接模式和有线网络中的网桥很像,它从一端接收数据包,并把它转手转发到另一端。WDS的桥接模式除了不再同时具有AP功能之外,其它和中继模式基本相同,所以在WDS桥接模式下,AP不再接受无线网络终端的连接,你也搜索不到它的存在。

        下面是我们上文中WDS拓扑示意图的升级版,你能发现它们做了哪些改动吗?

        首先你可以看到,我们使用了三级WDS,它能把无线网络的覆盖距离扩展到更远。另外你可能也发现,在AP2上,你既没有发现xPad,也没所有发现xPhone,正如我前面所讲的,工作在WDS桥接模式下的AP2,不再接受来自无线终端的连接,因为它已经不再同时具备AP的功能了,但是和它通过有线连接的PC们,并没有受到影响。

        这种方式该怎么设置呢?呵呵,说了这么多,我想你已经胸有成竹了吧?AP1AP3参照上面所讲的设置就可以了,注意,在AP3WDS设置中,要设置AP2MAC地址哦。而AP2由于承接AP1AP3之间的连接,就需要把它们的MAC地址都加入WDS设置了。


    桥接模式下的WDS设置

        为什么我还上不了网呢?BLABLABLA……,参照前面的解决办法吧,我的口有点渴了,喝点水先,嘿嘿!

        最后我把WDS的三种方式的特点用个图表来简单的总结一下吧。

        WDS的东东我就讲这么多了,通过举一反三,你应该会发现,通过WDS可以实现很多种组网方式。下面我列举了几种,就当家庭作业吧!有兴趣的话,自己去倒腾吧!另外你可能也发现了,我没有做WDS加密的实验,有需要的话,就要你自己动手试试喽!





    六、AP客户端方式

        看到这里,可能有的朋友会着急了:看了这么多,没一样我能用的,我的老古董无线路由器不支持WDS,该怎么办呢?杯具啊……

        不用“杯具”,有了支持AP客户端功能的无线路由器,你就可以“洗具”了!我手头这款JCG无线路由器就支持“AP客户端”功能,通过它你就可以像使用有线连接一样,通过无线来连接到你的老古董无线路由器了(不过呢,我很担心你的老古董无线路由器的速度问题哦)。还是先上拓扑示意图吧!

        从图中可以看到,我们的新路由器使用AP客户端连接上级路由器,这里AP客户端实际上就相当于路由器有了一个多出来的无线网卡,通过它连接到上级无线路由器,从而实现共享上网的功能。

        要使用AP客户端功能也很简单,首先进入路由器设置页面,在【工作模式】中选择【AP客户端模式】,点击【应用】,路由器会重启。


    AP客户端模式

        重启之后,路由器会自动定向到【无线设置】->AP客户端设置】,需要在这里为AP客户端设置无线网络连接参数。点击【基点扫描】,找到你的老古董无线路由器,直接选取就可以了,所有参数会自动帮你填好。这一点上JCG做的还是值得表扬的,比较人性化,呵呵!不过如果你设置了无线加密,就需要自己填上密码了,这一点厂家可不能代劳,否则就要有人骂娘了,呵呵!


    AP客户端参数设置

        设置好之后,路由器会自动连接,【返回首页】查看一下连接状态就知道了。


    AP客户端连接状态

        等等……等等……,为什么我的路由器无法连接上去呢?哦,那我就再说一下吧!第一步:把路由器恢复出厂设置吧,以免会出现没必要的问题;第二步:注意设置相同的无线信道;第三步:注意使用不同IP地址段;第四步:往前翻翻……

        至此,无线网络扩展就算全部讲完了,你意犹未尽,我精疲力竭…… 呵呵,如果讲的这些能够对你有所帮助,我就非常开心了。正如JCG所倡导的一样,“无线自由,无限精彩”,享受生活,享受网络才是硬道理,你说呢?


    七、参考资料

    [1]. 建立Ad Hoc 无线连接Barb Bowman

    [2]. Windows XP网桥连接Ad Hoc无线网络与有线局域网, 纪国刀客 新浪博客

    [3]. 802.11无线网络权威指南》

    [4]. www.jcgcn.com



    展开全文
  • k8s-dns-gateway 网关网络扩展实战

    千次阅读 2017-06-28 20:42:19
    dns以及网络扩展实战*k8s-dns-gateway dns网关网络扩展实战* k8s服务暴露分为几种情况 1.svc-nodeport暴露 缺点所有node上开启端口监听,需要记住端口号。 2.ingress http 80端口暴露 必需通过域名引入。 3.tcp...

    dns以及网络扩展实战

    *k8s-dns-gateway dns网关网络扩展实战*


    • k8s服务暴露分为几种情况
      1.svc-nodeport暴露 缺点所有node上开启端口监听,需要记住端口号。
      2.ingress http 80端口暴露 必需通过域名引入。
      3.tcp–udp–ingress tcp udp 端口暴露需要配置一个ingress lb,一次只能一条规则,很麻烦,要先规划好lb节点 同样也需要仿问lb端口,无比麻烦。
      然而正常的虚拟机我们只需要一个地址+端口直接仿问即可
      那么我们能不能做到像访部虚拟机一样访部k8s集群服务呢,当然可以 以下架构实现打通k8s网络和物理网理直通,物理网 络的dns域名直接调用k8s-dns域名服务直接互访
      架构环境如下
      k8s集群网络 172.1.0.0/16
      k8s-service网络 172.1.0.0/16
      物理机网络192.168.0.0/16

      访问k8s中的一个服务 mysql-read 为我们要访问的svc服务如下


    [root@master3 etc]# kubectl get svc -o wide|egrep 'NAME|mysql'
    NAME                    CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE       SELECTOR
    mysql                   None           <none>        3306/TCP        8h        app=mysql
    mysql-read              172.1.86.83    <none>        3306/TCP        8h        app=mysql
    [root@master3 etc]# 
    
    k8s集群节点:
    [root@master3 etc]# kubectl get cs -o wide
    NAME                 STATUS    MESSAGE              ERROR
    controller-manager   Healthy   ok                   
    scheduler            Healthy   ok                   
    etcd-2               Healthy   {"health": "true"}   
    etcd-0               Healthy   {"health": "true"}   
    etcd-1               Healthy   {"health": "true"}   
    [root@master3 etc]# kubectl get node -o wide
    NAME            STATUS    AGE       VERSION   EXTERNAL-IP   OS-IMAGE                KERNEL-VERSION
    jenkins-2       Ready     14d       v1.6.4    <none>        CentOS Linux 7 (Core)   4.4.71-1.el7.elrepo.x86_64
    node1.txg.com   Ready     14d       v1.6.4    <none>        CentOS Linux 7 (Core)   4.4.71-1.el7.elrepo.x86_64
    node2.txg.com   Ready     14d       v1.6.4    <none>        CentOS Linux 7 (Core)   4.4.71-1.el7.elrepo.x86_64
    node3.txg.com   Ready     14d       v1.6.4    <none>        CentOS Linux 7 (Core)   4.4.71-1.el7.elrepo.x86_64
    node4.txg.com   Ready     14d       v1.6.4    <none>        CentOS Linux 7 (Core)   3.10.0-514.6.2.el7.x86_64
    [root@master3 etc]# 
    
    
    [root@master3 etc]# kubectl get pod --all-namespaces -o wide |egrep 'NAME|node|mysql|udp'
    NAMESPACE     NAME                                        READY     STATUS    RESTARTS   AGE       IP              NODE
    default       cnetos6-7-rc-xv12x                          1/1       Running   0          7d        172.1.201.225   node3.txg.com
    default       kibana-logging-3543001115-v52kn             1/1       Running   0          12d       172.1.26.70     node1.txg.com
    default       mysql-0                                     2/2       Running   0          10h       172.1.201.236   node3.txg.com
    default       mysql-1                                     2/2       Running   0          10h       172.1.24.230    jenkins-2
    default       mysql-2                                     2/2       Running   1          10h       172.1.160.213   node4.txg.com
    default       nfs-client-provisioner-278618947-wr97r      1/1       Running   0          12d       172.1.201.201   node3.txg.com
    kube-system   calico-node-5r37q                           2/2       Running   3          14d       192.168.2.72    jenkins-2
    kube-system   calico-node-hldk2                           2/2       Running   2          14d       192.168.2.68    node3.txg.com
    kube-system   calico-node-pjdj8                           2/2       Running   4          14d       192.168.2.69    node4.txg.com
    kube-system   calico-node-rqkm9                           2/2       Running   2          14d       192.168.1.68    node1.txg.com
    kube-system   calico-node-zqkxd                           2/2       Running   0          14d       192.168.1.69    node2.txg.com
    kube-system   heapster-v1.3.0-1076354760-6kn4m            4/4       Running   4          13d       172.1.160.199   node4.txg.com
    kube-system   kube-dns-474739028-26gds                    3/3       Running   3          14d       172.1.160.198   node4.txg.com
    kube-system   nginx-udp-ingress-controller-c0m04          1/1       Running   0          1d        192.168.2.72    jenkins-2
    [root@master3 etc]# 
    
    
    
    k8s证书如下:
    [root@node3 kubernetes]# ls
    bootstrap.kubeconfig  kubelet.kubeconfig  kube-proxy.kubeconfig  ssl  token.csv
    [root@node3 kubernetes]# 
    
    角色名称:边界网关路由器     192.168.2.71  主机名 jenkins-1     主机名自己定义
    角色名称:边界dns代理服务器  192.168.2.72  主机名 jenkins-2     主机名自己定义
    
    架构原理:  
    
              192.168.0.0/16                #物理网络以域名或tcp方式发起访问k8s service以及端口
                     '
                     '
      mysql-read.default.svc.cluster.local  #请求k8s服务所在空间的服务名svc名,完整域名
                     '
                     '   
              192.168.2.72                   #dns代理服务以ingress-udp pod的模式运行在此节点udp53号端口上 
                     '                       ,为物理网络提供仿问k8s-dns的桥梁解析dns
                     '                      #此节点应固定做为一个节点布署,所有外部设置dns为此192.168.2.72
                     ' 
               172.1.86.83                  #获取svc的实际clusterip
                     '
                     ' 
               192.168.2.71          #边界网关,用于物理网络连接k8s集群内内核转发开启net.ipv4.ip_forward=1
                     '               #所有外部物理机加一条静态路由访问k8s网络172网段必需经过网关192.168.2.71 
                     '               #route add -net 172.1.0.0 netmask 255.255.0.0 gw 192.168.2.71
                     '               #边界网关运行kube-proxy用于防火墙规则同步实现svc分流,此节点不运行kubele服务,不受k8s管控
        calico and flannel-Iface接口  #此节点为物理节点,只运行calico 或flanne服务 
                     '
                k8s集群网络            #流量最终到达k8s集群
    
    #布署dns代理服务节点为外部提供服务,以 hostNetwork: true 为非k8s集群网络物理机节点提共访问53 dns服务
    [root@master3 udp]# ls
    nginx-udp-ingress-configmap.yaml  nginx-udp-ingress-controller.yaml
    
    [root@master3 udp]# cd ../ ; kubectl create -f udp/
    [root@master3 udp]# cat nginx-udp-ingress-configmap.yaml
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: nginx-udp-ingress-configmap
      namespace: kube-system
    data:
      53: "kube-system/kube-dns:53"
    [root@master3 udp]# cat nginx-udp-ingress-controller.yaml
    apiVersion: v1
    kind: ReplicationController
    metadata:
      name: nginx-udp-ingress-controller
      labels:
        k8s-app: nginx-udp-ingress-lb
      namespace: kube-system
    spec:
      replicas: 1
      selector:
        k8s-app: nginx-udp-ingress-lb
      template:
        metadata:
          labels:
            k8s-app: nginx-udp-ingress-lb
            name: nginx-udp-ingress-lb
        spec:
          hostNetwork: true
          terminationGracePeriodSeconds: 60
          containers:
          #- image: gcr.io/google_containers/nginx-ingress-controller:0.9.0-beta.8
          - image: 192.168.1.103/k8s_public/nginx-ingress-controller:0.9.0-beta.5
            name: nginx-udp-ingress-lb
            readinessProbe:
              httpGet:
                path: /healthz
                port: 10254
                scheme: HTTP
            livenessProbe:
              httpGet:
                path: /healthz
                port: 10254
                scheme: HTTP
              initialDelaySeconds: 10
              timeoutSeconds: 1
            env:
              - name: POD_NAME
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.name
              - name: POD_NAMESPACE
                valueFrom:
                  fieldRef:
                    fieldPath: metadata.namespace
            ports:
            - containerPort: 81
              hostPort: 81
            - containerPort: 443
              hostPort: 443
            - containerPort: 53
              hostPort: 53
            args:
            - /nginx-ingress-controller
            - --default-backend-service=$(POD_NAMESPACE)/default-http-backend
            - --udp-services-configmap=$(POD_NAMESPACE)/nginx-udp-ingress-configmap
    [root@master3 udp]# 
    
    
    布署gateway 边界网关节点,此节点只运行 calico 或者flannel 和kube-proxy
    echo 'net.ipv4.ip_forward=1' >>/etc/sysctl.conf ;sysctl -p
    1.k8s运行在calico集群上网络方式 ,calico集群安装方式详见本人另一篇文章 http://blog.csdn.net/idea77/article/details/73090403
    
    #本次安装的节点为docker方式运行
    [root@jenkins-1 ~]# cat calico-docker.sh 
    systemctl start docker.service
    /usr/bin/docker rm -f calico-node
    /usr/bin/docker run --net=host --privileged --name=calico-node -d --restart=always \
      -v /etc/kubernetes/ssl:/etc/kubernetes/ssl \
      -e ETCD_ENDPOINTS=https://192.168.1.65:2379,https://192.168.1.66:2379,https://192.168.1.67:2379 \
      -e ETCD_KEY_FILE=/etc/kubernetes/ssl/kubernetes-key.pem \
      -e ETCD_CERT_FILE=/etc/kubernetes/ssl/kubernetes.pem \
      -e ETCD_CA_CERT_FILE=/etc/kubernetes/ssl/ca.pem \
      -e NODENAME=${HOSTNAME} \
      -e IP= \
      -e CALICO_IPV4POOL_CIDR=172.1.0.0/16 \ 
      -e NO_DEFAULT_POOLS= \
      -e AS= \
      -e CALICO_LIBNETWORK_ENABLED=true \
      -e IP6= \
      -e CALICO_NETWORKING_BACKEND=bird \
      -e FELIX_DEFAULTENDPOINTTOHOSTACTION=ACCEPT \
      -v /var/run/calico:/var/run/calico \
      -v /lib/modules:/lib/modules \
      -v /run/docker/plugins:/run/docker/plugins \
      -v /var/run/docker.sock:/var/run/docker.sock \
      -v /var/log/calico:/var/log/calico \
    192.168.1.103/k8s_public/calico-node:v1.1.3
    
    #192.168.1.103/k8s_public/calico-node:v1.3.0
    [root@jenkins-1 ~]# 注意此入为-e CALICO_IPV4POOL_CIDR=172.1.0.0/16  k8s集群网络的网段一致
    
    注意,calicocatl 我是安装在k8s的master服务器上的,在主控节点上运行创建边界路由器
    此处在master3服务器上执行开通边界网关这台机的calicoctl用于管理BGP 的命令。它主要面向在私有云上运行的用户,并希望与其底层基础架构对等。
    [root@master3 calico]# cat bgpPeer.yaml 
    
    apiVersion: v1
    kind: bgpPeer
    metadata:
      peerIP: 192.168.2.71
      scope: global
    spec:
      asNumber: 64512
    
    
    [root@master3 calico]#  calicoctl  create -f bgpPeer.yaml
    
    #查看node情况
    [root@master3 kubernetes]# calicoctl node status
    Calico process is running.
    
    IPv4 BGP status
    +--------------+-------------------+-------+----------+-------------+
    | PEER ADDRESS |     PEER TYPE     | STATE |  SINCE   |    INFO     |
    +--------------+-------------------+-------+----------+-------------+
    | 192.168.2.71 | node-to-node mesh | up    | 04:08:47 | Established |
    | 192.168.2.71 | global            | start | 04:08:43 | Idle        |
    | 192.168.2.72 | node-to-node mesh | up    | 04:08:47 | Established |
    | 192.168.1.61 | node-to-node mesh | up    | 04:08:47 | Established |
    | 192.168.1.62 | node-to-node mesh | up    | 04:08:47 | Established |
    | 192.168.1.68 | node-to-node mesh | up    | 04:08:48 | Established |
    | 192.168.1.69 | node-to-node mesh | up    | 04:08:47 | Established |
    | 192.168.2.68 | node-to-node mesh | up    | 04:08:47 | Established |
    | 192.168.2.69 | node-to-node mesh | up    | 04:08:47 | Established |
    +--------------+-------------------+-------+----------+-------------+
    
     #查看全局对等体节点
     [root@master3 calico]# calicoctl get bgpPeer --scope=global
    SCOPE    PEERIP         NODE   ASN     
    global   192.168.2.71          64512   
    
    [root@master3 calico]# ok calico配置完成 192.168.2.71 为路由转发节点
    
    
    
    2.flannel方式,如果k8s集群是运行在flannel网络基础上的 在此节点安装flannel 
    直接启动flannel即可 systemctl start flanneld.service 
    
    echo 'net.ipv4.ip_forward=1' >>/etc/sysctl.conf ;sysctl -p
    
    
    
    3.布署kube-proxy.service
    kube-proxy.service 需要证书kube-proxy.kubeconfig ,复制k8s node上的kubeconfig /etc/kubernetes/kube-proxy.kubeconfig 到此节点处即可
    #复制kube-proxy的二进至文件到些处即可 
    [root@jenkins-1 ~]#  mkdir -p /var/lib/kube-proxy
    [root@jenkins-1 ~]#  rsync -avz node3:/bin/kube-proxy /bin/kube-proxy
    
    #kube-proxy服务
    [root@jenkins-1 ~]# cat /lib/systemd/system/kube-proxy.service 
    [Unit]
    Description=Kubernetes Kube-Proxy Server
    Documentation=https://github.com/GoogleCloudPlatform/kubernetes
    After=network.target
    [Service]
    WorkingDirectory=/var/lib/kube-proxy
    ExecStart=/bin/kube-proxy \
    --bind-address=192.168.2.71 \
    --hostname-override=jenkins-1 \
    --cluster-cidr=172.1.0.0/16 \
    --kubeconfig=/etc/kubernetes/kube-proxy.kubeconfig \
    --logtostderr=true \
    --proxy-mode=iptables \
    --v=2
    Restart=on-failure
    RestartSec=5
    LimitNOFILE=65536
    [Install]
    WantedBy=multi-user.target
    [root@jenkins-1 ~]# 
    #启动 systemctl start kube-proxy.service
    
    
    4.测试网关和dns解析 以及服务访问情况
    #上面我说过了,所有K8S集群外机器要想访问必需要加一条静态路由
    linux 机器命令 ,找台集群外的机器来验证,这台机器只有一个网卡,没有安装calico和 flannel
    
    [root@247 ~]#route add -net 172.1.0.0 netmask 255.255.0.0 gw 192.168.2.71
    检查路由 route -n
    Kernel IP routing table
    Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
    0.0.0.0         192.168.5.1     0.0.0.0         UG    0      0        0 eth0
    169.254.0.0     0.0.0.0         255.255.0.0     U     1002   0        0 eth0
    172.1.0.0       192.168.2.71    255.255.0.0     UG    0      0        0 eth0 #注意看此处已经设置了网段路由生效了
    192.168.0.0     0.0.0.0         255.255.0.0     U     0      0        0 eth0
    192.168.1.0     0.0.0.0         255.255.255.0   U     0      0        0 eth0
    
    linux 服务器dns设置为该机dns 192.168.2.72 为了能解析K8Sdns服务名
    [root@247 ~]# egrep 'DNS' /etc/sysconfig/network-scripts/ifcfg-eth0 
    IPV6_PEERDNS="yes"
    DNS1="192.168.2.72"
    
    
    
    [root@247 ~]# nslookup  kubernetes-dashboard.kube-system.svc.cluster.local
    Server:     192.168.2.72
    Address:    192.168.2.72#53
    
    Non-authoritative answer:
    Name:   kubernetes-dashboard.kube-system.svc.cluster.local
    Address: 172.1.8.71
    
    #dns成功解析
    访问一下 curl  成功访问
    [root@247 ~]# curl -v kubernetes-dashboard.kube-system.svc.cluster.local
    * About to connect() to kubernetes-dashboard.kube-system.svc.cluster.local port 80 (#0)
    *   Trying 172.1.8.71...
    * Connected to kubernetes-dashboard.kube-system.svc.cluster.local (172.1.8.71) port 80 (#0)
    > GET / HTTP/1.1
    > User-Agent: curl/7.29.0
    > Host: kubernetes-dashboard.kube-system.svc.cluster.local
    > Accept: */*
    > 
    < HTTP/1.1 200 OK
    < Accept-Ranges: bytes
    < Cache-Control: no-store
    < Content-Length: 848
    < Content-Type: text/html; charset=utf-8
    < Last-Modified: Thu, 16 Mar 2017 13:30:10 GMT
    < Date: Thu, 29 Jun 2017 06:45:47 GMT
    < 
     <!doctype html> <html ng-app="kubernetesDashboard"> <head> <meta charset="utf-8"> <title ng-controller="kdTitle as $ctrl" ng-bind="$ctrl.title()"></title> <link rel="icon" type="image/png" href="assets/images/kubernetes-logo.png"> <meta name="viewport" content="width=device-width"> <link rel="stylesheet" href="static/vendor.4f4b705f.css"> <link rel="stylesheet" href="static/app.93b90a74.css"> </head> <body> <!--[if lt IE 10]>
          <p class="browsehappy">You are using an <strong>outdated</strong> browser.
          Please <a href="http://browsehappy.com/">upgrade your browser</a> to improve your
          experience.</p>
    * Connection #0 to host kubernetes-dashboard.kube-system.svc.cluster.local left intact
        <![endif]--> <kd-chrome layout="column" layout-fill> </kd-chrome> <script src="static/vendor.6952e31e.js"></script> <script src="api/appConfig.json"></script> <script src="static/app.8a6b8127.js"></script> </body> </html> 
    
    
    
    
    
    windows机器用管理员打开cmd命令运行 route ADD -p 172.1.0.0 MASK 255.255.0.0 192.168.2.71 
    
    角色名称:边界dns代理服务器  192.168.2.72  主机名 jenkins-2     主机名自己定义
    
    windowsip配置里面 dns 服务器设置为该机dns  192.168.2.72
    
    
    我们测试访问k8s的mysql服务 
    
    mysql-read 为我们要访问的svc服务,k8s master上查看mysql svc 
    
    [root@master3 etc]# kubectl get svc -o wide|egrep 'NAME|mysql'
    NAME                    CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE       SELECTOR
    mysql                   None           <none>        3306/TCP        8h        app=mysql
    mysql-read              172.1.86.83    <none>        3306/TCP        8h        app=mysql
    cmd 命令行运行
    
    C:\Users\op>nslookup mysql-read.default.svc.cluster.local
    服务器:  UnKnown
    Address:  192.168.2.72
    
    非权威应答:
    名称:    mysql-read.default.svc.cluster.local
    Address:  172.1.86.83
    
    #成功访问dns 并解析出域名
    如果知道容器ip 和端口直接访问即可,如ssh web服务 等
    [root@master3 udp]# kubectl get pod,svc -o wide|egrep 'NAME|kibana'
    NAME                                        READY     STATUS    RESTARTS   AGE       IP              NODE
    po/kibana-logging-3543001115-v52kn          1/1       Running   0          12d       172.1.26.70     node1.txg.com
    
    NAME                        CLUSTER-IP     EXTERNAL-IP   PORT(S)         AGE       SELECTOR
    svc/kibana-logging          172.1.166.83   <nodes>       5601:8978/TCP   12d       k8s-app=kibana-logging
    [root@master3 udp]# 
    
    
    [root@master3 udp]# kubectl get pod -o wide
    NAME                                     READY     STATUS    RESTARTS   AGE       IP              NODE
    cnetos6-7-rc-xv12x                       1/1       Running   0          8d        172.1.201.225   node3.txg.com
    kibana-logging-3543001115-v52kn          1/1       Running   0          12d       172.1.26.70     node1.txg.com
    
    **如果你不想一台台机器加路由和dns
    你可以把路由信息加入物理路由器上,这样就不用每台机都加路由和dns了,直接打通所有链路**
    
    
    
    
    

    接下来在windows只接仿问dashboard 和用navicat仿问k8s服务,完美成功访问
    这对于在windows用开发工具调试访问k8s服务提供了捷径
    直接浏览器仿问kubernetes-dashboard.kube-system.svc.cluster.local
    直接用mysql工具仿问mysql服务 mysql-read.default.svc.cluster.local
    直接用浏览器访问kibana http://172.1.26.70 :5601
    这里写图片描述
    这里写图片描述
    这里写图片描述
    这里写图片描述

    展开全文
  • 服务器基础知识——扩展插槽

    千次阅读 2011-02-12 22:15:00
    <br />摘要:扩展插槽是主板上用于固定扩展卡并将其连接到系统总线上的插槽,也叫扩展槽、扩充插槽。 扩展插槽   扩展插槽是主板上用于固定扩展卡并将其连接到系统总线上的插槽,也叫扩展槽、...
  • 模块:Ethernet W5100网络扩展模块 开发工具:零知开源开发工具 功能:实现一个简单Web服务器。 2、操作步骤 (1)硬件连接 使用的是以太网扩展板-W5100模块,该扩展板采用了...
  • 网络安全-扩展ACL访问控制列表配置

    千次阅读 2019-08-09 10:48:54
    一.实验要求 1.全网互通 1).将server1及server2设置...禁止PC1访问server1的web服务,但可以访问server1的其它服务2).PC2只能访问server1的web服务,不可以访问server1的其它服务 3).禁止PC1及PC2ping server2,...
  • Windows 10打开SecoClient 提示网络扩展启动失败 卸载已经安装的SecoClient ,并清除所有软件数据 重启电脑,以管理员身份运行SecoClient安装包进行安装 安装完成后以管理员身份运行并配置连接和输入用户密码...
  • 白皮书:Qt集成Webkit渲染、使用和扩展网络技术

    千次下载 热门讨论 2009-08-19 10:05:29
    有了此类混合模式的服务,就可以高效地构建和发布很难或无法仅通过网络 API 或本地开发环境单 独开发的功能。由于融合了网络技术的简易性和 Qt 应用程序框架的强大功能,设计人员和编码人员可 专注于自己最擅长的...
  • 20202 节点1 群组1 127.0.0.1:30302 127.0.0.1:8547 0.0.0.0:20203 机构C 节点0 群组1 127.0.0.1:30303 127.0.0.1:8548 0.0.0.0:20204 节点1 群组1 127.0.0.1:30305 127.0.0.1:8550 0.0.0.0:20205 现扩展机构B多一个...
  • 场景介绍:一般我们在做性能压测的时候,需要关注服务器的cpu、内存、磁盘、网络等情况。有很多监控的工具,这个是直接在jmeter上使用的监控。我这个步骤是依据压测执行脚本是在linux服务器上的,按道理也可以直接在...
  • 唯一包含的网络处理是基于 HTTP 协议提供媒体流服务,和流状态信息和嵌入脚本的服务一样。   可扩展性  MistServer 是考虑到以可扩展性为主要需求进行设计的。它创建时的每一部分,从 连接器 到控制层都被设计于...
  • 简要步骤如下: 一、建立网络数据集 二、发布地图服务 三、访问Network Analyst服务
  • Thrift可扩展高性能的通信服务框架

    千次阅读 2015-07-07 15:34:40
    Thrift可扩展高性能的通信服务框架 The Apache Thrift software framework, for scalable cross-language services development, combines a software stack with a code generation engine to build services that...
  • kotlin的扩展方法,其实是以java的静态方法形式存在的,也就是说如果要用java调用kotlin的扩展方法,和调用静态函数一样 调用扩展属性也是相同的道理 举个例子,我们在某个kotlin文件(文件名为Utils.kt)里为...
  • 在互联网应用领域,服务的动态性需求十分常见,这就对服务的自动发现和可动态扩展提出了很高的要求。 Docker 的出现,以及微服务架构的兴起,让众多开源项目开始关注在松耦合的架构前提下,如何基于 Docker 实现...
  • 扩展ACL

    千次阅读 2019-05-29 21:01:00
    扩展ACL 实验拓扑以及地址规划 要求: 拒绝PC0 所在网段访问Server 172.84.3.100 的Web 服务 拒绝PC1 所在网段访问Server 172.84.3.100 的Ftp 服务 拒绝PC0 所在网段访问Server 172.84.3.100 的SQL 服务 ...
  • 六大服务器和网络监控工具

    万次阅读 2016-11-04 16:21:49
    OpenNMS  OpenNMS 是网络管理系统Network Management System 的简称,是一种开源软件网络监视工具。可用来自动发现网络节点,监控网络服务,如 HTTP,DNS... 它可以支持SNMP网络管理协议,确保管理的扩展性,并
  • 扩展架构介绍

    千次阅读 2019-06-23 12:40:54
    面向服务拆分:将系统提供的服务拆分 面向功能拆分:将系统提供的功能拆分 一般说来,流程>服务>功能。下图是一个简单示例: 2、扩展模式分析 做好架构,系统在实际工作时才好按照团队设计好工作分解...
  • 许多这样的企业会觉得有必要扩大或向外扩展他们的应用基础设施,以跟上需求的步伐。  许多企业早有先见之明,在基础设施创建之初就考虑到了既要满足当前的需要,又可以允许在未来有适度的扩展(或可伸缩性)。...
  • 理解水平扩展和垂直扩展

    千次阅读 2018-03-11 09:35:53
    当一个开发人员提升计算机系统负荷时,通常会考虑两种方式垂直扩展和水平扩展。选用哪种策略主要依赖于要解决的问题 以及系统资源的限制。在这篇文章中我们将讲述这两种策略并讨论每种策越的优缺点。如果你已经有一...
  • 设计新Xlator扩展GlusterFS

    万次阅读 热门讨论 2012-07-25 20:16:18
    GlusterFS是一个开源的分布式文件系统,具有强大的Scale-Out横向扩展能力,通过扩展能够支持数PB存储容量和处理数千客户端。GlusterFS借助TCP/IP或InfiniBand RDMA网络将物理分布的存储资源聚集在一起,使用单一全局...
  • 100 个网络基础知识普及,看完成半个网络高手

    万次阅读 多人点赞 2019-09-23 11:38:54
    1)什么是链接? 链接是指两个设备之间的连接。它包括用于一个设备...骨干网络是集中的基础设施,旨在将不同的路由和数据分发到各种网络。它还处理带宽管理和各种通道。 4)什么是 LAN? LAN 是局域网的缩写。...
  • 引言 发布网络分析服务 1利用ArcMap创建网络 2将创建的地图进行符号化 3开启网络分析权限并添加分析图层 4修改属性并将其发布为网络服务
  • 配置扩展ACL

    千次阅读 2019-05-22 20:39:33
    为了实现更灵活、列精确的网络控制就需要用到扩展访问控制列表了。 扩展IP访问控制列表比标准IP访问控制列表具有更多的匹配项,包括协议类型、源地址、目的地址、源端口、目的端口、建立连接的和IP优先级等。 网络...
  • 简单的说就是在对现有系统影响最小的情况下,系统功能可持续扩展及提升的能力,讲扩展性之前,我先讲下扩展性和伸缩性的区别,因为这两个点经常有人会混淆; 扩展性:指对现有系统影响最小的情况下,系统功能可持续...
  • 说起Apache和IIS网络服务器,真可谓无人不知,其应用之广也是首屈一指。...高可扩展性稳定易配置轻巧:CPU负载低,资源占用率低,内存占用率低  这些网络服务器大多都是免费的,几乎都可以用于提供
  • 这是作者的网络安全自学教程系列,主要是关于安全工具和实践操作的在线笔记,特分享出来与博友们学习,希望您们喜欢,一起进步。前文分享了木马原理知识,并通过远程服务器IPC $ 漏洞实现木马植入及控制远程服务器。...
  • 翻译说明: 完成端口基本上公认为一种在windows服务平台上比较成熟和高效的IO方法,理解和编写程序都不是很困难。目前我正在进行这方面的实践,代码还没有完全调试和评价,只有这一篇拙劣的学习翻译文摘,见笑见笑。...
  • 对服务器的请求已遭到某个扩展程序的阻止net::ERR_BLOCKED_BY_CLIENT

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 710,026
精华内容 284,010
关键字:

网络扩展服务