不为有趣之事,何遣有涯之生
不失其所者久,死而不亡者寿

大型网站架构演变初探

hzqiuxm阅读(2582)

前言

大型网站的发展都是由一个小网站开始的,随着现在越来越多的大型网站出现,导致越来越少的架构师能够去经历一个网站真正从小到大历程。从这点上来说,不对不说是有点遗憾,但是不管是农业社会的发展,还是工业社会的发展,以及当下互联网时代的发展,我们人类教育,科技,文明发展无一不是站在巨人的肩膀上。只有这样才能迅速成长。在这个知识大爆炸的时代,这兴许是已成为自然规律。

虽然现在越来越少有机会去亲身去经历一个小型网站如何逐步进化,蜕变成庞然大物的,但是我们可以参考现有的大型网站,研究它们是如何一步一步走到今天的。不管何种的大型网站架构,一般都会经历从简单到复杂,从单服务器到集群的演变。鄙人不才,作为新手,初探此径。总结了它们一般所经历的几个演变阶段。由于每个行业的业务存在较大差别,所以在某些方面可能会有不同,该演变阶段只是提供了一个简单的演变思路。真正的演变历程,原比我们想象要复杂的多,那是多少前辈与先驱者辛勤劳动与智慧的结晶。

第一阶段:有家网站初长成

由于网站规模很小,所有的程序,文件都会部署在通一台应用服务器上,甚至采用虚拟技术与其它网站共同部署在一台应用服务器上。
那么它的架构大致如下图:

此处输入图片的描述

第二阶段:分而治之

随着网站规模增大,将应用程序,文件存储,数据库单独部署,从而满足更多用户请求
由于每台应用服务器作用不同,它们关注的东西也不尽相同,如应用服务器,我们通常所说的
程序代码都跑在上面,那么最关注的是CPU。

单独部署架构大致如下:

此处输入图片的描述

第三阶段:二八定律

耳熟能详的二八定律再次降临,无论在管理,销售,教育等等领域,都有这经典二八理论一说。那么它对架构有着什么影响呢?

上个阶段我们已经将数据库,文件,应用程序作了单独部署,但是随着用户量的增大,数据库压力将面临挑战。由于大多数用户感兴趣所访问的数据(热门商品,公共数据),一般占了总数据的20%,就像热卖的商品只有性价比高的,或促销的那几样一个道理。那么既然如此我们可以把经常访问的数据事先加载入缓存,这样就不用每次都去访问数据库了。

加入缓存后的架构:

此处输入图片的描述

第四阶段:人多力量大的应用

加了缓存后,数据库的压力是得到了缓解,但是应用还是要被每个用户实实在在访问的,随着用户进一步增大,考虑增加应用服务器,实现集群技术采用负载均衡很好分摊了各服务器的压力。

应用服务器集群化后的架构图:

此处输入图片的描述

第五阶段:速度与主仆

在之前阶段中我们已经对经常访问的数据做了缓存,减轻了数据库的压力。但是缓存的只能是用户需要访问的数据,对于用户需要写入的数据,还是需要实实在在去访问数据库的,所以随着该类型的业务增长,数据库模块必须做出改变。

一般我们会采用读写分离的技术,某几台数据服务器负责写操作,某几台数据服务器负责读操作,负责写的一般称之为主服务器,负责读的则称之为从服务器。然后将主服务器的数据同步到从服务器,从而保证数据的一致性。

一般在这个阶段,说明我们网站的用户规模已经不可小觑了,那么用户体验将变得更加重要。用户体验最直接的影响就是用户通过浏览器来访问你的网页,你让用户看到网页上内容的时间。这个时间不仅仅取决服务的提供者我们,还取决于用户使用的浏览器,用户的使用网络服务商。所以我们必须尽可能让用户第一时间看到他们想要看到的。

一般我们会在负载均衡前再部署2类应用设备,一类叫反向代理服务器,一类叫CDN(内容分发网络,有专门的服务提供商)这二者的本质还是缓存,我们将一些静态元素(html,js,css)和常用的数据缓存在上面,用户发起请求时,部分请求可直接由它们负责响应,大大提升了响应速度。

由于用户有着区域性特点,通过在不同区域增加CDN节点,也能起到提升用户体验的效果。
该阶段的架构图大致如下:

此处输入图片的描述

第六阶段:集群普遍化

随着用户规模越来越大,主从式的数据库也出现了瓶颈,管理的文件也增加了不少,那么我们就将它们也集群化吧。
数据库的集群还可以采用关系数据库与NoSQL数据库混合模式,不仅高效而且灵活。还有可以增加搜索引擎来检索数据。

此处输入图片的描述

第七阶段:SOA与分类

一般到了第六阶段,已经能够应付比较大规模的用户了,但是有的网站,由于其业务繁多,逻辑复杂,或者某些应用在特殊的应用场景下,其压力远远大于其他应用服务器。那么一般我们会采用SOA思想,将不同的应用拆分到不同的应用服务器集群,将相同的应用封装成公共服务,统一管理。不同应用之间还可以采用异步方式,缓解压力,加速响应。

一般到此为止,能够应付绝大多数海量用户了。当然一样的架构,由于其内部模块设计,算法,数据结构等因素,最后的表现也不尽相同。还有不同的企业,由于其业务导向,侧重点不一样,架构上也会做相应的调整。所以没有一成不变的大型网站架构,不变的只有其本质思想。
该阶段的架构图:

此处输入图片的描述

小结

最后对分布式架构部署演变做个简单的小结,罗列了分布式系统演化的各个阶段,根据每个系统自己业务特点,每个阶段的顺序会出现不同,有的甚至会跳过或者几个阶段合并成一个阶段,但其思想脉络还是一脉相承,希望大家通过本文,你对网站系统架构演变有了基本的了解。
- 集所有应用到一台服务器的最简部署
- 分离web服务器和数据库
- 水平增加web服务器
- 加入分布式的文件系统
- 加入缓存服务
- 数据库主从集群、读写分离
- 进一步水平增加web服务器,引入反向代理,负载均衡
- 按业务进行缓存分离,缓存集群
- 数据库分区,分库,分表
- 加入Nosql
- 加入消息系统
- 各种服务均集群化
- 对应用进行拆分部署,甚至是功能级别的细粒度拆分
- 加入F5等硬件设备,CDN服务
- 对重要的节点进行HA集群或者双机热备

常见的负载均衡策略

hzqiuxm阅读(2617)

常见负载均衡策略

前言

随着大规模的集群应用越来越普及,大小企业都会采用负载均衡来实现服务器压力分摊。
本人初步整理了下,目前在企业中常用的几种负载均衡策略。每种策略有着自己的优缺点,适用的场景也不同,所以在一个企业中,
可能存在一种或多种的策略共存情况。

HTTP重定向负载均衡

这个是早期用的比较多的一种负载均衡策略,采用的思路是用一台http服务器来接受用户的请求,通过设置的负责均衡算法,返回一个重定向的真实服务器给用户终端,用户终端根据重定向的URL,访问真实的服务器。该种策略的虽然简单,但是目前可能会被搜索引擎判为SEO作弊,降低搜索排名,需要权衡使用。
http重定向策略架构图:

此处输入图片的描述

DNS域名解析负载均衡

设计思路是利用DNS服务器,对地址解析的时候,直接根据配置好的规则,返回均衡后的IP地址,该策略设计简单省力,性能也有改善,DNS会自动解析离用户最近的一个服务器地址给用户。但是一般DNS解析是一个多级解析,当某台服务器下线后,DNS未及时更新,可能访问已经失效的服务器。所以在实际应用时一般通过DNS返回的是一组服务器,然后再通过其他负载手段访问组服务器中的某台服务器。

DNS域名解析负载策略架构图:
此处输入图片的描述

反向代理负载均衡策略

反向代理服务器是处在服务器前端的位置,一般可以扮演安全,缓存,负载的角色。作为负载服务器,它的有点是简单,缺点是每次都经过反向代理服务器中转,它很容易成为系统瓶颈。

反向代理负载均衡策略架构图:
此处输入图片的描述

IP负载均衡策略

设计思路是采用一台网关服务器,设置上服务器的内外网地址,当用户通过外网地址访问的时候,通过负载算法,将其路由到某台内网服务上。
由于内部服务器和网关采用过的是内网交互,最后网关返回给用户时候,必须将源地址重新修改为网关服务器的外网地址。该策略比起反向代理,性能上有了改善,但是带宽会成为其瓶颈,如果服务的应用以下载功能为主的话,慎用该策略。

IP负载均衡策略架构图:
此处输入图片的描述

数据链路负载均衡策略

IP负载均衡策略采用的是网关服务器修改IP来解决,那么能不能直接让内部服务器返回给用户呢?当然可以,只要负载均衡器修改MAC地址即可,这种方式就被成为数据链路负责均衡策略。这个就避免修改数据包的源地址,目的地址,与目的服务器直接响应。比如LVS采用的就是该种策略。

数据链路负载均衡策略架构图:
此处输入图片的描述

本文中未提及负载均衡算法,在实际应用中,负载均衡策略与负载均衡算法是结合使用的。在某些简单的应用中,可能直接在代码或配置文件中采用均衡算法来实现负载,

程序猿DE密码学(2)

hzqiuxm阅读(3680)

随机数漫谈(下)

故事后续

上回说到,不懂随机数的锁匠,他虽然打造出了世界上最安全的锁,但是所有的锁都是统一的钥匙。只要获得了其中一把钥匙,就可以打开所有的锁了。了解了随机数的三个性质后,锁匠开始准备打造至少具备不可预测性的钥匙来和他的锁配对,这样的组合才是最牢固的。于是他开始了随机数生成器研究。

伪随机数生成器

上一节说到随机数可以用软件方式生成(我们大多数情况下都是这么做的),也可以用硬件方式生成。硬件方式生成才能具备不可重复性,软件无论如何只能生成不可预测性的随机数。我们把这里的硬件设备叫做随机数生成器,而软件则成为伪随机数生成器。因为软件生成的只能做到不可预测性,所以软件生成的随机数,也叫做伪随机数。

伪随机数生成器结构

伪随机数生成器一般由二部分组成:内部状态和外部种子

伪随机数生成器结构

内部状态

伪随机数生成器结构的内部状态,就是指伪随机数生成器管理的内存中的数值(一般是多个)。伪随机数就是根据内存中的值进行一系列的计算,计算的结果就是伪随机数。随后,为了响应下一个伪随机数生成请求,伪随机数会改变自己的内部状态。因此,将根据内部状态计算伪随机数的方法和改变内部状态的方法组合起来,就是伪随机数生成的算法。

内部状态决定了下一个生成的伪随机数,因此内部状态不能被攻击者知道。

种子

为了生成伪随机数,伪随机数生成器需要被称为种子的信息对伪随机数生成器的内部状态进行初始化。

伪随机数的种子是一串随机序列的比特值,然后根据种子结合内部状态,我们就可以生成伪随机数列了。要特别注意:伪随机数生成算法是公开的,但是种子必须保密,这就好像是密码算法是公开的,但密钥必须保密。由于种子是需要保密的,所以不能用容易被预测到的值。例如人们最常犯的错误就是把当前时间作为种子。

打造伪随机数生成器方法

杂乱的方法

有人会说,既然是生成杂乱无章的数列,那么我就使用杂乱无章的方法不就可以了吗?答案当然是否定的,如果你无法理解一个生成方法,那么你如何保证这个复杂的算法生成的数列是具备不可预测性的呢?试验证明,往往这样算法生成的伪随机数周期都非常短。由于密码技术中使用的伪随机数要求具备不可预测性,短周期的数列肯定是不可以的。

线性同余法

线性同余法是一种广泛使用的伪随机数生成器算法。然而,它不能应用于密码技术。

线性同余法算法大概思想就是将当前的伪随机数值乘以A再加上C,然后将除以M得到的余数作为下一个伪随机数
假设我们要生成的伪随机数列伪R0,R1,R2 ......。首先我们根据种子,用下列公式计算第一个伪随机数R0

第一个随机数R0 = (A x 种子 + C)mod M

公式中的A,C都是常数,且A和C需要小于M。接下来,根据R0用相同的公式计算下一个伪随机数R0,如此反复。概括公式如下:

Rn+1 = (A x Rn + C) mod M

在线性同余法中,最近一次生成的伪随机数的值就是内部状态。伪随机数的种子被用来对内部状态进行初始化。它的结构图如下:

线性同余法伪随机数生成器结构图

程序代码示例如下:

public class LineRandom {
    public static void main(String[] args) {

        int m = 7;
        int a = 3;
        int c = 1;
        int random = 0;
        int seed = 1;

        while(true){
            random = (a * seed + c)%m;
            seed = random;
            System.out.print(random);
        }

    }
}

我们看下输出结果:

46520146520146520146520146520146520146520146520146520146520146520146520146520146 ......

可以发现该数列的循环周期是6:465201
在线性同余法中,只要谨慎选择A,C,M的值,就能够很容易地生成具备随机性的伪随机数列。然而,它不具备不可预测性,我们不能将它应用与密码学技术。很多随机数库都是采用线性同余法写的。比如C语言的rand,还有java的Random。所以这些函数不能用于密码技术。

单向散列函数法

使用单向散列函数可以编写出具备不可预测性的伪随机数列(强伪随机数)。它的结构图如下:

单项散列函数法伪随机数生成器

它的工作方式如下:
1 用伪随机数的种子初始化内部状态
2 用单向散列函数计算散列值
3 输出散列值作为强伪随机数
4 修改内部状态
5 根据需要重复2-4步骤

这个工作方式是否可预测呢?攻击者如果想要预测下一个伪随机数,需要知道内部状态的值。而伪随机数是一个散列值,就相当于攻击者要破解散列函数的单向性,这是非常困难的。其实大家都看到了,单向散列函数的单向性是支撑伪随机数生成器不可预测的基础

程序代码示例如下:

public class MacRandom {
    public static final String SHA_ALGORITHM = "SHA-512";

    public static void main(String[] args) throws Exception {

        String counter = "hello world!";//计数器初始值
        String randomStr = "";//随机数


        while (true) {
            randomStr = SHA(counter.getBytes());
            System.out.println(randomStr);
            counter = counter + 1;
        }

    }

    /**
     * SHA Security Hash Algorithm 安全散列算法,固定长度摘要信息 SHA-1 SHA-2( SHA-224
     * SHA-256 SHA-384 SHA-512) 使用的依然是MessageDigest类,JDK不支持224
     *
     * @param plainText
     * @return
     */
    public static String SHA(byte[] plainText) {
        MessageDigest messageDigest;
        try {
            messageDigest = MessageDigest.getInstance(SHA_ALGORITHM);
            return Base64.encodeBase64String(messageDigest.digest(plainText));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

上面代码中我们对内部状态值改变使用了简单的加1操作
篇幅有限这里随机截取了一些输出结果,有兴趣的同学可以自己尝试下,验证其不可预测性

cHRLWs/WLXOLhJ273RhDuN0MBC3plbi0JwyHEUo7gD02J7g8aUK0BYp4JROtTaz88UtgHm8c/9t7
fHGTu9op1Q==

jwW2P0m88M5saQue3Y9hwwVJYVs9JN94EXTkOZfB8Dsw5O9NrciPROFgfcygZ7wvH88ETRpY8ciP
k5pLhjwrAQ==

8X9m7c+1qVctkRljYXbqqZbVTAQ+Y/frL2hmHRamKIaqMO8AMytBD4GyxMPmqbWEVZRm9TLQrRiC
lWOGUa12IQ==

FoNd2JYZlIjbipqB6eShDaE78DGYOV+gw3g++bsaDJPhG88W5VcMLHz9LFDO6ZZr3/iweYChwMNG
aW1iJ5APFw==

RQ9JN8C91v+WoJYsDnlaLPsB0PTe2snp1YLj3yYCWGKknCEcYgnnZEYjEu7TfAEEjHUytWAiyaaR
61BhOzYCjw==

okZDHefqnCLT0qsAZwxA3/R423ccSLtVmlFwlcV3LZOXNdfLULSNz4X0tOKYkO4IfZU49K1UM2it
lEg4OyHw1A==

qRmhTlaQE71wHAo0+XuCBHp2CXA9CwQHYQvb50NTLIRYyEQ/41REx32UZUVqpQVLWtOwyovkUKhC
qPJ8wx5GLg==

HdN5JxdpM+m9XFnLZWois0XsrRE+XSulTfCm0/8ixCPea/DG1HaItbxRqFUnFb2zIw6yJFgeWlV9
QiWdOZmdnQ==

0HKocNlc6Un9c8Pms9vi6ppDrFv9/mq9boY38Ek2DahS4kkpyyjz5OOZD/Hr17DHlMXZKZl1h0QH
1z0rojOOiQ==

znRatSv1+5otr4E98+CPI+MeRqyhH16dbWpsFntxMGAfbTnLK76+mtRUBZ0gge3eXz3l1OB+Qg9y
aJAd9h0o8g==

k9y1PLVypfn1LqNfTCNHvkFJ3EBLYtN4nnXPkVDh+LDBjLobiyswBuoXEexOn1yjjV0fknU9wtUj
1dWKo5RxFA==

密码法

我们可以使用密码来编写能够生成强伪随机数的伪随机数生成器。既可以使用AES对称加密,也可以使用非对称的RSA,ECC算法。
这种伪随机数生成器的结构如下:

密码法伪随机数生成器

它的工作方式如下:
1 用种子的初始值部分初始化内部状态
2 用密钥加密内部状态的值
3 输出密文作为强伪随机数
4 修改内部状态
5 根据需要重复2-4步骤

我们可以看到,密码法的伪随机数生成器中发生最大变化的就是种子,它巧妙的把密钥和初始值作为种子,再结合加密算法,将密文作为伪随机数列。
和单向散列有异曲同工之妙,利用密码法中的密钥的机密性来保证了伪随机数列的不可预测性

由于篇幅原因,就不上示例代码了。先生成密钥后,用密码像单向函数那样进行计算就可以了。该方法的伪程序代码如下:

key 的值与内部状态初始值的结合相当于伪随机数种子

初始值的值相当于内部状态
key = 密码的密钥
counter = 初始值
while(true){
    伪随机数 = 用key加密(counter)
    输出伪随机数
    counter值加1
}

ANSI X9.17

该种方法使用了三重DES算法,它的核心思想和密码法类似。在这里简单介绍下其实现步骤:
1 用种子的初始值部分初始化内部状态
2 将当前时间加密生成掩码
3 对内部状态与掩码求XOR
4 对步骤3的结果用种子密钥部分进行加密
5 将步骤4的结果作为强伪随机数输出
6 对步骤4的结果与掩码求XOR
7 将步骤6的结果用种子密钥部分进行加密
8 将步骤7的结果作为新的内部状态
9 根据需要重复2-8步骤

篇幅原因,这里只给出该程序的伪代码

key 的值与内部状态初始值的结合相当于伪随机数种子

key = 加密密钥
内部状态 = 初始化(内部状态初始值)
while(true){
    掩码 =  用key加密当前时间
    伪随机数 = 用key加密(内部状态 XOR 掩码)
    输出伪随机数
    内部状态 = 用key加密(伪随机数 XOR 掩码)
}

伪随机数生成器常受到的攻击

对种子进行攻击

伪随机数的种子和密钥同等重要。如果攻击者知道了种子,再由于算法是公开的,他就知道这个伪随机数生成器所生成的全部伪随机数列。所以我们必须使用具备了不可重现性的真随机数作为种子。

对随机数池进行攻击

一般我们不会在需要随机数的时候才会去生成,为了生成效率考虑,我们都会事先生成一堆随机数比特序列。我们称之为随机数池,一般保存在文件中。当密码软件需要伪随机数的种子时,我们就从随机池中取出所需长度的随机比特序列来使用。
随机数池本身并不存储任何有意义的信息,但是我们却要认真的保护它们。虽然听上去有点违背常识,但这是你必须要做的。

上期答案: 具备不可重复性。注意审题哦,题目问的是反复掷骰子生成的数列,而不是问掷骰子的点数哦

程序猿DE密码学(1)

hzqiuxm阅读(3349)

随机数漫谈(上)

阅读前希望你具备一定的密码学基础,理解了一些最基本的密码学名词

故事前言

从前有个锁匠,他制锁的手艺非常之高超,他自豪的和村子里的人说:"我制作的锁头十分坚固,小偷绝对打不开。"因此,村子里的人都为自己的房子装上了锁匠打的锁。锁匠的锁,真的非常坚固,没有人能够不用钥匙打开,但是大家发现了一个问题,锁匠做的每把锁的钥匙居然都是相同的!因此小偷只要得到任意一把钥匙就可以打开所有的房子上的锁了!这个粗心的锁匠~

此处输入图片的描述

锁和随机数

从上个故事里我们看到粗心的锁匠做的锁虽然坚固,但是却都用了相同的钥匙,导致一把钥匙可以打开所有的锁了。那么和我今天要讲的随机数有什么关系呢?我们知道在密码学里和安全最机密关系的就是对称密钥或私钥。那么要生成绝对安全性的对称密钥或者私钥,其实都是要用到随机数的,可以说随机数的生成方式就决定了密钥或私钥的安全性。如果我们用了相同的随机数或者不安全的随机数,那么生成的密钥或私钥就如同锁匠打造的锁,其实都用了相同的钥匙,你说随机数重要不重要?

随机数用来做什么?

在密码学里,其实很多地方都用到了随机数,但是我们平时都不太关注它,不知道默默无闻的随机数,在密码学领域时刻在默默无闻的发挥着重要的作用。例如如下场景中,我们就会使用到随机数:

  • 生成密钥

用于对称密码或者消息认证码

  • 生成密钥对

用于公钥密钥(非对称加密)和数字签名,公钥和私钥

  • 生成初始化向量(IV)

用于分组密码的CBC,CFB,OFB模式等

  • 生成nonce

用于防御重放攻击以及分组密码的CTR模式等

  • 生成盐

用于基于口令的密码(PBE)等

这些场景中,随机数扮演的角色都很重要,当然最重要的还是我们之前谈到的这里的头两项:生成密钥和生成密钥对。即使我们的密码算法强度再高,只要攻击者知道了密钥,你加密算法就会立刻形同虚设。而随机数就是让攻击者无法看穿密钥的关键所在。

随机数有哪些性质?

我们今天的随机概念只讲随机数和密码学之间的关系,不会涉及到哲学领域。
我们一般将随机数的性质分为以下三类:
- 随机性:不存在统计学偏差,是完全杂乱的数列(弱伪随机数)
- 不可预测性:不能从过去的数列推测出下一个出现的数(强伪随机数)
- 不可重现性:除非将数列本身保存下来,否则不能重现相同的数列(真伪随机数)

这三个性质的严格程度,是从上到下递增的。下面的性质包含了上面的性质,比如说:具备了不可重现性,就一定具备了不可预测性和随机性。
在密码学领域,至少具备了不可预测性性质的随机数,才可以被用于密码技术。
但是其实,密码学中的随机数也都只是做到了具备不可预测性而已,不会使用到不可重现性性质的随机数。为什么呢?我们接下来简单介绍下每个性质,你就一目了然了。

此处输入图片的描述

随机性

简单的说随机性就是杂乱无章的概念。不可以存在统计学上的偏差(所有值出现的频率相近),比如我们掷骰子,每个点数的出现都是随机的,进行统计的话,1-6的出现概率都是接近1/6的。我们平时玩个游戏,抽个奖,使用的随机数只要具备随机性就可以了。

但是密码学里不可行,因为只是具备随机性的话,不代表不会被看穿,就拿刚才掷骰子的例子,一个筛子只有1-6个点,只要攻击者知道你的随机数使用掷骰子的方式生成的(或者观察了一定次数后),那么就会知道下一次的点数肯定是1-6中的某一个数字,来6个攻击者,每个人猜一个数字,肯定有一个能猜中是吧。

所以,只具备随机性的随机数,我们称之为:弱伪随机数

不可预测性

密码学中的随机数,必须不能被看穿,所以要具备不可预测的性质才行。简单的说不可预测性就是事先不可能说中。复杂点说就是指攻击者在知道过去生成的伪随机数的前提下,依然无法预测出下一个生成出来的伪随机数。

其实伪随机数生成器的算法和密码学中加密算法一样,都是公开的。但是伪随机数生成器的种子(你可以理解成生成随机数需要的密钥)是保密的。所以即使攻击这知道了之前所有的伪随机数以及生成算法,他也无法预测出下一个生成出来的伪随机数,这就是不可预测性。

那么如何编写出不可预测性的伪随机数生成器呢?这是个很有趣的问题,我们的不可预测性其实是通过其他密码技术来实现的。例如:可以通过单向散列函数的单向性和密码的机密性来保证伪随机数生成器的不可预测性。后面会有详细的代码示例。

我们把具备不可预测性的随机数称之为:强伪随机数

不可重现性

不可重现性就是指无法重现和某一种随机数列完全相同的数列的性质。如果除了将随机数列本身保存下来以外,没有其他方法重现该数列。

告诉大家一个不幸的消息:使用软件是无法生成出具备不可重复性的随机数列的。软件只能生成伪随机数列,所以软件实现的随机数生成器,我们就称作伪随机数生成器。那这是什么原因呢?那是因为运行软件的计算机本身仅具备有限的状态集,在内部状态相同的情况下,软件必然会生成相同的数,所以通过软件生成的随机数,一定会重复。重复的长度我们称之为周期。周期可以很短,也可以很长,但终归还是有限的。

要生成具备不可重复性的随机数列,需要从不可重现的物理现象中获取信息。比如周围的温度和声音变化,鼠标的移动位置信息,键盘输入的时间间隔,放射线测量仪输出值等。根据硬件中获取到的信息生成的数列,一般可以认为是具备不可重复性的随机数列。

目前,已经出现了用传感器感知热度变化,并根据这一变化的信息来生成具备不可重复性的随机数列的硬件设备。但是要让这样的设备成为计算机的标配,那还需要比较长的一段时间。

我们把具备不可重复性的随机数称之为:真随机数

本文的漫谈就先到这里,下篇中我会给大家介绍伪随机数生成器的设计方法以及简单代码示例,还有一些常见的攻击方式。
最后问大家一个问题:我们反复掷骰子所生成的数列,是否具备不可重复性呢?答案见《随机数漫谈(下)》末尾

SpringCloud微服务系列(1)

hzqiuxm阅读(5562)

微服务与SpringCloud入门

微服务的实现方式

  • 1 Doubbo
  • 2 SpringCloud
  • 3 其他开源实现

参考链接

Spring Cloud:http://projects.spring.io/spring-cloud
Dubbo:http://dubbo.io
Dropwizard:http://www.dropwizard.io
Consl、etcd &etc.

SpringCloud中的概念名字一览

Eureka Server


- 依赖于:spring-cloud-starter-eureka-server (默认是服务端和客户端为一体的)
- 作为服务使用时,一般需要关闭掉客户端的功能
- 注册中心,可以注册服务的提供者,服务的调用者,服务网关,服务跟踪者,配置服务等
- 当需要多个注册中心时,可以配置和其他注册中心同步,实现高可用

Eureka Client


- 依赖于:spring-cloud-starter-eureka-server
- 任何需要注册到注册中心的服务,都是Eureka Clinet,可以是服务提供者,调用者,服务网关,服务跟踪者,配置服务等

Ribbon


- 客户端的负载均衡器
- ribbon是一个负载均衡客户端,可以很好的控制http和tcp的一些行为
- 依赖于:spring-cloud-starter-eureka-server,spring-cloud-starter-ribbon
- 结合restTemplate使用,通过@ LoadBalanced注册表明,这个restTemplate是负载均衡的
- 支持简单的URL访问,复杂的不太适合
- 可以单独使用,不依赖于Eureka

Hystrix

  • 断路器,防止微服务出现雪崩现象
  • 依赖于:spring-cloud-starter-hystrix
  • 有的SpringCloud版本默认已经为Feign整合了Hystrix(亲自测试Edgware是没有自动支持的,需要添加依赖并在配置文件中开启),我们要做的是自定义添加回退函数和原因

Feign


- 它是一个声明式的http客户端负载功能,其实也是依赖Ribbon
- 使用的时候坑还是有点多的,要多注意
- 通过注解方式,弥补了Ribbon访问时只适合URL的方式
- 依赖于:spring-cloud-starter-eureka-server,spring-cloud-starter-feign(包含了Ribbon,Hystrix)
- Feign有自己的注解,但是spring为了降低大家的使用成本,对其做了一些封装改造,很多的地方可以使用spring的注解来操作
- 使用注解@FeignClient(value = "服务名")来指定哪个服务

Zuul


- 网关中心,外部客户端统一调用网关,由网关协调各服务调用
- 依赖于:spring-cloud-starter-zuul
- 网关中心好处:易于监控,易于认证,减少客户端与各个微服务之间的交互次数

SpringCloudConfig


- 分布式配置中心,分为服务端server和客户端client
- 依赖于:spring-cloud-config-server,spring-cloud-starter-eureka-server
- config-client从config-server获取了foo的属性
- config-server从git仓库中获取配置,仓库可以是本地也可以是远程

  • http请求地址和资源文件映射如下:
    /{application}/{profile}[/{label}]
    /{application}-{profile}.yml
    /{label}/{application}-{profile}.yml
    /{application}-{profile}.properties
    /{label}/{application}-{profile}.properties

Spring Cloud Bus

  • 消息总线

Sleuth

  • 追踪器,为spring cloud 提供了分布式跟踪的解决方案
  • 依赖于: spring-cloud-starter-sleuth
  • 一般还会同其他的日志系统结合使用:ELK

SpringCloud整体图

欢迎加入极客江湖

进入江湖关于作者