什么是Dirty Hack?

什么是Dirty hack?

答案来自知乎,感觉生动有趣,所以摘抄过来,以做保留!


以不符合设计原理 / 不易维护 / 不易调整 / 不够健壮 / 不够美观的方式解决问题。
比如水管连接处生了锈开始漏——

  • 把水管系统整个重新布置成没有接头的管线,叫做 refactor
  • 按原样把锈掉的水管换新的,叫做 proper fix
  • 把水管拆下来用防渗胶带缠住螺丝纹再装回去,叫做 patch
  • 叫你女朋友先把漏水的地方捂住然后下面放个脸盆接漏水,叫做 monkey patch
  • 用电焊把接头焊起来,叫做 hack
  • 用口香糖塞住漏缝然后用水泥把接头浇筑起来,结果因为那一大坨太重,下面不得不放一根木棍撑着,叫做 dirty hack

Dirty hack 不一定总是坏事,如果你没有脸盆、电焊、管钳、女朋友、新水管和防渗胶带,而这套水管系统反正就快整个报废了的话。


巨硬(微软)的生动展示:
ms_dirty_hack


常规答案:

我觉得上面的例子非常生动,但有点脱离软件开发的场景了。
Dirty hack,首先是hack。
hack就是用非常规的手段搞定(不是解决)某个问题。
比如说有段代码是这样的:a/b
当b为0的时候,这段代码就会报错。
正确的fix是避免b为0。
hack就是这样:

try {
    a/b
}

dirty hack就是在这段代码下面写上: catch{}


:
前方高能,重口味答案:

假设一个女的得了直肠癌——

  • 移植一段正常直肠叫 fix
  • 在肚子上开个口再挂个袋子叫 workaround
  • 人工直肠叫 hack
  • 在阴道上打个洞叫大便从那里出去才叫真正的 DIRTY HACK ~~~
    -_-

默克尔树(Merkle Tree)学习(转改)

Merkle Tree概念

Merkle Tree

Merkle Tree,通常也被称作Hash Tree,顾名思义,就是存储hash值的一棵树。Merkle树的叶子是数据块(例如,文件或者文件的集合)的hash值。非叶节点是其对应子节点串联字符串的hash。[1]

  1. Hash
    Hash是一个把任意长度的数据映射成固定长度数据的函数[2]。例如,对于数据完整性校验,最简单的方法是对整个数据做Hash运算得到固定长度的Hash值,然后把得到的Hash值公布在网上,这样用户下载到数据之后,对数据再次进行Hash运算,比较运算结果和网上公布的Hash值进行比较,如果两个Hash值相等,说明下载的数据没有损坏。可以这样做是因为输入数据的稍微改变就会引起Hash运算结果的面目全非,而且根据Hash值反推原始输入数据的特征是困难的。[3]

    hashfunction

    如果从一个稳定的服务器进行下载,采用单一Hash是可取的。但如果数据源不稳定,一旦数据损坏,就需要重新下载,这种下载的效率是很低的。

  2. Hash List
    在点对点(p2p)网络中作数据传输的时候,会同时从多个机器上下载数据,而且很多机器可以认为是不稳定或者不可信的。为了校验数据的完整性,更好的办法是把大的文件分割成小的数据块(例如,分割成2K为单位的数据块)。这样的好处是,如果小块数据在传输过程中损坏了,那么只要重新下载这一块数据就行了,不用重新下载整个文件。

    怎么确定小的数据块有没有损坏呢?只需要为每个数据块做Hash。BT下载的时候,在下载到真正数据之前,我们会先下载一个Hash列表。那么问题又来了,怎么确定这个Hash列表本身是正确的呢?

    答案是把每个小块数据的Hash值拼到一起,然后对这个长字符串在做一次Hash运算,这样就得到Hash列表的根Hash(Top Hash or Root Hash)。下载数据的时候,首先从可信的数据源得到正确的根Hash,就可以用它来校验Hash列表了,然后通过校验后的Hash列表校验数据块。

    merkle

  3. Merkle Tree
    Merkle Tree可以看做Hash List的泛化(Hash List可以看作一种特殊的Merkle Tree,即树高为2的多叉Merkle Tree)。

    在最底层,和哈希列表一样,我们把数据分成小的数据块,有相应地哈希和它对应。但是往上走,并不是直接去运算根哈希,而是把相邻的两个哈希合并成一个字符串,然后运算这个字符串的哈希,这样每两个哈希就结婚生子,得到了一个”子哈希“。如果最底层的哈希总数是单数,那到最后必然出现一个单身哈希,这种情况就直接对它进行哈希运算,所以也能得到它的子哈希。于是往上推,依然是一样的方式,可以得到数目更少的新一级哈希,最终必然形成一棵倒挂的树,到了树根的这个位置,这一代就剩下一个根哈希了,我们把它叫做 Merkle Root[3]

    在p2p网络下载数据之前,先从可信的源获得文件的Merkle Tree树根。一旦获得了树根,就可以从其他从不可信的源获取Merkle tree。通过可信的树根来检查接收到的Merkle Tree。如果Merkle Tree是损坏的或者虚假的,就从其他源获得另一个Merkle Tree,直到获得一个与可信树根匹配的Merkle Tree。

    Merkle Tree和Hash List的主要区别是,可以直接下载并立即验证Merkle Tree的一个分支。因为可以将文件切分成小的数据块,这样如果有一块数据损坏,仅仅重新下载这个数据块就行了。如果文件非常大,那么Merkle tree和Hash list都很多,但是Merkle tree可以一次下载一个分支,然后立即验证这个分支,如果分支验证通过,就可以下载数据了。而Hash list只有下载整个hash list才能验证。

    merkle

Merkle Tree的特点

MT是一种树,大多数是二叉树,也可以多叉树,无论是几叉树,它都具有树结构的所有特点;Merkle Tree的叶子节点的value是数据集合的单元数据或者单元数据HASH。非叶子节点的value是根据它下面所有的叶子节点值,然后按照Hash算法计算而得出的。[4][5]

通常,加密的hash方法像SHA-2和MD5用来做hash。但如果仅仅防止数据不是蓄意的损坏或篡改,可以改用一些安全性低但效率高的校验和算法,如CRC。

Second Preimage Attack: Merkle tree的树根并不表示树的深度,这可能会导致second-preimage attack,即攻击者创建一个具有相同Merkle树根的虚假文档。一个简单的解决方法在Certificate Transparency中定义:当计算叶节点的hash时,在hash数据前加0x00。当计算内部节点是,在前面加0x01。另外一些实现限制hash tree的根,通过在hash值前面加深度前缀。因此,前缀每一步会减少,只有当到达叶子时前缀依然为正,提取的hash链才被定义为有效。

Merkle Tree的操作
  1. 创建Merckle Tree
    假如最底层有9个数据块。

    step1:(红色线)对数据块做hash运算,Node0i = hash(Data0i), i=1,2,…,9

    step2: (橙色线)相邻两个hash块串联,然后做hash运算,Node1((i+1)/2) = hash(Node0i+Node0(i+1)), i=1,3,5,7;对于i=9, Node1((i+1)/2) = hash(Node0i)

    step3: (黄色线)重复step2

    step4:(绿色线)重复step2

    step5:(蓝色线)重复step2,生成Merkle Tree Root

    merkle

    易得,创建Merkle Tree是O(n)复杂度(这里指O(n)次hash运算),n是数据块的大小。得到Merkle Tree的树高是log(n)+1。

  2. 检索数据块
    为了更好理解,我们假设有A和B两台机器,A需要与B相同目录下有8个文件,文件分别是f1 f2 f3 ....f8。这个时候我们就可以通过Merkle Tree来进行快速比较。假设我们在文件创建的时候每个机器都构建了一个Merkle Tree。具体如下图:

    merkle

    从上图可得知,叶子节点node7的value = hash(f1),是f1文件的HASH;而其父亲节点node3的value = hash(v7, v8),也就是其子节点node7 node8的值得HASH。就是这样表示一个层级运算关系。root节点的value其实是所有叶子节点的value的唯一特征。

    假如A上的文件5与B上的不一样。我们怎么通过两个机器的merkle treee信息找到不相同的文件? 这个比较检索过程如下:

    Step1. 首先比较v0是否相同,如果不同,检索其孩子node1和node2.

    Step2. v1 相同,v2不同。检索node2的孩子node5 node6;

    Step3. v5不同,v6相同,检索比较node5的孩子node 11 和node 12

    Step4. v11不同,v12相同。node 11为叶子节点,获取其目录信息。

    Step5. 检索比较完毕。

    以上过程的理论复杂度是Log(N)。过程描述图如下:
    merkle

    从上图可以得知真个过程可以很快的找到对应的不相同的文件。

  3. 更新,插入和删除
    虽然网上有很多关于Merkle Tree的资料,但大部分没有涉及Merkle Tree的更新、插入和删除操作,讨论Merkle Tree的检索和遍历的比较多。我也是非常困惑,一种树结构的操作肯定不仅包括查找,也包括更新、插入和删除的啊。后来查到stackexchange上的一个问题,才稍微有点明白,原文见[6]

    对于Merkle Tree数据块的更新操作其实是很简单的,更新完数据块,然后接着更新其到树根路径上的Hash值就可以了,这样不会改变Merkle Tree的结构。但是,插入和删除操作肯定会改变Merkle Tree的结构,如下图,一种插入操作是这样的:

    merkle

    插入数据块0后(考虑数据块的位置),Merkle Tree的结构是这样的:

    merkle

    [6]中的同学在考虑一种插入的算法,满足下面条件:

    1. re-hashing操作的次数控制在log(n)以内
    2. 数据块的校验在log(n)+1以内
    3. 除非原始树的n是偶数,插入数据后的树没有孤儿,并且如果有孤儿,那么孤儿是最后一个数据块
    4. 数据块的顺序保持一致
    5. 插入后的Merkle Tree保持平衡
    

    然后上面的插入结果就会变成这样:
    merkle

    根据[6]中回答者所说,Merkle Tree的插入和删除操作其实是一个工程上的问题,不同问题会有不同的插入方法。如果要确保树是平衡的或者是树高是log(n)的,可以用任何的标准的平衡二叉树的模式,如AVL树,红黑树,伸展树,2-3树等。这些平衡二叉树的更新模式可以在O(lgn)时间内完成插入操作,并且能保证树高是O(lgn)的。那么很容易可以看出更新所有的Merkle Hash可以在O((lgn)2)时间内完成(对于每个节点如要更新从它到树根O(lgn)个节点,而为了满足树高的要求需要更新O(lgn)个节点)。如果仔细分析的话,更新所有的hash实际上可以在O(lgn)时间内完成,因为要改变的所有节点都是相关联的,即他们要不是都在从某个叶节点到树根的一条路径上,或者这种情况相近。

    [6]的回答者说实际上Merkle Tree的结构(是否平衡,树高限制多少)在大多数应用中并不重要,而且保持数据块的顺序也在大多数应用中也不需要。因此,可以根据具体应用的情况,设计自己的插入和删除操作。一个通用的Merkle Tree插入删除操作是没有意义的。

Merkle Tree的应用
  1. 数字签名
    最初Merkle Tree目的是高效的处理Lamport one-time signatures。 每一个Lamport key只能被用来签名一个消息,但是与Merkle tree结合可以来签名多条Merkle。这种方法成为了一种高效的数字签名框架,即Merkle Signature Scheme。

  2. P2P网络
    在P2P网络中,Merkle Tree用来确保从其他节点接受的数据块没有损坏且没有被替换,甚至检查其他节点不会欺骗或者发布虚假的块。大家所熟悉的BT下载就是采用了P2P技术来让客户端之间进行数据传输,一来可以加快数据下载速度,二来减轻下载服务器的负担。BT即BitTorrent,用于点对点文件共享(“P2P”)的通信协议,通过Internet分发数据和电子文件[7]

    要进下载必须从中心索引服务器获取一个扩展名为torrent的索引文件(即大家所说的种子),torrent文件包含了要共享文件的信息,包括文件名,大小,文件的Hash信息和一个指向Tracker的URL[8]。Torrent文件中的Hash信息是每一块要下载的文件内容的加密摘要,这些摘要也可运行在下载的时候进行验证。大的torrent文件是Web服务器的瓶颈,而且也不能直接被包含在RSS或gossiped around(用"流言传播协议"进行传播)[14][15]。一个相关的问题是大数据块的使用,因为为了保持torrent文件的非常小,那么数据块Hash的数量也得很小,这就意味着每个数据块相对较大。大数据块影响节点之间进行交易的效率,因为只有当大数据块全部下载下来并校验通过后,才能与其他节点进行交易。

    就解决上面两个问题是用一个简单的Merkle Tree代替Hash List。设计一个层数足够多的满二叉树,叶节点是数据块的Hash,不足的叶节点用0来代替。上层的节点是其对应孩子节点串联的hash。Hash算法和普通torrent一样采用SHA1。其数据传输过程和第一节中描述的类似。
    p2p

  3. Trusted Computing
    可信计算是可信计算组为分布式计算环境中参与节点的计算平台提供端点可信性而提出的。可信计算技术在计算平台的硬件层引入可信平台模块(Trusted Platform,TPM),实际上为计算平台提供了基于硬件的可信根(Root of trust,RoT)。从可信根出发,使用信任链传递机制,可信计算技术可对本地平台的硬件及软件实施逐层的完整性度量,并将度量结果可靠地保存再TPM的平台配置寄存器(Platform configuration register,PCR)中,此后远程计算平台可通过远程验证机制(Remote Attestation)比对本地PCR中度量结果,从而验证本地计算平台的可信性。可信计算技术让分布式应用的参与节点摆脱了对中心服务器的依赖,而直接通过用户机器上的TPM芯片来建立信任,使得创建扩展性更好、可靠性更高、可用性更强的安全分布式应用成为可能[10]。可信计算技术的核心机制是远程验证(remote attestation),分布式应用的参与结点正是通过远程验证机制来建立互信,从而保障应用的安全。
    Trusted Computing

    文献[10]提出了一种基于Merkle Tree的远程验证机制,其核心是完整性度量值哈希树。

    首先,RAMT 在内核中维护的不再是一张完整性度量值列表(ML),而是一棵完整性度量值哈希树(integrity measurement hash tree,简称IMHT).其中,IMHT的叶子结点存储的数据对象是待验证计算平台上被度量的各种程序的完整性哈希值,而其内部结点则依据Merkle 哈希树的构建规则由子结点的连接的哈希值动态生成。

    其次,为了维护IMHT 叶子结点的完整性,RAMT 需要使用TPM 中的一段存储器来保存IMHT 可信根哈希的值。

    再次,RAMT 的完整性验证过程基于认证路径(authentication path)实施.认证路径是指IMHT 上从待验证叶子结点到根哈希的路径。

  4. IPFS
    IPFS(InterPlanetary File System)是很多NB的互联网技术的综合体,如DHT( Distributed HashTable,分布式哈希表),Git版本控制系统,Bittorrent等。它创建了一个P2P的集群,这个集群允许IPFS对象的交换。全部的IPFS对象形成了一个被称作Merkle DAG的加密认证数据结构。

    IPFS对象是一个含有两个域的数据结构:

    Data – 非结构的二进制数据,大小小于256kB
    Links – 一个Link数据结构的数组。IPFS对象通过他们链接到其他对象
    

    Link数据结构包含三个域:

    Name – Link的名字
    Hash – Link链接到对象的Hash
    Size – Link链接到对象的累积大小,包括它的Links
    

    ipfs

    通过Name和Links,IPFS的集合组成了一个Merkle DAG(有向无环图)。
    ipfs-dag

    对于小文件(小于256kB),是一个没有Links的IPFS对象。
    no-links

    对于大文件,被表示为一个文件块(小于256kB)的集合。只有拥有最小的Data的对象来代表这个大文件。这个对象的Links的名字都为空字符串。

    big-file
    ipfs

    目录结构:目录是没有数据的IPFS对象,它的链接指向其包含的文件和目录。
    ipfs-dir

    IPFS可以表示Git使用的数据结构,Git Commit Object。Commit Object主要的特点是他有一个或多个名为’parent0’和‘parent1’等的链接(这些链接指向前一个版本),以及一个名为object的对象(在Git中成为tree)指向引用这个commit的文件系统结构。
    git-commit

  5. BitCoin和Ethereum[12][13]
    Merkle Proof最早的应用是Bitcoin,它是由中本聪在2009年描述并创建的。Bitcoin的Blockchain利用Merkle proofs来存储每个区块的交易。
    merkle-proofs

    而这样做的好处,也就是中本聪描述到的“简化支付验证”(Simplified Payment Verification,SPV)的概念:一个“轻客户端”(light client)可以仅下载链的区块头即每个区块中的80byte的数据块,仅包含五个元素,而不是下载每一笔交易以及每一个区块:

    上一区块头的哈希值
    时间戳
    挖矿难度值
    工作量证明随机数(nonce)
    包含该区块交易的Merkle Tree的根哈希
    

    如果客户端想要确认一个交易的状态,它只需简单的发起一个Merkle proof请求,这个请求显示出这个特定的交易在Merkle trees的一个之中,而且这个Merkle Tree的树根在主链的一个区块头中。

    但是Bitcoin的轻客户端有它的局限。一个局限是,尽管它可以证明包含的交易,但是它不能进行涉及当前状态的证明(如数字资产的持有,名称注册,金融合约的状态等)。

    Bitcoin如何查询你当前有多少币?一个比特币轻客户端,可以使用一种协议,它涉及查询多个节点,并相信其中至少会有一个节点会通知你,关于你的地址中任何特定的交易支出,而这可以让你实现更多的应用。但对于其他更为复杂的应用而言,这些远远是不够的。一笔交易影响的确切性质(precise nature),可以取决于此前的几笔交易,而这些交易本身则依赖于更为前面的交易,所以最终你可以验证整个链上的每一笔交易。为了解决这个问题,Ethereum的Merkle Tree的概念,会更进一步。

    Ethereum的Merkle Proof

    每个以太坊区块头不是包括一个Merkle树,而是为三种对象设计的三棵树:

    交易Transaction
    收据Receipts(本质上是显示每个交易影响的多块数据)
    状态State
    

    eth-head

    这使得一个非常先进的轻客户端协议成为了可能,它允许轻客户端轻松地进行并核实以下类型的查询答案:

    这笔交易被包含在特定的区块中了么?
    告诉我这个地址在过去30天中,发出X类型事件的所有实例(例如,一个众筹合约完成了它的目标)
    目前我的账户余额是多少?
    这个账户是否存在?
    假如在这个合约中运行这笔交易,它的输出会是什么?
    

    第一种是由交易树(transaction tree)来处理的;第三和第四种则是由状态树(state tree)负责处理,第二种则由收据树(receipt tree)处理。计算前四个查询任务是相当简单的。服务器简单地找到对象,获取Merkle分支,并通过分支来回复轻客户端。

    第五种查询任务同样也是由状态树处理,但它的计算方式会比较复杂。这里,我们需要构建一个Merkle状态转变证明(Merkle state transition proof)。从本质上来讲,这样的证明也就是在说“如果你在根S的状态树上运行交易T,其结果状态树将是根为S',log为L,输出为O” (“输出”作为存在于以太坊的一种概念,因为每一笔交易都是一个函数调用;它在理论上并不是必要的)。

    为了推断这个证明,服务器在本地创建了一个假的区块,将状态设为 S,并在请求这笔交易时假装是一个轻客户端。也就是说,如果请求这笔交易的过程,需要客户端确定一个账户的余额,这个轻客户端(由服务器模拟的)会发出一个余额查询请求。如果需要轻客户端在特点某个合约的存储中查询特定的条目,这个轻客户端就会发出这样的请求。也就是说服务器(通过模拟一个轻客户端)正确回应所有自己的请求,但服务器也会跟踪它所有发回的数据。

    然后,服务器从上述的这些请求中把数据合并并把数据以一个证明的方式发送给客户端。

    客户端会进行相同的步骤,但会将服务器提供的证明作为一个数据库来使用。如果客户端进行步骤的结果和服务器提供的是一样的话,客户端就接受这个证明。

    MPT
    MPT(Merkle Patricia Trees)

    前面我们提到,最为简单的一种Merkle Tree大多数情况下都是一棵二叉树。然而,Ethereum所使用的Merkle Tree则更为复杂,我们称之为“梅克尔.帕特里夏树”(Merkle Patricia tree)。

    对于验证属于list格式(本质上来讲,它就是一系列前后相连的数据块)的信息而言,二叉Merkle Tree是非常好的数据结构。对于交易树来说,它们也同样是不错的,因为一旦树已经建立,花多少时间来编辑这棵树并不重要,树一旦建立了,它就会永远存在并且不会改变。

    但是,对于状态树,情况会更复杂些。以太坊中的状态树基本上包含了一个键值映射,其中的键是地址,而值包括账户的声明、余额、随机数nounce、代码以及每一个账户的存储(其中存储本身就是一颗树)。例如,摩登测试网络(the Morden testnet)的创始状态如下所示:
    the morden testnet

    然而,不同于交易历史记录,状态树需要经常地进行更新:账户余额和账户的随机数nonce经常会更变,更重要的是,新的账户会频繁地插入,存储的键( key)也会经常被插入以及删除。我们需要这样的数据结构,它能在一次插入、更新、删除操作后快速计算到树根,而不需要重新计算整个树的Hash。这种数据结构同样得包括两个非常好的第二特征:

    树的深度是有限制的,即使考虑攻击者会故意地制造一些交易,使得这颗树尽可能地深。不然,攻击者可以通过操纵树的深度,执行拒绝服务攻击(DOS attack),使得更新变得极其缓慢。
    树的根只取决于数据,和其中的更新顺序无关。换个顺序进行更新,甚至重新从头计算树,并不会改变根。
    

    MPT是最接近同时满足上面的性质的的数据结构。MPT的工作原理的最简单的解释是,值通过键来存储,键被编码到搜索树必须要经过的路径中。每个节点有16个孩子,因此路径又16进制的编码决定:例如,键‘dog’的16进制编码是6 4 6 15 6 7,所以从root开始到第六个分支,然后到第四个,再到第六个,再到第十五个,这样依次进行到达树的叶子。

    在实践中,当树稀少时也会有一些额外的优化,我们会使过程更为有效,但这是基本的原则。

  6. 其他应用
    用到Merkle Tree的应用还有很多,比如Git,Amazon Dynamo,Apache Wave Protocol,Tahoe-LAFS backup system,Certificate Transparency framework,NoSQL systems like Apache Cassadra and Riak等


原文出自这里,有部分修改,如有侵权请联系删除!

参考:
[1]https://en.wikipedia.org/wiki/Merkle_tree

[2]https://en.wikipedia.org/wiki/Hash_function#Hash_function_algorithms

[3]http://www.jianshu.com/p/458e5890662f

[4]http://blog.csdn.net/xtu_xiaoxin/article/details/8148237

[5]http://blog.csdn.net/yuanrxdu/article/details/22474697?utm_source=tuicool&utm_medium=referral

[6]http://crypto.stackexchange.com/questions/22669/merkle-hash-tree-updates

[7]https://en.wikipedia.org/wiki/BitTorrent

[8] 梁成仁, 李健勇, 黄道颖, 等. 基于 Merkle 树的 BT 系统 torrent 文件优化策略[J]. 计算机工程, 2008, 34(3): 85-87.

[9]http://bittorrent.org/beps/bep_0030.html

[10] 徐梓耀, 贺也平, 邓灵莉. 一种保护隐私的高效远程验证机制[J]. Journal of Software, 2011, 22(2).

[11]http://whatdoesthequantsay.com/2015/09/13/ipfs-introduction-by-example/

[12]https://www.weusecoins.com/what-is-a-merkle-tree/

[13]http://www.8btc.com/merkling-in-ethereum

[14]https://en.wikipedia.org/wiki/Gossip_protocol

[15]http://blog.csdn.net/cloudresearch/article/details/23127985

SOA和微服务架构的区别

  • 首先,可以肯定的是SOA和微服务的确是一脉相承的.
  • SOA:面向服务的架构是一个组件模型,它将应用程序的不同功能单元(称为服务)通过这些服务之间定义良好的接口和契约联系起来.
  • 以一个公司为例:有基层员工 有管理层 有老板,最初大家都听老板指挥,谁干什么,根据需要,你可能今天干A事情,明天干B事情,后来人越来越多了,事情也越来越多了,做事情的效率越来越低,管理也很混乱;
  1. 现在开始做部门划分(服务化),不同部门做不同事情,IT部门只做研发,人事部门只做招聘;
  2. 这个时候就无法避免的发生跨部门协作(服务器调用);
  3. 但是你怎么知道有这样一个部门可以做这个事情呢?这就要依赖行政部门(注册中心);
  4. 新成立的部门要在行政那里做一个备案(服务注册);
  5. 然后公布一下,让其他部门知道(服务发布),大家就可以在新的工作秩序里面嗨皮的上班了,这个时候依然是在公司的组织架构中运转;
  6. 上述就是我理解的SOA的概念.
  • 微服务:微服务有一定SOA的概念在里面,只是在粒度中,微服务更加细一点;
  1. 比如说用户业务服务:登录 注册 个人中心 包含3个业务,SOA中都由userService提供的;
  2. 但是在微服务中,登录会被独立出来一个微服务,注册也会被独立出来微服务,他们可能采用不同的语言开发,相对SOA的粒度更细,业务场景耦合更低;
  3. 另外微服务强调一个去中心化,上述的公司的组织架构会被打散,没有老板,没有管理层,每一个人都是一个服务,做着自己的事情;
  • 还是以公司举例:
  1. 工资计算是会计的事情,但我把会计部门独立出来一个公司(微服务),他们不仅能计算自己公司的财务情况,还能帮别的公司计算账务情况;
  2. IT部门只做研发,但我把IT部门独立出来一个公司(微服务),他们不仅能给自己公司开发项目,也能接别的公司的项目;
  3. 同理,HR也能客串一把猎头.

转载但有许多修改,转载地址

一次http请求的过程

  • 用户访问

首先会输入网站URL,例如:https://blog.blianb.com,这个时候DNS( Domain Name System):“域名系统”,会把域名翻译为对应的IP地址。为什么会有这一步呢?你可以先简单的理解为手机里保存的手机号与对应姓名,QQ号与备注的关系,目的是为了辨识和使用。

  1. 输入URL回车后,计算机会先查找浏览器的缓存,如果浏览器没有缓存这个URL对应的IP地址,或者缓存已经过期,那么计算机会接着查找操作系统本地DNS解析器的缓存。

    注:我们怎么查看Chrome自身的缓存?

    可以使用 chrome://net-internals/#dns 来进行查看,如下图,标红为过期:
    浏览器缓存

  2. 计算机检查本地hosts文件里是否含有这个映射关系
    Windows的hosts路径一般是 C:\Windows\System32\drivers\etc\hosts,Linux的hosts文件路径一般是 /etc/hosts

    注:Linux文件路径和内容如下图:
    host文件路径
    host文件内容

    BTW,一般做网站开发的都会修改这个文件,配合本地的web server实现虚拟主机,方便在本地测试,127.0.0.1代表请求本地的服务

  3. 查找网络设置里的DNS服务器(区域)

  4. 检查此DNS服务器里是否含有这个IP地址映射关系

  5. 最后转至根DNS服务器查询,以下是DNS服务器的一些相关资料:

名称类型 说明 示例
根域 DNS域名中使用时,规定由尾部句点(.)来指定名称位于根或更高级别的域层次结构 单个句点(.)或句点用于末尾的名称
顶级域 用来指示某个国家/地区或组织使用的名称的类型名称 .com
第二层域 个人或组织在Internet上使用的注册名称 blianb.com
子域 已注册的二级域名派生的域名,通俗的讲就是网站名 www.blianb.com
主机名 通常情况下,DNS的域名的最左侧的标签标识网络上的特定计算机,如h1 blog.blianb.com
DNS域名称 组织类型
com 商业公司
edu 教育机构
net 网络公司
gov 非军事政府机构
Mil 军事政府机构
xx 国家/地区代码(cn代表中国)
  1. DNS工作简图:
    DNS工作简图

  • 发起TCP三次请求

拿到域名对应的IP地址之后,User-Agent(一般是指浏览器)会以一个随机端口(1024 < 端口 < 65535)向服务器的web server(常用的有apache,nginx等)80端口发起TCP的连接请求。这个连接请求(原始的http请求经过TCP/IP4层模型的层层封包)到达服务器端后(这中间通过各种路由设备,局域网内除外),进入到网卡,然后是进入到内核的TCP/IP协议栈(用于识别该连接请求,解封包,一层一层的剥开),还有可能要经过Netfilter防火墙(属于内核的模块)的过滤,最终到达web server(本文就以Nginx为例),最终建立了TCP/IP的连接。

  1. 使用子网掩码判断客户机和服务器是否在一个子网络

  2. 在同一个子网络,则使用以太网进行广播发送数据包

  3. 不在同一个子网络,则通过网关转发

涉及的相关资料:
OSI模型七层协议
tcp的三次握手,建立连接
TCP/IP模型是一系列网络协议的总称,TCP/IP模型一共包括几百种协议,对互联网上交换信息的各个方面都做了规定


  • Web Server(nginx)
要知道http请求到达web server之后,web server是怎么工作的,就要先知道以下几个概念:
  1. CGI:CGI 是 Web Server 与后台语言交互的协议;

  2. FPM (FastCGI Process Manager),它是 FastCGI 的实现,任何实现了 FastCGI 协议的 Web Server 都能够与之通信;

  3. FPM 是一个 PHP 进程管理器,包含masterworker两种进程:master进程只有一个,负责监听端口,接收来自Web Server的请求,而worker进程则一般有多个 (具体数量根据实际需要配置),每个进程内部都嵌入了一个 PHP 解释器,是 PHP 代码真正执行的地方,下图是我本机上 fpm 的进程情况,1个master进程,多个worker进程(本地有3个,云服务器上有5个worker);
    本机:
    本机

运程服务器:
远程服务器

  1. 关于php-fpm worker进程的配置说明,详见php-fpm里进程管理配置介绍;

  • web server按端口监听到请求后,会分配给worker进程,调用相关PHP脚本进行具体的处理。

  • php-fpm执行php文件
    涉及到解释器的执行过程
    通过socket和数据库或是缓存等交互

  • 返回结果
    也是通过网络协议

  • 浏览器显示

转:或许你也患上了开发瘫痪症

亲爱的开发者们:你们是否因为自己只精通于三大设备平台的八种编程语言而惴惴不安?又发现一个JavaScript框架是否会让你不寒而栗、愁眉苦脸?你是否曾经因为无法确定哪个云平台最适合而把业余项目一再推迟?

或许你也换上了开发瘫痪症(Developaralysis)。颤抖吧,这个病是治不好的。

如今开发者们可选的技术方案多到令人发指,让人眼花缭乱,透不过气来。过去几年里,我拿着别人给我的酬劳,写过Java、Objective-C、C、C++、Python、Ruby、JavaScript、PHP(对不起,这个也算),用过各种各样的SQL/键值/文件数据存储技术(MySQL、PostgreSQL、MongoDB、BigTable、Redis、Memcached等等)。我是否自我感觉良好?上帝啊,一点也没有。我反而感觉到愧疚,因为我还没有用过Erlang、Clojure、Rust、Go、C#、Scala、Haskell、Julia、Scheme、Swift或者是OCaml。

我就是一名开发瘫痪症患者:软件产业发展太快、任何一个人都无法跟上,从而对我的意识造成了毁灭性打击。

上面提到的几乎任何一种语言,你都会找到无数可选的框架、套件和库——看得头都要爆炸了。如今仅仅是把JavaScript的框架和库的所有排列认真评估一遍就要花上几个月的时间。另外,你知道Ruby语言有多少种gem包吗?有多少种iOS框架吗?有多少种NewSQL或NoSQL的数据库技术吗?更不用说从Hadoop、Spark与Google Dataflow中进行选择了,究竟是用Avro,还是Thrift,还是协议缓冲区,等等,等等……

还好,移动领域已经简化到了Android、iOS两大垄断平台——尽管也隐藏着一些交叉代替方案,比如Xarmarin或者PhoneGap、Sencha这样的跨平台HTML技术——但是确定在哪个平台上部署后端、如何部署又会让你头大。我开发过的各个系统部署在Heroku、Amazon Web Services、Google App Engine、Google Compute Engine以及Parse上面……这让我感觉非常糟糕,因为我对OpenStack、Force.com、Azure、Appfog一无所知,好多AWS服务我也从来没有真正用过,说多了都是泪。

I Am Devloper @iamdevloper

2014年编写简单网站的步骤:

  1. 安装Node

  2. 安装Bower

  3. 选择CSS框架

  4. 选择敏捷的方法

……

  1. 写几行HTML代码

如今的开发者面临着太多的选择,以至于使用的许多工具仅仅是用来管理另一堆工具:比如Bundler、Bower、CocoaPods、Pip等等。这些东西太棒了!我完全离不开它们!别高兴得太早。你开始使用另一堆工具后,等用到一半的时候你真正理解了它们的内容,你开始觉得这样的配置还不够用,你有点想要把它们重写一遍了……也许再找另一个工具代替……

可悲的是,如今开发者可用的语言、工具、框架以及平台的多样性和绝对数量庞大到让人畏惧。当然没人会承认这一点。所有人都想装作精通所有语言的编程大师。然而事实却是,我们都已经深陷于开发瘫痪症之中无法自拔。

即便收集了各种信息做出了最明智的选择,结果往往也适得其反。比如说,在项目开始前,你真的花时间分析了所有的可能,克服了由此产生的学习曲线,结果却被一些用着PHP、Swift这样易于上手的语言,写着表情符号变量名的小屁孩抢了市场先机——

——不过另一方面,如果你选择使用Swift和PHP的话,你就会生活在无休止的恐惧之中,担心一些C#/Haskell程序员高手很快就会做出更好的产品几百你,就像保罗·格拉汉姆(Paul Graham)很多年前用Lisp语言编写Viaweb那样。回忆往昔,他这样写道:

当你选择了技术之后,你必须要忽略其他人在做什么,全心全意思考怎样做到最好……事实上我们确实有一个秘密武器……我们开发软件的速度超出了所有人的想象……我们用一种全是括号的语法奇怪的AI语言编写出了我们的软件。

再说回开发瘫痪症。我们应该选择已经掌握的技术吗?这样我们就能立刻动手开发,无需克服学习曲线,但是需要生活在恐惧之中,担心其他人在以更好、更快、更优雅的方式实现同样的产品,担心到了明年我们的技能就跟不上时代、丧失竞争力了。还是应该选择未知的新技术?因为我们热爱学习,更好的工具使用起来不仅更加有趣,而且能够带来巨大的竞争优势……付出的代价则是大量的时间、精力和认知负荷。

这个问题太难回答了!不存在绝对正确的答案。因此每个月都是开发瘫痪症发作月。我马上会做好五颜六色、闪闪发光的丝带给你们佩戴,只要等我选好用哪种3D打印机、哪种微控制器、哪种LED软件、哪种无人机系统就行了。恐怕要麻烦你们期待很久很久了。

翻译:顾秋实

逆波兰表达式

今天在搜索PHP算法的时候,无意间进入了知乎,有人问,PHP需要算法?有人说需要,有人说不需要,这里不说结论,只谈看到的一个回复,里面提到了逆波兰表达式,原谅我搞PHP两年了还是第一次听到这个词(非计算机专业,算法知识也很弱,正在学习中),觉得很新鲜,所以想分享一下!

逆波兰表达式又称后缀表达式,它的解释器一般都是基于堆栈的,操作数入栈,遇到操作符时,操作数出栈,求值,将结果入栈;写法是运算符在数字的后面,表达式中无需使用小括号"()",运算顺序也清楚明了,如中缀表达式1 + 2用逆波兰表达式则为 1 2 +,中缀表达式1 + 2 * 3用逆波兰表达式则为 1 2 3 * +,PS:在搜索中缀表达式时,看到百度百科的词条里面好像有错误,理解了这个例子能更好的理解逆波兰表达式,如下图(截图时间是2015-08-30 20:40):

它举了一个例子:中缀表达式8 + 4 - 6 * 2(=0)用逆波兰表达式则为6 2 * 8 4 + -(=0),按照这个逆波兰表达式,如果转为中缀表达式其实是(6 * 2) - (8 + 4)(=0),计算结果没有问题,但计算顺序错误。如果把中缀表达式换为8 + 4 - 6 * 3(= 负6),按照图中写法逆波兰表达式则为6 3 * 8 4 + -(= 正6),所以正确写法应是8 4 + 6 2 * - 或是8 4 + 6 3 * -(如果有理解不对的地方,请快速提醒我,以免误导他人)。

逆波兰表达式的优点(摘自维基百科,自由的百科全书):

用于表达式求值,以利用堆栈结构和减少计算机内存访问。

当有操作符时就计算,因此,表达式并不是从右至左整体计算而是每次由中心向外计算一部分,这样在复杂运算中就很少导致操作符错误。

堆栈自动记录中间结果,这就是为什么逆波兰计算器能容易对任意复杂的表达式求值。与普通科学计算器不同,它对表达式的复杂性没有限制。

逆波兰表达式中不需要括号,用户只需按照表达式顺序求值,让堆栈自动记录中间结果;同样的,也不需要指定操作符的优先级。逆波兰计算器中,没有“等号”键用于开始计算。

逆波兰计算器需要“确认”键用于区分两个相邻的操作数。

机器状态永远是一个堆栈状态,堆栈里是需要运算的操作数,栈内不会有操作符。

教育意义上,逆波兰计算器的使用者必须懂得要计算的表达式的含义。

Лучшее Казино Онлайн На Рубли С Бонусом

Лучшее Казино Онлайн На Рубли С Бонусом::играть В Игровой Автомат Смайл Фортуна

Казино работает на платформе от PlayTech, данный разработчик игр отличается непревзойденным качеством и реалистичностью игровых продуктов, которых насчитывается более 400.