精华内容
参与话题
问答
  • 通信原理MATLAB仿真教程 《通信原理MATLAB仿真教程》系统地介绍了通信原理MATLAB仿真的基本思想与方法,重点讨论了MATLAB对常见信号与线性系统、模拟调制、模拟信号的数字传输、数字信号的基带传输、数字信号的频带...
  • Web服务器工作原理详解(基础篇)

    万次阅读 多人点赞 2018-08-14 17:12:00
    概述:Web服务器概念较为广泛,我们最常说的Web服务器指的是网站服务器,它是建立在Internet之上并且驻留在某种计算机上的程序。Web服务器可以向Web客户端(如浏览器)提供文档或其他服务,只要是遵循HTTP协议而... ...

    概述:Web服务器概念较为广泛,我们最常说的Web服务器指的是网站服务器,它是建立在Internet之上并且驻留在某种计算机上的程序。Web服务器可以向Web客户端(如浏览器)提供文档或其他服务,只要是遵循HTTP协议而设计的网络应用程序都可以是Web客户端。

    Web服务器和HTTP服务器可以说是同一个东西,当然非得细分的话,HTTP服务器是建立在HTTP协议之上的提供文档浏览的服务器,更多的是提供静态的文件。而Web服务器涵盖了HTTP服务器(这一点可以自行百度百科), Web服务器不仅能够存储信息,还能在用户通过Web浏览器提供的信息的基础上运行脚本和程序。
    Web服务器 约等于 HTTP服务器 + 其他服务

    目前所熟知的Web服务器有很多,其最主流的是 Apache, Nginx, IIS
    各大Web服务器的实现细节都不同,是为了某种情形而设计开发的。但是它们的基础工作原理是相同的,这也是本次基础篇所讲解的内容。

    一、Web服务器工作原理图解

    这里写图片描述
    首先我们暂时不考虑HTTP协议的各种请求方式,我们先跟着**(Web服务器工作原理总体描述01)这张图,将一次Web服务的工作流程过一遍,我们假设以浏览器作为客户端
    (1) 用户做出了一个操作,可以是填写网址敲回车,可以是点击链接,可以是点击按键等,接着浏览器获取了该事件。
    (2) 浏览器与对端服务程序建立TCP连接。
    (3) 浏览器将用户的事件
    按照HTTP协议格式**打包成一个数据包,其实质就是在待发送缓冲区中的一段有着HTTP协议格式的字节流。
    (4) 浏览器确认对端可写,并将该数据包推入Internet,该包经过网络最终递交到对端服务程序。
    (5) 服务端程序拿到该数据包后,同样以HTTP协议格式解包,然后解析客户端的意图。
    (6) 得知客户端意图后,进行分类处理,或是提供某种文件、或是处理数据。
    (7) 将结果装入缓冲区,或是HTML文件、或是一张图片等。
    (8) 按照HTTP协议格式将(7)中的数据打包
    (9) 服务器确认对端可写,并将该数据包推入Internet,该包经过网络最终递交到客户端。
    (10) 浏览器拿到包后,以HTTP协议格式解包,然后解析数据,假设是HTML文件。
    (11) 浏览器将HTML文件展示在页面
    以上为Web服务器工作基本原理。其实不难发现,这仅仅只是一个简单的网络通信。我们应该深信,作为一个服务器,其根本的工作无非有三个

    1. 接收数据 2. 发送数据 3. 数据处理
      而Web服务器的本质就是 接收数据 ⇒ HTTP解析 ⇒ 逻辑处理 ⇒ HTTP封包 ⇒ 发送数据
      高级的服务器无非就是将这三个部分更加细致的设计了。

    二、Web服务器之提供静态文件工作原理图解

    Web服务器最主要的功能是提供静态的文件。日常的上网浏览大多是网页浏览,少数时候才会有一些数据的提交操作。因此,我们结合上一张图示来重点讲解在GET请求下的Web服务器工作原理。
    这里写图片描述
    其他流程基本不变,着重在于红色与蓝色部分。
    (1) 当用户点击一个网页链接或浏览器加载一些资源(css,jpg …)时产生。
    (6) 服务程序解包后,确定其为GET请求,并且是对该服务器上的某一资源的请求。首先服务程序会去确认该路径是否存在,再确定该路径的文件是否可以获取。
    (7-1) 如果请求的路径有误,或者该资源不能被用户获取,则返回错误提示页面。很多服务器的错误页面只有404,更专业的应该是将错误分类并返回对应的错误代码页面。
    (7-2) 如果该路径合法且文件可以被获取,那么服务程序将根据该文件类型进行不同的装载过程,记录其类型作为(8)中HTTP协议中对应的返回类型,并加入响应头。

    假设以点击一个页面链接为例,浏览器首先将HTML文件请求过来,再以同样的流程对HTML文件中包含的资源文件路径进行依次请求。
    这里写图片描述

    三、Web服务器之数据提交工作原理图解

    仅仅只是网页的浏览并不能满足所有人的需求,客户端与服务器应当是有数据交互的。
    即使单方面的资源请求任然是网络的主力军。
    我们应该清楚的知道,数据提交对于用户来说有什么作用。
    (1) 资源上传 (2) 登陆验证 (3) API接口调用 (4) 远程指令等
    数据提交使得用户的操作性有了质的飞跃,它使得HTTP短连接获取静态文件的方式提升到了动态交互的层次上。该性质也催化出各式各样的编程语言、框架。例如PHP,JavaWeb。
    如果你留意目前主流的那些大型服务器,你会发现再高级再牛逼的东西实际是也是最基础的东西建造的。那么我们还可以顺便学习一下最古老的动态技术CGI
    这里写图片描述
    其他流程基本不变,着重在于红色与蓝色部分。
    (1) 用户提交数据,假设用户点击一个按键提交填好的信息。在(3)中将以POST格式写入,并填入提交至服务端的可执行程序的路径。
    (6) 服务端将参数与该CGI绑定,复制进程,用管道传递参数和接收结果
    (7) 子进程执行CGI,接收(6)父进程传来的参数,运算完成返回结果。
    最后父进程将结果装入静态模板文件,放入缓冲区

    四、动态技术

    我们得明白,Web服务器是以短连接为主,并且获取的数据到达浏览器的那一刻一定是静态的不变的。那么所谓动态实际是指两种情况

    1. 服务端产生
      (1) 用户POST提交数据到某个程序,程序根据该数据作为参数运行,得出结果并装入静态的模板页面中,返回该静态页面。但对于用户来说,同一个页面,做了一个操作后数据不一样了。好了,这就是动态页面。(CGI原理)
      (2) PHP的原理是,用户GET请求一个php后缀的文件,服务器先执行该php后缀文件中的PHP代码,将结果填入代码的位置,再返回。当然也可以提交数据参与运算再返回。
    2. 客户端产生
      (1) 用户GET请求一个JavaScript文件,服务端不做任何运算返回该静态文件。浏览器收到该JS文件,在本地执行并更新页面。
      (2) 用户POST提交数据到服务端,服务端根据该提交的数据指令返回静态文件,浏览器收到后执行并更新。
    展开全文
  • BT下载原理简介

    万次阅读 2017-06-26 14:27:58
    1. BT下载原理简介 BT是一种用来进行文件下载的共享软件(不是“变态”),全名叫"BitTorrent"。BitTorrent是一个多点下载的源码公开的P2P软件,使用非常方便,就像一个浏览器插件,很适合新 发布的热门下载。其...

    1.   BT下载原理简介

    BT是一种用来进行文件下载的共享软件(不是“变态”),全名叫"BitTorrent"。BitTorrent是一个多点下载的源码公开的P2P软件,使用非常方便,就像一个浏览器插件,很适合新

    发布的热门下载。其特点简单的说就是:下载的人越多,速度越快 。

     

    一般来讲,下载是把文件由服务器端传送到客户端,例如FTP,HTTP,PUB等等。工作原理如下图:

    但是这样就出现了一个问题,随着用户的增多,对带宽的要求也随之增多,用户过多就会造成瓶颈,而且搞不好还会把服务器挂掉,所以很多的服务器会都有用户人数的限制,下载速度的限制,这样就给用户造成了诸多的不便。

     

    但BT就不同,用BT下载反而是用户越多,下载越快,这是为什么呢?因为BT用的是一种传销的方式来达到共享的,工作原理如下图:

    BT首先在上传者端把一个文件分成了Z个部分,甲在服务器随机下载了第N各部分,乙在服务器随机下载了第M个部分,这样甲的BT就会根据情况到乙的电脑上去拿乙已经下载好的M部分,乙的BT就会根据情况去到甲的电脑上去拿甲已经下载好的N部分,这样就不但减轻了服务器端得负荷,也加快了用户方(甲乙)的下载速度,效率也提高了,更同样减少了地域之间的限制。比如说丙要连到服务器去下载的话可能才几K,但是要是到甲和乙的电脑上去拿就快得多了。所以说用的人越多,下载的人越多,大家也就越快,BT的优越性就在这里。而且,在你下载的同时,你也在上传(别人从你的电脑上拿那个文件的某个部分),所以说在享受别人提供的下载的同时,你也在贡献。

    2.  BT协议介绍

    2.1.  综述

    BitTorrent(简称BT,比特洪流)是一个文件分发协议。它通过URL识别内容并且和网络无缝结合。它和普通HTTP协议相比优势在于,同时下载一个文件的下载者在下载同时不断互相上传数据,使文件源可以在很有限的负载增加的情况下支持大量下载者同时下载。

     

    一个BT式文件分发需要以下实体:

    l  一个普通网络服务器

    l  一个静态元信息文件('Metainfo' file)

    l  一个BT Tracker

    l  一个“原始”下载者('original'downloader)

    l  网络终端的浏览器

    l  网络终端的下载者

    这里假设理想情况下一个文件有多个网络终端的下载者。

     

    架设一个BT服务器步骤如下:

    1.开始运行Tracker(已运行的跳过这一步);

    2.开始运行普通网络服务器程序,如Apache,已运行的跳过这一步;

    3.在网络服务器上将.torrent文件关联到Mime类型application/x-bittorrent(已做过关联的跳过这一步);

    4.用要发布的完整文件和Tracker的URL创建一个元信息文件(.torrent文件);

    5.将元信息文件放置在网络服务器上;

    6.在网页上发布元信息文件(.torrent文件)的链接;

    7.原始下载者开始提供完整的文件(原本)。

     

    通过BT下载步骤如下:

    1.安装BT客户端程序(已安装的跳过这一步);

    2.上网;

    3.点击一个链到.torrent文件的链接;

    4.选择本地存储路径,或者选定未完成的下载的续传;

    5.等待下载完成;

    6.下载者退出下载(之前下载者不停止上传)。

    连通性如下:

    l  网站正常提供静态文件,并且启动客户端上的BitTorrenthelper(这里说官方的客户端程序);

    l  Tracker即时接收所有下载者信息,并且给每个下载者一份随机的peer列表。通过HTTP或HTTPS协议实现;

    l  下载者定时向Tracker登记,使之知道每个人的进度,并和那些直接连接上的peer互相进行数据的上传下载。这些连接遵循BitTorrent peer协议,通过TCP协议进行通信。

    l  原始下载者只上传不下载,他拥有整个文件,所以向网络中传输完文件的所有部分是很必要的。在一些人气很旺的下载中,原始下载者经常可以在较短的时间后退出上传,因为许多下载已经完成,并且可能依然在运行(此时相当于替原始下载者接着提供上传)。

     

    2.2.  B编码及元信息文件

    元信息文件和Tracker的回应信息都以一种简单高效可扩展的格式(Bencoding,B编码格式)传送。B编码过的信息就是字典和列表的嵌套(像在Python中一样),这些字典和列表包含字符串和整型数据。它的可扩展性是因为字典中存在被忽略的关键值(key),所以附加可选的关键值也可以在以后添加。

    B编码的规则如下:

    l  字符串表示为前缀十进制的字符串长度加冒号再跟原字符串。
    如4:spam就相当于'spam'。

    l  整型数据的表示是前面加'i'后面加'e'中间是十进制数,如i3e就相当于3,i-3e就是-3。整型数据没有长度限制。i-0e无效,所有以'i0'开头的除了代表0的i0e,其它都无效。

    l  列表编码为一个'l'开头,后面跟它所包含的项目(已经被编码过)最后加一个'e',比如 l4:spam4:eggse 就等于 ['spam', 'eggs'] 。

    l  字典编码为一个'd'开头,后面是关键值(key)及其对应值轮流出现,最后加一个'e'。如:d3:cow3:moo4:spam4:eggse 相当于 {'cow': 'moo', 'spam': 'eggs'} d4:spaml1:a1:bee相当于 {'spam':['a', 'b']} 关键值必须是处理过的字符串(用原始字符串编码的,而不是数字字母混合编码的)。

     

    元信息文件就是B编码的有以下关键值的字典(括号里面的字是简译的关键值中文意思,不作为关键值一部分,后同):

    announce(声明):Tracker的URL。

    info(信息):此关键值对应一个包含以下关键值的字典。

    l  关键值name对应一个字符串,代表默认的下载文件(或保存时目录)的名字。它是纯粹建议性的。

    l  关键值piece length(块长)对应文件分割成的块的字节数。出于传输需要,文件被分割成大小相等的块,除了最后一块可能会被文件尾截断而小一些(剩下的大小不足一个块长)。块长一般来说是2的权值,大部分设块长为256K即2的18次幂(BitTorrent官方版3.2版本以前的默认值是1M,2的20次幂)。

    l  关键值pieces(块)对应一个字符串,此字符串长度是20的倍数。它可以再分成每20字节一段的多个字符串,分别对应块在相应索引中的SHA1校验码(hash)。

    l  关键值length(长度)和files(文件),它们不能同时出现也不能都不出现。当length出现说明这个元信息文件只是提供单文件下载(the single filecase),否则说明是多文件下载(themulti-file case),载到一个目录里。

    单文件情况下,length对应文件长度的字节数。多文件情况被看作是把许多单文件按文件列表中的顺序连成一个大文件下载,

    而关键值files就对应文件列表,是一个字典的列表,其中每个字典又包含以下关键值:

    l  length(长度):文件长度的字节数。

    l  path(路径):一个包含字符串的列表,字符串就是子目录名,最后一项的字符串就是文件本身的文件名。(一个长度为零的length表单是错误的。)

     

    2.3.  Tracker HTTP协议

    Tracker质询是双向的。Tracker通过HTTP协议的GET参数获得信息,然后返回一个B编码后的信息。尽管Tracker需要在自己的服务器端执行,但它运行流畅就像Apache的一个嵌入模块。

     

    Tracker的GET请求有如下关键值:

    l  info_hash
    20字节长的SHA1验证码,就是元信息文件中的info值中分出来的字符串进行B编码以后的信息,是元信息文件的一个支链。这个值必须是自动转换的。

    l  peer_id
    一个20字节长的字符串,是每个用户开始新下载时随机生成的ID。这个值也必须是自动转换的。

    l  ip

    一个非强制性的参数(可有可无)给出peer所在的IP(或DNS主机名),一般是和Tracker同机器的原始下载者得到后用来散发文件。

    l  port

    监听端口,官方默认的是从6881端口开始试,如果端口被占用则依次向后推一个端口直到找到空闲端口,到6889端口没找到就放弃。

    l  uploaded

    目前总上传量,编码为十进制ASCII码。

    l  downloaded

    目前总下载量,编码为十进制ASCII码。

    l  left

    还要下载的字节数,编码为十进制ASCII码。这个数不能通过文件长度和已下载数出来的,因为文件可能是续传的,还可能有一些已经下载的数据不能通过完整性检查必须被重新下载。

    l  event

    这是个非强制性的关键值,有started,completed或stopped(或empty,等同于未运行)三种值。如果没有这个关键值,说明下载状态的声明也会从下载者那里定期发出。首次开始下载时发出started值,完成下载时发出completed。当文件完整后再开始,没有completed发出,下载者中止下载时发出stopped。

     

    Tracker的回应也是B编码字典。如果Tracker回应中有关键值failure reason(失败原因),则对应一个人易读懂的字符串信息,解释质询失败的原因,不需要其它关键值。

    否则,回应必须有两个关键值:

    l  interval(间隔):对应下载者定期发出请求的间隔秒数;

    l  peers,peers是个包含字典的列表,每个字典对应一个peer,里面包含关键值peer id、ip和port,分别对应peer自选ID、IP地址或DNS主机名的字符串以及端口号。记住假如下载者发生一个意外事件或者想要更多的peer列表,下载者会不定期重发请求。

    如果你想对元信息文件或者Tracker质询进行扩展,请与Bram Cohen进行协调,确保所有扩展都兼容。

    (downloader 通过 HTTP 的GET 命令来向 tracker 发送查询请求,tracker 响应一个peers 的列表)

     

    2.4.  BitTorrent peer protocol

        BT对等协议基于TCP,它很有效率,并不需要设置任何socket选项。(译注:BT对等协议指的是peer与peer之间交换信息的协议)

    对等的两个连接是对称的,消息在两个方向上同样的传递,数据也可以在任何一个方向上流动。一旦某个peer下载完了一个片断,并且也检查了它的完整性,那么它就向它所有的peers宣布它拥有了这个片断。

    Peer之间的上载和下载关系有其简单的机制来保证。

    在连接的任一端包含两个bit位用来指示连接状态:choked or not、interested or not。

    连接的任何一端都包含两比特的状态信息:choked or not(是否choked),interested or not(是否感兴趣)。Choking是通知对方,没有数据可以发送,除非unchoking发生。Choking的原因以及技术后文解释。

    一旦一端状态变为interested,而另一端变为非choking,那么数据传输就开始了。(也就是说,一个peer,如果想从它的某个peer那里得到数据,那么,它首先必须将它两之间的连接设置为 interested,其实就是发一个消息过去,而另一个peer,要检查它是否应该给这个家伙发送数据,如果它对这个家伙是 unchoke,那么就可以给它发数据,否则还是不能给它数据)Interested状态必须一直被设置――任何时候。要用点技巧才能比较好的实现这个目的,但它使得下载者能够立刻知道哪些peers将开始下载。

    对等协议

    由一个握手开始,后面是循环的消息流,每个消息的前面,都有一个数字来表示消息的长度。握手的过程

    首先是先发送19,跟着是字符串“BitTorrent protocol”。19就是“Bittorrentprotocol”的长度。后续的所有的整数,都采用big-endian 来编码为4个字节在协议名称之后,是8个保留的字节,这些字节当前都设置为0。接下来对元文件中的 info 信息,通过 sha1 计算后得到的hash值,20个字节长。接收消息方,也会对 info 进行一个 hash 运算,如果这两个结果不一样,那么说明对方要的文件,并不是自己所要提供的,所以切断连接。接下来是20个字节的 peer id。

    接下来就是以消息长度开始的消息流,这是可选的。长度为0 的消息,用于保持连接的活动状态,被忽略。通常每隔2分钟发送一个这样的消息。

    其它类型的消息,都有一个字节长的消息类型,可能的值如下:

    ‘choke’, ‘unchoe’, ‘interested’, not interested’类型的消息不再含有其它数据了。

    ‘bitfield’永远也仅仅是第一个被发送的消息。它的数据实际是一个位图,如果downloader已经发送了某个片断,那么对应的位置1,否则置0。Downloaders如果一个片断也没有,可以忽略这个消息。(通过这个消息,能知道什么了?)

    ‘have’类型的消息,后面的数据是一个简单的数字,它是下载者刚刚下载完并检查过完整性的片断的索引。(由此,可以看到,peer通过这种消息,很快就相互了解了谁都有什么片断)

    ‘request’类型的消息,后面包含索引、开始位置和长度)长度是2的幂。当前的实现都用的是215 ,而关闭连接的时候,请求一个超过2 17的长度。(这种类型的消息,就是当一个peer希望另一个peer给它提供片断的时候,发出的请求)

    ‘cancel’类型的消息,它的数据和’request’消息一样。它们通常只在下载趋向完成的时候发送,也就是在‘结束模式“阶段发送。在一次下载接近完成的时候,最后的几个片断需要很长时间才能下载完。为了确保最后几个片断尽快下载完,它向所有的peers发送下载请求。为了保证这不带来可怕的低效,一旦某个片断下载完成,它就其它peers发送’cancel’消息。(意思就是说,我不要这个片断了,你要是准备好了,也不用给我发了,可以想象,如果对方还是把数据发送过来了,那么这边必须忽略这些重复的数据)。

    ‘piece’类型的消息,后面保护索引号、开始位置和实际的数据。注意,这种类型的消息和 ‘request’消息之间有潜在的联系(译注:因为通常有了request消息之后,才会响应‘piece’消息)。如果choke和unchoke消息发送的过于迅速,或者,传输速度变的很慢,那么可能会读到一些并不是所期望的片断。( 也就是说,有时候读到了一些片断,但这些片断并不是所想要的)

    Choking 算法

    BT下载过程中没有一个统一的资源调度,所有的下载者都希望能够尽可能的提高下载速度,对等体之间从任何对端下载,同时礼尚往来的进行上传,就是说,在下载上传形成对子,对于不合作方,则在上传方向进行Choke(阻塞),比如我和你之间形成Pair,但是你只想下载不想上传,则把你Choke。Choking用于阶段性的阻止上载,但是在Choking结束后,上传可以继续进行。

    Choking算法不是BT链路协议的技术组成,但是对提高下载效率很有作用,一个好的Choking应该能够利用各种资源,保障参加下载的每个用户获得理想的下载速度,同时杜绝有人只下载不上载。

    每一个BT客户一般会不阻塞一定数量的对等体,所以应该决定哪些Peer应该不去阻塞,这个决定是是基于当前的下载速度,为提高效率,BT对20S内的下载速度进行计算,同时为避免频繁的计算在成效率下降,BT每隔10S进行一次计算,10S的时间也足够TCP机制达到最高的下载速度。另外,为了始终选择到能够提供最大下载速度的Peer,BT会使用一种‘optimistic unchoke’机制,每隔30s就循环的地Choke一个Peer,这样有机会去查询是否还有更好的下载对象。

     

    2.5.  BT限流的解决方案

    1、利用客户端与客户端连接的端口号:6m## o
    BT实现中,提供了一个端口范围(6881~6889),如果通过这个范围的所有端口来限

    流,一些运营商曾采用这种方法来封杀BT,如长城宽带和重庆网通曾采用这种方法来封堵

    BT。

        这种方法在前期一定程度上是可用的;因为:BT的官方网站提供了一个默认的监听端

    口范围(6881~6889)。但是,这种方法比较片面,因为通过一定的技术手段可以改变这个

    端口范围(网上有);另外,BT的客户端较多,它们所采用的端口范围及实现方式各不相

    同(见下表)。

                

    BT客户端

    端口范围

    贪婪ABC

    可以手工设置

    BitComet

    没有公开

    BitTorrent Plus

    可以手工设置

    BitTorrent

    6881~6889

    比特精灵Bit Spirit

    16881

      

       所以,采用这种方来对BT进行限流效果不是很好。

         

    2、对协议进行分析

    对所有的 ip 包都进行检查,如果 ip 包的数据区包含 BT 对等协议的特征“BitTorrent

    protocol”(BT协议规定),那么可以标识这是一个BT流,标识了以后,就可以采取相应的措施(CAR)对它进行限流。

    以下是通过对几种BT客户端的报文分析来验证上述方案。

    客户端:贪婪ABC

     

           由上图可以看贪婪ABC建立连接的过程是:

    1、 TCP的三次握手。

    2、 握手成功后,紧接着是BT对等协议的二次握手。

    3、 握手成功后,进行数据的传输。

    由图分析可知:

    1、 TCP三此握手与BT对等协议二次握手用的端口号都是一样的,并且以后得数据传输用的端口号也和前两者是一样的。

    2、 TCP头之后的BT对等协议的报文格式对应如下:

    19-对应图中的“13(十六进制)”

    ‘B’- 对应图中的“42(十六进制)”以后对应“Bittorrentprotocol”

    八个保留字节-对应图中的八个“00(十六进制)”

    info 信息-对应的报文有20个字节长

    总长为48字节

     

    客户端:BitTorrent Plus! 2

    由上图可以看BitTorrentPlus! 2建立连接的过程是:

    1、 TCP的三次握手。

    2、 握手成功后,紧接着是BT对等协议的二次握手。

    3、 握手成功后,进行数据的传输。

    由图分析可知:

    1、 TCP三此握手与BT对等协议二次握手用的端口号都是一样的,并且以后得数据传输用的端口号也和前两者是一样的。

    2、 TCP头之后的BT对等协议的报文格式对应如下:

    19-对应图中的“13(十六进制)”

    ‘B’- 对应图中的“42(十六进制)”以后对应“Bittorrentprotocol”

    八个保留字节-对应图中的八个“00(十六进制)”

    info 信息-对应的报文有20个字节长

    peer id-20个字节

    总长为68字节

     

     

     

    客户端:BitComet

     

    由上图可以看BitTorrentPlus! 2建立连接的过程是:

    1、TCP的三次握手。

    2、握手成功后,紧接着是BT对等协议的二次握手。

    3、握手成功后,进行数据的传输(图中显示握手没有成功)。

    由图分析可知:

    1、 TCP三此握手与BT对等协议二次握手用的端口号都是一样的,并且以后得数据传输用的端口号也和前两者是一样的。

    2、 TCP头之后的BT对等协议的报文格式对应如下:

    19-对应图中的“13(十六进制)”

    ‘B’- 对应图中的“42(十六进制)”以后对应“Bittorrentprotocol”

    八个保留字节-对应图中的八个“00(十六进制)”

    info 信息-对应的报文有20个字节长

    peer id-20个字节

    总长为68字节

     

    总结:

        1、三个不同客户端的报文验证了BT对等协议的连接过程是:

    (1)TCP的三次握手。

    (2)握手成功后,紧接着是BT对等协议的二次握手。

    (3)握手成功后,进行数据的传输。

    2、TCP三此握手与BT对等协议二次握手用的端口号都是一样的,并且以后得数据传输用的端口号也和前两者是一样的。

    3、TCP头之后的BT对等协议的报文格式对应如下:

    19-对应图中的“13(十六进制)”

    ‘B’- 对应图中的“42(十六进制)”以后对应“Bittorrentprotocol”

    八个保留字节-对应图中的八个“00(十六进制)”

    info 信息-对应的报文有20个字节长

     

     

    展开全文
  • hash算法原理详解

    万次阅读 多人点赞 2016-05-19 22:35:01
    一.概念 哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。 哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为...

    一.概念

    哈希表就是一种以 键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即key,即可查找到其对应的值。

    哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。

    使用哈希查找有两个步骤:

    1. 使用哈希函数将被查找的键转换为数组的索引。在理想的情况下,不同的键会被转换为不同的索引值,但是在有些情况下我们需要处理多个键被哈希到同一个索引值的情况。所以哈希查找的第二个步骤就是处理冲突

    2. 处理哈希碰撞冲突。有很多处理哈希碰撞冲突的方法,本文后面会介绍拉链法和线性探测法。

    哈希表是一个在时间和空间上做出权衡的经典例子。如果没有内存限制,那么可以直接将键作为数组的索引。那么所有的查找时间复杂度为O(1);如果没有时间限制,那么我们可以使用无序数组并进行顺序查找,这样只需要很少的内存。哈希表使用了适度的时间和空间来在这两个极端之间找到了平衡。只需要调整哈希函数算法即可在时间和空间上做出取舍。

     

     

    在Hash表中,记录在表中的位置和其关键字之间存在着一种确定的关系。这样我们就能预先知道所查关键字在表中的位置,从而直接通过下标找到记录。使ASL趋近与0.

     

                  1)   哈希(Hash)函数是一个映象,即: 将关键字的集合映射到某个地址集合上,它的设置很灵活,只要这个地       址集合的大小不超出允许范围即可;

                 2)  由于哈希函数是一个压缩映象,因此,在一般情况下,很容易产生“冲突”现象,即: key1!=key2,而  f  (key1) = f(key2)。

                  3).  只能尽量减少冲突而不能完全避免冲突,这是因为通常关键字集合比较大,其元素包括所有可能的关键字, 而地址集合的元素仅为哈希表中的地址值

     

           在构造这种特殊的“查找表” 时,除了需要选择一个“好”(尽可能少产生冲突)的哈希函数之外;还需要找到一 种“处理冲突” 的方法。

    二.Hash构造函数的方法

     

       1.直接定址法:

                             

     直接定址法是以数据元素关键字k本身或它的线性函数作为它的哈希地址,即:H(k)=k  或 H(k)=a×k+b ; (其中a,b为常数)

      例1,有一个人口统计表,记录了从1岁到100岁的人口数目,其中年龄作为关键字,哈希函数取关键字本身,如图(1):

    地址

    A1

    A2

    ……

    A99

    A100

    年龄

    1

    2

    ……

    99

    100

    人数

    980

    800

    ……

    495

    107

    可以看到,当需要查找某一年龄的人数时,直接查找相应的项即可。如查找99岁的老人数,则直接读出第99项即可。

     

    地址

    A0

    A1

    ……

    A99

    A100

    年龄

    1980

    1981

    ……

    1999

    2000

    人数

    980

    800

    ……

    495

    107

     

    如果我们要统计的是80后出生的人口数,如上表所示,那么我们队出生年份这个关键字可以用年份减去1980来作为地址,此时f(key)=key-1980

    这种哈希函数简单,并且对于不同的关键字不会产生冲突,但可以看出这是一种较为特殊的哈希函数,实际生活中,关键字的元素很少是连续的。用该方法产生的哈希表会造成空间大量的浪费,因此这种方法适应性并不强。[2]

      此法仅适合于:地址集合的大小 = = 关键字集合的大小,其中a和b为常数。

     

    2.数字分析法:

                 假设关键字集合中的每个关键字都是由 s 位数字组成 (u1, u2, …, us),分析关键字集中的全体,并从中提取分布均匀的若干位或它们的组合作为地址。

    数字分析法是取数据元素关键字中某些取值较均匀的数字位作为哈希地址的方法。即当关键字的位数很多时,可以通过对关键字的各位进行分析,丢掉分布不均匀的位,作为哈希值。它只适合于所有关键字值已知的情况。通过分析分布情况把关键字取值区间转化为一个较小的关键字取值区间。

       例2,要构造一个数据元素个数n=80,哈希长度m=100的哈希表。不失一般性,我们这里只给出其中8个关键字进行分析,8个关键字如下所示:

    K1=61317602      K2=61326875      K3=62739628      K4=61343634

    K5=62706815      K6=62774638      K7=61381262      K8=61394220

    分析上述8个关键字可知,关键字从左到右的第1、2、3、6位取值比较集中,不宜作为哈希地址,剩余的第4、5、7、8位取值较均匀,可选取其中的两位作为哈希地址。设选取最后两位作为哈希地址,则这8个关键字的哈希地址分别为:2,75,28,34,15,38,62,20。           

     

     此法适于:能预先估计出全体关键字的每一位上各种数字出现的频度。

                 

    3.折叠法:

                将关键字分割成若干部分,然后取它们的叠加和为哈希地址。两种叠加处理的方法:移位叠加:将分 割后的几部分低位对齐相加;边界叠加:从一端沿分割界来回折叠,然后对齐相加。

    所谓折叠法是将关键字分割成位数相同的几部分(最后一部分的位数可以不同),然后取这几部分的叠加和(舍去进位),这方法称为折叠法。这种方法适用于关键字位数较多,而且关键字中每一位上数字分布大致均匀的情况。

      折叠法中数位折叠又分为移位叠加和边界叠加两种方法,移位叠加是将分割后是每一部分的最低位对齐,然后相加;边界叠加是从一端向另一端沿分割界来回折叠,然后对齐相加。

    例4,当哈希表长为1000时,关键字key=110108331119891,允许的地址空间为三位十进制数,则这两种叠加情况如图:

           移位叠加                                 边界叠加

           8 9 1                                     8 9 1

           1 1 9                                     9 1 1

           3 3 1                                     3 3 1

           1 0 8                                     8 0 1

        +  1 1 0                                   + 1 1 0              

       (1) 5 5 9                                  (3)0 4 4

                     图(2)由折叠法求哈希地址

         用移位叠加得到的哈希地址是559,而用边界叠加所得到的哈希地址是44。如果关键字不是数值而是字符串,则可先转化为数。转化的办法可以用ASCⅡ字符或字符的次序值。

                此法适于:关键字的数字位数特别多。

     

    4.平方取中法

      这是一种常用的哈希函数构造方法。这个方法是先取关键字的平方,然后根据可使用空间的大小,选取平方数是中间几位为哈希地址。

    哈希函数 H(key)=“key2的中间几位”因为这种方法的原理是通过取平方扩大差别,平方值的中间几位和这个数的每一位都相关,则对不同的关键字得到的哈希函数值不易产生冲突,由此产生的哈希地址也较为均匀。

    例5,若设哈希表长为1000则可取关键字平方值的中间三位,如图所示:

    关键字

    关键字的平方

    哈希函数值

    1234

    1522756

    227

    2143

    4592449

    924

    4132

    17073424

    734

    3214

    10329796

    297 

      

    下面给出平方取中法的哈希函数

         //平方取中法哈希函数,结设关键字值32位的整数

         //哈希函数将返回key * key的中间10位

           Int  Hash (int key)

             {

         //计算key的平方

          Key * = key ;

         //去掉低11位

         Key>>=11;

         // 返回低10位(即key * key的中间10位)

           Return key %1024;

              }

       此法适于:关键字中的每一位都有某些数字重复出现频度很高的现象


    5.减去法

    减去法是数据的键值减去一个特定的数值以求得数据存储的位置。

    例7,公司有一百个员工,而员工的编号介于1001到1100,减去法就是员工编号减去1000后即为数据的位置。编号1001员工的数据在数据中的第一笔。编号1002员工的数据在数据中的第二笔…依次类推。从而获得有关员工的所有信息,因为编号1000以前并没有数据,所有员工编号都从1001开始编号。

     

    6.基数转换法

      将十进制数X看作其他进制,比如十三进制,再按照十三进制数转换成十进制数,提取其中若干为作为X的哈希值。一般取大于原来基数的数作为转换的基数,并且两个基数应该是互素的。

     

    例Hash(80127429)=(80127429)13=8*137+0*136+1*135+2*134+7*133+4*132+2*131+9=(502432641)10如果取中间三位作为哈希值,得Hash(80127429)=432

     为了获得良好的哈希函数,可以将几种方法联合起来使用,比如先变基,再折叠或平方取中等等,只要散列均匀,就可以随意拼凑。

     

     

      7.除留余数法:

                

    假设哈希表长为mp为小于等于m的最大素数,则哈希函数为

    hk=k  %  p ,其中%为模p取余运算。

    例如,已知待散列元素为(18756043549046),表长m=10p=7,则有

        h(18)=18 % 7=4    h(75)=75 % 7=5    h(60)=60 % 7=4   

        h(43)=43 % 7=1    h(54)=54 % 7=5    h(90)=90 % 7=6   

        h(46)=46 % 7=4

    此时冲突较多。为减少冲突,可取较大的m值和p值,如m=p=13,结果如下:

        h(18)=18 % 13=5    h(75)=75 % 13=10    h(60)=60 % 13=8    

        h(43)=43 % 13=4    h(54)=54 % 13=2    h(90)=90 % 13=12   

        h(46)=46 % 13=7

    此时没有冲突,如图8.25所示。

     

         1      2     3     4     5      6     7     8     9     10     11    12

     

     

     

    54

     

    43

    18

     

    46

    60

     

    75

     

    90

                          


    除留余数法求哈希地址

     

    理论研究表明,除留余数法的模p取不大于表长且最接近表长m素数时效果最好,且p最好取1.1n~1.7n之间的一个素数(n为存在的数据元素个数)

     

     

    8.随机数法:

               设定哈希函数为:H(key) = Random(key)其中,Random 为伪随机函数

               此法适于:对长度不等的关键字构造哈希函数。

     

             实际造表时,采用何种构造哈希函数的方法取决于建表的关键字集合的情况(包括关键字的范围和形态),以及哈希表    长度(哈希地址范围),总的原则是使产生冲突的可能性降到尽可能地小。

     

    9.随机乘数法

      亦称为“乘余取整法”。随机乘数法使用一个随机实数f,0≤f<1,乘积f*k的分数部分在0~1之间,用这个分数部分的值与n(哈希表的长度)相乘,乘积的整数部分就是对应的哈希值,显然这个哈希值落在0~n-1之间。其表达公式为:Hash(k)=「n*(f*k%1)」其中“f*k%1”表示f*k 的小数部分,即f*k%1=f*k-「f*k」

      例10,对下列关键字值集合采用随机乘数法计算哈希值,随机数f=0.103149002 哈希表长度n=100得图:

     

    k

    f*k

    n*((f*k)的小数部分)

    Hash(k)

    319426

    32948.47311

    47.78411

    47

    718309

    74092.85648

    86.50448

    86

    629443

    64926.41727

    42.14427

    42

    919697

    84865.82769

    83.59669

    83

      此方法的优点是对n的选择不很关键。通常若地址空间为p位就是选n=2p.Knuth对常数f的取法做了仔细的研究,他认为f取任何值都可以,但某些值效果更好。如f=(-1)/2=0.6180329...比较理想。


    10.字符串数值哈希法

    在很都情况下关键字是字符串,因此这样对字符串设计Hash函数是一个需要讨论的问题。下列函数是取字符串前10个字符来设计的哈希函数

    Int Hash _ char (char *X)

    {

      int I ,sum

      i=0;

      while (i 10 && X[i])

      Sum +=X[i++];

      sum%=N;      //N是记录的条数

      }

    这种函数把字符串的前10个字符的ASCⅡ值之和对N取摸作为Hash地址,只要N较小,Hash地址将较均匀分布[0,N]区间内,因此这个函数还是可用的。对于N很大的情形,可使用下列函数

    int ELFhash (char *key )

    {

     Unsigned long h=0,g;

    whie (*key)

    {

    h=(h<<4)+ *key;

    key++;

    g=h & 0 xF0000000L;

    if (g) h^=g>>24;

    h & =~g;

    }

    h=h % N

    return (h);

    }

      这个函数称为ELFHash(Exextable and Linking Format ,ELF,可执行链接格式)函数。它把一个字符串的绝对长度作为输入,并通过一种方式把字符的十进制值结合起来,对长字符串和短字符串都有效,这种方式产生的位置不可能不均匀分布。


    11.旋转法

      旋转法是将数据的键值中进行旋转。旋转法通常并不直接使用在哈希函数上,而是搭配其他哈希函数使用。

      例11,某学校同一个系的新生(小于100人)的学号前5位数是相同的,只有最后2位数不同,我们将最后一位数,旋转放置到第一位,其余的往右移。

    新生学号

    旋转过程

    旋转后的新键值

    5062101

    5062101

    1506210

    5062102

    5062102

    2506210

    5062103

    5062103

    3506210

    5062104

    5062104

    4506210

    5062105

    5062105

    5506210

                        如图

     运用这种方法可以只输入一个数值从而快速地查到有关学生的信息。

     

     

    在实际应用中,应根据具体情况,灵活采用不同的方法,并用实际数据测试它的性能,以便做出正确判定。通常应考虑以下五个因素 

    l 计算哈希函数所需时间 (简单)。

    l 关键字的长度。

    l 哈希表大小。

    l 关键字分布情况。

    l 记录查找频率

     



    三.Hash处理冲突方法

       通过构造性能良好的哈希函数,可以减少冲突,但一般不可能完全避免冲突,因此解决冲突是哈希法的另一个关键问题。创建哈希表和查找哈希表都会遇到冲突,两种情况下解决冲突的方法应该一致。下面以创建哈希表为例,说明解决冲突的方法。常用的解决冲突方法有以下四种:

     通过构造性能良好的哈希函数,可以减少冲突,但一般不可能完全避免冲突,因此解决冲突是哈希法的另一个关键问题。创建哈希表和查找哈希表都会遇到冲突,两种情况下解决冲突的方法应该一致。下面以创建哈希表为例,说明解决冲突的方法。常用的解决冲突方法有以下四种:

    1.         开放定址法

    这种方法也称再散列法其基本思想是:当关键字key的哈希地址p=Hkey)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,直到找出一个不冲突的哈希地址pi 将相应元素存入其中。这种方法有一个通用的再散列函数形式:

              Hi=Hkey+di% m   i=12…,n

        其中Hkey)为哈希函数,为表长,di称为增量序列。增量序列的取值方式不同,相应的再散列方式也不同。主要有以下三种:

    l         线性探测再散列

        dii=123m-1

    这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。

    l         二次探测再散列

        di=12-1222-22k2-k2    ( k<=m/2 )

        这种方法的特点是:冲突发生时,在表的左右进行跳跃式探测,比较灵活。

    l         伪随机探测再散列

        di=伪随机数序列。

    具体实现时,应建立一个伪随机数发生器,(如i=(i+p) % m),并给定一个随机数做起点。

    例如,已知哈希表长度m=11,哈希函数为:Hkey= key  %  11,则H47=3H26=4H60=5,假设下一个关键字为69,则H69=3,与47冲突。如果用线性探测再散列处理冲突,下一个哈希地址为H1=3 + 1% 11 = 4,仍然冲突,再找下一个哈希地址为H2=3 + 2% 11 = 5,还是冲突,继续找下一个哈希地址为H3=3 + 3% 11 = 6,此时不再冲突,将69填入5号单元,参图8.26 (a)。如果用二次探测再散列处理冲突,下一个哈希地址为H1=3 + 12% 11 = 4,仍然冲突,再找下一个哈希地址为H2=3 - 12% 11 = 2,此时不再冲突,将69填入2号单元,参图8.26 (b)。如果用伪随机探测再散列处理冲突,且伪随机数序列为:259……..,则下一个哈希地址为H1=3 + 2% 11 = 5,仍然冲突,再找下一个哈希地址为H2=3 + 5% 11 = 8,此时不再冲突,将69填入8号单元,参图8.26 (c)

     

     

                                                           10    

     

     

     

     

    47

    26

    60

    69

     

     

     

     

             a 用线性探测再散列处理冲突

     

     

                                                           10    

     

     

     

    69

    47

    26

    60

     

     

     

     

     

             b 用二次探测再散列处理冲突

     

     

                                                           10    

     

     

     

     

    47

    26

    60

     

     

    69

     

     

             c 用伪随机探测再散列处理冲突

     

                          8.26开放地址法处理冲突

    从上述例子可以看出,线性探测再散列容易产生“二次聚集”,即在处理同义词的冲突时又导致非同义词的冲突。例如,当表中i, i+1 ,i+2三个单元已满时,下一个哈希地址为i, i+1 ,i+2,或i+3的元素,都将填入i+3这同一个单元,而这四个元素并非同义词。线性探测再散列的优点是:只要哈希表不满,就一定能找到一个不冲突的哈希地址,而二次探测再散列和伪随机探测再散列则不一定。

    2. 再哈希法

        这种方法是同时构造多个不同的哈希函数:

        Hi=RH1key  i=12k

    当哈希地址Hi=RH1key)发生冲突时,再计算Hi=RH2key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。

    3. 链地址法

        这种方法的基本思想是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。

    例如,已知一组关键字(324036531646712742244964),哈希表长度为13,哈希函数为:Hkey= key % 13,则用链地址法处理冲突的结果如图

     



     
      哈希表及处理冲突的方法(转) - 另一片天空 - 仰望天空
     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     


    链地址法处理冲突时的哈希表

    本例的平均查找长度 ASL=(1*7+2*4+3*1)=1.5

    4.建立公共溢出区

    这种方法的基本思想是:将哈希表分为基本表溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表



     hash算法就学习总结到这里了,今天度过了22岁生日,晚上还是坚持完成了写这篇博客,今天暂时不写了,明天来总结Java中的hashcode和equals方法,

    转载请指明出处http://blog.csdn.net/tanggao1314/article/details/51457585

    参考资料

    大话数据结

    算法导论


    展开全文
  • 微服务,你得知道这些!(底层原理

    千次阅读 多人点赞 2018-12-11 10:38:27
    目录 一、业务场景介绍 二、Spring Cloud核心组件:Eureka 三、Spring Cloud核心组件:Feign 四、Spring Cloud核心组件:Ribbon 五、Spring Cloud核心组件:Hystrix ...六、Spring Cloud核心组件:Zuul ...

    目录

    一、业务场景介绍

    二、Spring Cloud核心组件:Eureka

    三、Spring Cloud核心组件:Feign

    四、Spring Cloud核心组件:Ribbon

    五、Spring Cloud核心组件:Hystrix

    六、Spring Cloud核心组件:Zuul

    七、总结

     

     

    概述

    毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术。不过大多数讲解还停留在对Spring Cloud功能使用的层面,其底层的很多原理,很多人可能并不知晓。因此本文将通过大量的手绘图,给大家谈谈Spring Cloud微服务架构的底层原理。

    实际上,Spring Cloud是一个全家桶式的技术栈,包含了很多组件。本文先从其最核心的几个组件入手,来剖析一下其底层的工作原理。也就是Eureka、Ribbon、Feign、Hystrix、Zuul这几个组件。

     

    一、业务场景介绍
    先来给大家说一个业务场景,假设咱们现在开发一个电商网站,要实现支付订单的功能,流程如下:

    创建一个订单之后,如果用户立刻支付了这个订单,我们需要将订单状态更新为“已支付”

    扣减相应的商品库存

    通知仓储中心,进行发货

    给用户的这次购物增加相应的积分

     

     

    针对上述流程,我们需要有订单服务、库存服务、仓储服务、积分服务。整个流程的大体思路如下:

    用户针对一个订单完成支付之后,就会去找订单服务,更新订单状态

    订单服务调用库存服务,完成相应功能

    订单服务调用仓储服务,完成相应功能

    订单服务调用积分服务,完成相应功能

    至此,整个支付订单的业务流程结束

     

    下图这张图,清晰表明了各服务间的调用过程:

     

    好!有了业务场景之后,咱们就一起来看看Spring Cloud微服务架构中,这几个组件如何相互协作,各自发挥的作用以及其背后的原理。

     

     

    二、Spring Cloud核心组件:Eureka

    咱们来考虑第一个问题:订单服务想要调用库存服务、仓储服务,或者是积分服务,怎么调用?

    订单服务压根儿就不知道人家库存服务在哪台机器上啊!他就算想要发起一个请求,都不知道发送给谁,有心无力!

    这时候,就轮到Spring Cloud Eureka出场了。Eureka是微服务架构中的注册中心,专门负责服务的注册与发现。

     咱们来看看下面的这张图,结合图来仔细剖析一下整个流程:

     

     

    如上图所示,库存服务、仓储服务、积分服务中都有一个Eureka Client组件,这个组件专门负责将这个服务的信息注册到Eureka Server中。说白了,就是告诉Eureka Server,自己在哪台机器上,监听着哪个端口。而Eureka Server是一个注册中心,里面有一个注册表,保存了各服务所在的机器和端口号

    订单服务里也有一个Eureka Client组件,这个Eureka Client组件会找Eureka Server问一下:库存服务在哪台机器啊?监听着哪个端口啊?仓储服务呢?积分服务呢?然后就可以把这些相关信息从Eureka Server的注册表中拉取到自己本地缓存起来。

    这时如果订单服务想要调用库存服务,不就可以找自己本地的Eureka Client问一下库存服务在哪台机器?监听哪个端口吗?收到响应后,紧接着就可以发送一个请求过去,调用库存服务扣减库存的那个接口!同理,如果订单服务要调用仓储服务、积分服务,也是如法炮制。

    总结一下:

    Eureka Client:负责将这个服务的信息注册到Eureka Server中

    Eureka Server:注册中心,里面有一个注册表,保存了各个服务所在的机器和端口号

     

    三、Spring Cloud核心组件:Feign
    现在订单服务确实知道库存服务、积分服务、仓库服务在哪里了,同时也监听着哪些端口号了。但是新问题又来了:难道订单服务要自己写一大堆代码,跟其他服务建立网络连接,然后构造一个复杂的请求,接着发送请求过去,最后对返回的响应结果再写一大堆代码来处理吗?

    这是上述流程翻译的代码片段,咱们一起来看看,体会一下这种绝望而无助的感受!!!

    友情提示,前方高能:

    看完上面那一大段代码,有没有感到后背发凉、一身冷汗?实际上你进行服务间调用时,如果每次都手写代码,代码量比上面那段要多至少几倍,所以这个事儿压根儿就不是地球人能干的。

    既然如此,那怎么办呢?别急,Feign早已为我们提供好了优雅的解决方案。来看看如果用Feign的话,你的订单服务调用库存服务的代码会变成啥样?

    看完上面的代码什么感觉?是不是感觉整个世界都干净了,又找到了活下去的勇气!没有底层的建立连接、构造请求、解析响应的代码,直接就是用注解定义一个 FeignClient接口,然后调用那个接口就可以了。人家Feign Client会在底层根据你的注解,跟你指定的服务建立连接、构造请求、发起靕求、获取响应、解析响应,等等。这一系列脏活累活,人家Feign全给你干了。

     

     

    那么问题来了,Feign是如何做到这么神奇的呢?很简单,Feign的一个关键机制就是使用了动态代理。咱们一起来看看下面的图,结合图来分析:

    首先,如果你对某个接口定义了@FeignClient注解,Feign就会针对这个接口创建一个动态代理

    接着你要是调用那个接口,本质就是会调用 Feign创建的动态代理,这是核心中的核心

    Feign的动态代理会根据你在接口上的@RequestMapping等注解,来动态构造出你要请求的服务的地址

    最后针对这个地址,发起请求、解析响应

     

     

    四、Spring Cloud核心组件:Ribbon
    说完了Feign,还没完。现在新的问题又来了,如果人家库存服务部署在了5台机器上,如下所示:

    192.168.169:9000

    192.168.170:9000

    192.168.171:9000

    192.168.172:9000

    192.168.173:9000

     

    这下麻烦了!人家Feign怎么知道该请求哪台机器呢?

    这时Spring Cloud Ribbon就派上用场了。Ribbon就是专门解决这个问题的。它的作用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把请求分发到各个机器上

    Ribbon的负载均衡默认使用的最经典的Round Robin轮询算法。这是啥?简单来说,就是如果订单服务对库存服务发起10次请求,那就先让你请求第1台机器、然后是第2台机器、第3台机器、第4台机器、第5台机器,接着再来—个循环,第1台机器、第2台机器。。。以此类推。

    另外,Ribbon是和Feign以及Eureka紧密协作,完成工作的,具体如下:

    首先Ribbon会从 Eureka Client里获取到对应的服务注册表,也就知道了所有的服务都部署在了哪些机器上,在监听哪些端口号。

    然后Ribbon就可以使用默认的Round Robin算法,从中选择一台机器

    Feign就会针对这台机器,构造并发起请求。

    对上述整个过程,再来一张图,帮助大家更深刻的理解:

    五、Spring Cloud核心组件:Hystrix

    在微服务架构里,一个系统会有很多的服务。以本文的业务场景为例:订单服务在一个业务流程里需要调用三个服务。现在假设订单服务自己最多只有100个线程可以处理请求,然后呢,积分服务不幸的挂了,每次订单服务调用积分服务的时候,都会卡住几秒钟,然后抛出—个超时异常。

     

    咱们一起来分析一下,这样会导致什么问题?

    如果系统处于高并发的场景下,大量请求涌过来的时候,订单服务的100个线程都会卡在请求积分服务这块。导致订单服务没有一个线程可以处理请求

    然后就会导致别人请求订单服务的时候,发现订单服务也挂了,不响应任何请求了

    上面这个,就是微服务架构中恐怖的服务雪崩问题,如下图所示:

     

    如上图,这么多服务互相调用,要是不做任何保护的话,某一个服务挂了,就会引起连锁反应,导致别的服务也挂。比如积分服务挂了,会导致订单服务的线程全部卡在请求积分服务这里,没有一个线程可以工作,瞬间导致订单服务也挂了,别人请求订单服务全部会卡住,无法响应。

    但是我们思考一下,就算积分服务挂了,订单服务也可以不用挂啊!为什么?

    我们结合业务来看:支付订单的时候,只要把库存扣减了,然后通知仓库发货就OK了

    如果积分服务挂了,大不了等他恢复之后,慢慢人肉手工恢复数据!为啥一定要因为一个积分服务挂了,就直接导致订单服务也挂了呢?不可以接受!

    现在问题分析完了,如何解决?

    这时就轮到Hystrix闪亮登场了。Hystrix是隔离、熔断以及降级的一个框架。啥意思呢?说白了,Hystrix会搞很多个小小的线程池,比如订单服务请求库存服务是一个线程池,请求仓储服务是一个线程池,请求积分服务是一个线程池。每个线程池里的线程就仅仅用于请求那个服务。

    打个比方:现在很不幸,积分服务挂了,会咋样?

    当然会导致订单服务里的那个用来调用积分服务的线程都卡死不能工作了啊!但是由于订单服务调用库存服务、仓储服务的这两个线程池都是正常工作的,所以这两个服务不会受到任何影响。

    这个时候如果别人请求订单服务,订单服务还是可以正常调用库存服务扣减库存,调用仓储服务通知发货。只不过调用积分服务的时候,每次都会报错。但是如果积分服务都挂了,每次调用都要去卡住几秒钟干啥呢?有意义吗?当然没有!所以我们直接对积分服务熔断不就得了,比如在5分钟内请求积分服务直接就返回了,不要去走网络请求卡住几秒钟,这个过程,就是所谓的熔断!

    那人家又说,兄弟,积分服务挂了你就熔断,好歹你干点儿什么啊!别啥都不干就直接返回啊?没问题,咱们就来个降级:每次调用积分服务,你就在数据库里记录一条消息,说给某某用户增加了多少积分,因为积分服务挂了,导致没增加成功!这样等积分服务恢复了,你可以根据这些记录手工加一下积分。这个过程,就是所谓的降级。

    为帮助大家更直观的理解,接下来用一张图,梳理一下Hystrix隔离、熔断和降级的全流程:

     

    六、Spring Cloud核心组件:Zuul
    说完了Hystrix,接着给大家说说最后一个组件:Zuul,也就是微服务网关。这个组件是负责网络路由的。不懂网络路由?行,那我给你说说,如果没有Zuul的日常工作会怎样?

    假设你后台部署了几百个服务,现在有个前端兄弟,人家请求是直接从浏览器那儿发过来的。打个比方:人家要请求一下库存服务,你难道还让人家记着这服务的名字叫做inventory-service?部署在5台机器上?就算人家肯记住这一个,你后台可有几百个服务的名称和地址呢?难不成人家请求一个,就得记住一个?你要这样玩儿,那真是友谊的小船,说翻就翻!

    上面这种情况,压根儿是不现实的。所以一般微服务架构中都必然会设计一个网关在里面,像android、ios、pc前端、微信小程序、H5等等,不用去关心后端有几百个服务,就知道有一个网关,所有请求都往网关走,网关会根据请求中的一些特征,将请求转发给后端的各个服务。

    而且有一个网关之后,还有很多好处,比如可以做统一的降级、限流、认证授权、安全,等等。

     

     

    七、总结:

    最后再来总结一下,上述几个Spring Cloud核心组件,在微服务架构中,分别扮演的角色:

    Eureka:各个服务启动时,Eureka Client都会将服务注册到Eureka Server,并且Eureka Client还可以反过来从Eureka Server拉取注册表,从而知道其他服务在哪里

    Ribbon:服务间发起请求的时候,基于Ribbon做负载均衡,从一个服务的多台机器中选择一台

    Feign:基于Feign的动态代理机制,根据注解和选择的机器,拼接请求URL地址,发起请求

    Hystrix:发起请求是通过Hystrix的线程池来走的,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题

    Zuul:如果前端、移动端要调用后端系统,统一从Zuul网关进入,由Zuul网关转发请求给对应的服务

     

    以上就是我们通过一个电商业务场景,阐述了Spring Cloud微服务架构几个核心组件的底层原理。

     

    文字总结还不够直观?没问题!

    我们将Spring Cloud的5个核心组件通过一张图串联起来,再来直观的感受一下其底层的架构原理:

    转自:

    https://blog.csdn.net/qq_42046105

    展开全文
  • BT原理分析

    万次阅读 多人点赞 2011-07-13 13:32:44
    BitTorrent协议。BT全名为BitTorrent,是一个p2p软件,你在下载download的同时,也在为其他用户提供上传upload,因为大家是“互相帮助”,所以不会随着用户数的增加而降低下载速度。 下面是一般用ftp,http等分享流程...
  • hashMap的实现原理

    2020-09-15 19:54:44
    HashMap的实现原理 HashMap的数据结构 在看Hashmap的数据结构之前先来看看数组和链表的特点 数组:寻址容易插入和删除的时候比较困难(数组有下表寻址,但是插入删除的时候下表要移动,扩容的时候也很麻烦) 链表:...
  • Canny算子边缘检测原理及实现

    万次阅读 多人点赞 2019-06-11 12:34:09
    写在前面 Canny边缘检是在在1986年提出来的,到今天已经30多年过去了,但Canny算法仍然是图像边缘检测算法中最经典、先进的算法之一。 相比Sobel、Prewitt等算子,Canny算法更为优异。Sobel、Prewitt等算子有如下...
  • kafka工作原理介绍

    万次阅读 多人点赞 2018-06-27 11:55:56
    两张图读懂kafka应用:Kafka 中的术语 broker:中间的kafka cluster,存储消息,是由多个server组成的集群。 topic:kafka给消息提供的分类方式。broker用来存储不同topic的消息数据。 producer:往broker中某个...
  • ZooKeeper原理解析

    千次阅读 2020-02-07 09:48:03
    分布式协调服务组件zookeeper的介绍、特点及原理解析
  • 编译原理实验:词法分析

    万次阅读 多人点赞 2018-09-29 21:17:16
    编译原理实验:词法分析1. 实验题目:词法分析实验目的实验内容实验要求输入输出2. 设计思想3.算法流程4. 源程序5. 调试数据 1. 实验题目:词法分析 实验目的 根据PL/0语言的文法规范,编写PL/0语言的词法分析...
  • 编译原理第三版课后习题

    万次阅读 多人点赞 2018-12-22 11:12:47
    编译原理课后习题 都是编译原理老师上课布置的课后习题的整理 第二章 1.P34-4 证明G(E)是二义的。 E-&gt;EOE|(E)|v|d O-&gt;+|* 2.P34-8 上下文无关文法G[S] :S-&gt;SS*|SS+|a 答:(1)S=&gt;SS*=...
  • 编译原理总结

    2018-06-11 08:53:39
    编译原理是计算机专业的一门重要课程,主要介绍在编译程序构造的一般原理和方法,其中有, 编译原理是计算机专业的一门重要专业课,旨在介绍编译程序构造的一般原理和基本方法。内容包括语言和文法、词法分析、语法...
  • 编译原理编译原理简单介绍

    万次阅读 多人点赞 2017-05-07 13:27:20
    编译原理简单介绍编译原理简单介绍 什么叫编译程序 翻译程序 编译程序 翻译和编译的区别 编译的过程 词法分析 语法分析 语义分析和中间代码的产生 优化 目标代码生成 编译程序的结构 编译程序总框 表格与表格的管理 ...
  • 《计算机科学丛书:编译原理》全面、深入地探讨了编译器设计方面的重要主题,包括词法分析、语法分析、语法制导定义和语法制导翻译、运行时刻环境、目标代码生成、代码优化技术、并行性检测以及过程间分析技术,并在...
  • 编译原理书籍推荐

    千次阅读 2018-09-28 13:44:20
    大学课程为什么要开设编译原理呢?这门课程关注的是编译器方面的产生原理和技术问题,似乎和计算机的基础领域不沾边,可是编译原理却一直作为大学本科的必修课程,同时也成为了研究生入学考试的必考内容。编译原理及...
  • 编译原理

    万次阅读 多人点赞 2017-12-04 21:42:58
    一、 编译程序 1、 编译器是一种翻译程序,它用于将源语言(即用某种程序设计语言写成的)程序翻译为目标语言(即用二进制数表示的伪机器代码写成的)程序。后者在windows操作系统平台下,其文件的扩展名通常为....
  • 编译原理_第2版_张素琴

    热门讨论 2014-03-16 22:45:41
    编译原理_第2版_张素琴等_清华大学 由张素琴和吕映芝等编著的《编译原理》介绍编译系统的一般构造原 理、基本实现技术和一些自动构造工具。主要由语言基础知识、词法分析 、语法分析、中间代码生成、代码优化、目标...
  • 自己大概整理了一下,希望对大家有用。如果你们有更好的答案希望能共享一下哈
  • 完整的编译原理实验报告 关于语法、语义和词法分析器三部分的 很全哦 一、实验题目 表达式中间代码生成 二、实验目的 熟悉算术表达式的语法分析与中间代码生成原理。 三、实验内容 1. 构造算术表达式的四元式翻译...
  • java编译原理

    千次阅读 2018-03-27 16:47:31
    4.Java编译原理1.javac是什么?(1)javac是一种编译器,能够将一种语言规范转换成另一种用语言规范,通常编译器是将便于人们理解的语言规范成机器容易理解的语言规范。(2)javac的任务就是将java源代码语言转换成jvm...
  • 原来编译原理可以这么学

    万次阅读 多人点赞 2012-04-09 00:33:37
    最近对数据结构的研究又有了进展,挺好玩的,总结这些内容的同时,希望也能帮助到大家,这样的话,达到双赢,这才是写博客的目的,接下来我们来轻松学习编译原理,不要被这些纸老虎吓着了。我们一步步来看到底是怎么...
  • 编译原理是用来做什么的?从源语言提取需要的信息;把源语言翻译成目标语言;自动生成满足一定规范的文本...有个东西叫DSL(领域专用语言):从各种格式的数据中提取信息:XML/JSON/CSV/Excel;...各种格式文本的...
  • 《程序设计语言:编译原理》(第3版)是在陈火旺、钱家骅、孙永强三位教授编写的《程序设计语言编译原理》的基础上,结合编译技术的最新研究成果和作者多年的教学经验编写而成的。《程序设计语言:编译原理》(第3版)比较...
  • 编译原理试题汇总+编译原理期末试题(8套含答案+大题集)
  • RT,zip中包含了非常多的资源,其中有现代编译原理PDF及其课后题答案,C/C++的垃圾回收器,Bison,Flex测试用例,勘误表,最大的资源就是有全书的代码。并且附加了一个Tiger编译器。非常丰富的资源 1:现代编译原理...
  • 可以这样入门编译原理

    千次阅读 2013-12-15 15:23:56
    学过编译原理的人都知道,编译原理这门课确实难学。我所看的关于编译原理的书籍有大家所熟悉的紫龙书以及《编译原理实践》,作者都为美国人。因为自己不是计算机专业的,所以没有上过这门课,而自学起来,由于没有一...
  • 编译原理中:短语,直接短语,句柄

    万次阅读 多人点赞 2016-12-13 19:37:55
    这几天邻近期末,感觉上了快一学期的编译原理的许多方面还是难以理解,今天早上就突然遇到了一道题,求短语,直接短语和句柄的题,突然才发现自己连这些词的定义都不清楚,于是仔细查了以下,下面分享出来:短语书上...
  • 1.计算机编译原理课后习题答案 第三版 张幸儿(一通好找,内容找的不全,但是重要的题目都在里面) 2.编译原理--陈英 2009 3.编译原理课程辅导与习题解析(胡元义,人民邮电出版社)
  • Android Apk 编译原理解析

    千次阅读 2017-07-14 09:44:16
    本文基于AOSP-7.1.1-R9源码分析,源码可以参见build/+/android-...对于刚开始接触系统开发的开发者来说,经常会使用如下命令编译apk或者系统固件。source build/envsetup.sh; lunch make -j8 or mmm packages/app/Se

空空如也

1 2 3 4 5 ... 20
收藏数 2,850,746
精华内容 1,140,298
关键字:

原理