冰冷的梦境


  • 首页

  • 分类

  • 归档

  • 标签

  • 关于

设计模式-命令模式

发表于 2017-06-25 | 分类于 设计模式

命令模式

  命令模式将请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,然后该对象在执行命令。属于行为模式。

优点

  • 降低了系统的耦合度。
  • 新的命令可以很容易添加到系统中去。

确定

  • 使用命令模式可能会导致某些系统有过多的具体命令类。

适用场景

  • 认为是命令的地方都可以使用命令模式。比如:GUI中每一个按钮都是一条命令。
  • 模拟CMD。

类图

image


参考

  • http://www.runoob.com/design-pattern/command-pattern.html

设计模式-责任链

发表于 2017-06-24 | 分类于 设计模式

责任链

  责任链模式就是为请求创建一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。属于行为型模式。

  每个接收者都包含下一个接收者的引用,如果该接收者不能处理该请求,那么就把该请求传递到下一个接收者。

优点

  • 降低耦合度,将请求的发送者和接收者解耦。
  • 简化了对象,使得对象不需要知道链的结构。
  • 增强了给对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态的新增或者删除责任。
  • 增加新的请求处理类变得很简单。

缺点

  • 不能保证请求一定被接收。(可能所有的处理者都处理不了这个请求)
  • 系统的性能将受到一定影响,而且在进行代码调试的时候会很麻烦。(比如,处理链有10个处理者,这个请求只能被最后一个处理者处理,但该请求还是要经过前面9个处理者)
  • 可能不容易观察运行时的特征,有碍于除错。

使用场景

  • 有多个对象可以处理同一个请求,具体哪个对象处理该请求由运行时刻自动决定。
  • 在不明确指定接收者的情况下,向多个对象中的一个提交请求。
  • 可动态指定一组对象处理请求。

类图

image
  声明一个抽象类Logger,在Logger中声明一个抽象方法write。然后声明4个继承Logger的类,并实现write方法。

1
2
3
4
5
6
7
8
9
10
11
DebugLogger debugLogger = new DebugLogger(1);
InfoLogger infoLogger = new InfoLogger(2);
WarningLogger warningLogger = new WarningLogger(3);
ErrorLogger errorLogger = new ErrorLogger(4);
//链式关系
debugLogger.setLogger(infoLogger);
infoLogger.setLogger(warningLogger);
warningLogger.setLogger(errorLogger);

debugLogger.loadMessage(1,"test1");
debugLogger.loadMessage(3,"test3");

参考

  • http://www.runoob.com/design-pattern/chain-of-responsibility-pattern.html

设计模式-模板模式

发表于 2017-06-24 | 分类于 设计模式

模板模式

  在一个抽象类中公开定义执行它的方法的模板。它的子类可以按需重写方法,但调用将以抽象类中定义的方式进行。

优点

  • 封装不变部分,扩展可变部分。
  • 提取公共代码,便于维护。
  • 行为由父类控制,子类实现。

缺点

  • 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。

适用场景

  • 有多个子类有相同的方法,且逻辑相同。
  • 重要的、复杂的方法,可以考虑作为模板方法。例如:spring中对hibernate封装的开启事务、获取session、关闭session等函数。

类图

image

1
2
3
4
Game dota = new Dota();
dota.play();
Game lol = new LOL();
lol.play();

参考

  • http://www.runoob.com/design-pattern/template-pattern.html

线程池

发表于 2017-05-14 | 分类于 笔记

线程的优势

  • 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
  • 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
  • 提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。

线程池的处理流程

  1. 线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。
  2. 线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了,则进入下个流程。
  3. 线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行任务。如果已经满了,则交给饱和策略来处理这个任务。

ThreadPoolExecutor执行execute方法的四种情况

  1. 如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(注意,执行这一步需要获取全局锁)。
  2. 如果运行的线程等于或多于corePoolSize,则将任务加入BlockingQueue。
  3. 如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(注意这一步需要获取全局锁)。
  4. 如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。

ThreadPoolExecutor的参数

1
new ThreadPoolExecutor(corePoolSize,maximumPoolSize,keepAliveTime,milliseconds,runnableTaskQueue,handler);
  • corePoolSize(线程池的基本大小):当提交一个任务到线程池时,线程池会创建一个线程来执行任务,即使其他空闲的基本能线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建。如果调用了线程池的prestartAllCoreThreads()方法,线程池会提前创建并启动所有基本线程。
  • runnableTaskQueue(任务队列):用于保存等待执行的任务的阻塞队列。可以选择一下几个阻塞队列。
    • ArrayBlockingQueue:是一个基于数字结构的有界阻塞队列,次队列按FIFO(先进先出)原则对元素进行排序。
    • LinkedBlockingQueue:是一个基于链表机构的阻塞队列,次队列按FIFO排序元素,吞吐量通常高于ArrayBlockingQueue。静态工厂方法Executors.new FixedThreadPool()使用了这个队列。
    • SynchronousQueue:一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常高于LinkedBlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。
    • PriorityBlockingQueue:一个具有优先级的无限阻塞队列。
  • maximumPoolSize(线程池最大数量):线程池运行创建的最大线程数。如果队列满了,并且已创建的线程数小于最大线程数,则线程池会再创建新的线程执行任务。值得注意的是,如果使用了无界的任务队列这个参数就没有效果了。
  • ThreadFactory:用于设置创建线程的工厂,可以用个线程工厂给每个创建出来的线程设置更有意义的名字。使用开源框架guava提供的ThreadFactoryBuilder可以快速给线程池里的线程设置有意义的名字。
  • RejectedExecutionHandler(饱和策略):当队列和线程池都满了,说明线程池处于饱和状态,那么必须采取一种策略处理提交的新任务。这个策略默认情况下是AbortPolicy,表示无法处理新任务时抛出异常。
    • AbortPolicy:直接抛出异常。
    • CallerRunsPolicy:只用调用者所在线程来运行任务。
    • DiscardOldestPolicy:丢弃队里里最近的一个任务,并执行当前任务。
    • DiscardPolicy:不处理,丢弃掉。

对zookeeper的理解

发表于 2017-03-13 | 分类于 笔记

zookeeper是一个开源的分布式服务。分布式应用可以基于zk实现的功能包括:数据发布/订阅、负载均衡、命名服务、集群管理、master选举、分布式锁、分布式队列等。


基本概念

角色

  在zookeeper中,主要有三种角色:

  • leader:在一个zk集群中,同一时刻只能有一个leader。zk集群通过选举,来选定一台机器为leader,leader服务器为客户端提供读写服务。
  • follower:follower服务器能够为客户端提供读服务,其参与master选举的过程。
  • observer:oberser与follower功能几乎一样,不同的是,observer不参与master选举。其配置与follower或者leader不一样的地方在于其端口后面多了一个observer:server.1=192.168.20.101:2888:3888:observer,并且设置peerType=observer。++observer可以在不影响写性能的情况下提升集群的读性能++。

会话(session)

  session指的是客户端会话。在zk中,一个客户端连接指的是客户端和zk服务器之间的长连接。zk对外的默认端口是2181,客户端启动时,首先会与服务器建立一个TCP长连接,从第一次连接建立开始,客户端会话的生命周期也就开始了,通过这个长连接,客户端能够通过心跳检测和服务器端保持有效的会话,能够向zk服务器发送请求并接受响应,同时还能接收来自服务器的watch事件通知。SessionTimeout用来设置一个客户端会话的超时时间。当服务器压力太大、网络故障或者是客户端主动断开连接等各种原因,只要客户端在SessionTimeout规定的时间内能够重新连接上集群中任意一台服务器,那之前创建的会话仍然有效。

数据节点(ZNode)

  ZNode是zookeeper数据模型中的数据单元,zk将所有数据都存储在内存中,数据模型是一个树形结构(ZNode Tree),有斜杠(/)进行路径的分割,就是一个ZNode,例如:/root/children,其中root和children都是ZNode,root是children的父级。每个ZNode上都会保存自己的数据内容。

  ZNode可以分为持久节点、临时节点、持久顺序节点和临时顺序节点。

  • 持久节点,可以使用create命令来创建。持久节点一旦被创建,除非主动删除,否则这个ZNode将一直保存在zookeeper上。例如:create /root1 hello,这样就创建了一个root1的持久节点,其数据为hello。
  • 临时节点的声明周期是跟客户端会话绑定的,一旦客户端会话失效,那么这个客户端创建的所有临时节点都会被移除。例如:create -e /root2 world,这样就创建了一个root2的临时节点,其数据为world,当会话关闭后,这个节点就会被删除。
  • 持久顺序节点,和顺序节点的特性基本一致,唯一不同的是,每个父节点会为它的第一级子节点维护一份时序,记录每个子节点创建的先后顺序。基于这个特性,在创建子节点的时候,zk会自动为给定节点加上一个数字后缀,作为新的节点,数字后缀的范围是整型的最大值。例如:create -s /root3/hello hello,会输出:created /root3/hello0000000001。
  • 临时顺序节点,其包含了临时节点和顺序节点的特性。创建方式:create -s -e /root4/world world,创建后的节点为world00000000001。

节点属性

1
2
3
4
5
6
7
8
9
10
11
cZxid = 0x1313f3d4d9
ctime = Wed Aug 17 15:10:00 CST 2016
mZxid = 0x28b8c53eb5
mtime = Thu Aug 17 14:13:05 CST 2017
pZxid = 0x294c791a36
cversion = 13
dataVersion = 1
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 28
numChildren = 11
  • cZxid:znode创建的事务id。
  • ctime:znode创建的时间。
  • mZxid:znode被修改的事务id,每次对znode的修改都会更新该值。
  • mtime:znode更新的时间。
  • pZxid:与znode的子节点有关,表示其子节点最近一次创建或者删除的时间。注意只有子节点列表变更才会更新pZxid,子节点内容变更不会影响pZxid。
  • cversion:子节点版本号,当znode子节点有变化时,cversion的值就会增加一。
  • dataVersion:数据版本号,每次对节点进行set操作,dataVersion的值都会加一。
  • aclVersion:Access Control List(访问控制)的版本号。
  • ephemeralOwner:如果该节点为临时节点,ephemeralOwner的值表示与该节点绑定的session id。如果该节点不是临时节点,ephemeralOwner的值为0。
  • dataLength:节点数据的字节数。
  • numChildren:子节点数量。

  在zk中,能改变zk服务器状态的操作被称为事务操作。一般包括数据节点的创建、删除、数据内容更新和客户端会话创建与失效等操作。对每一个事务请求,zk都会为其分配一个全局唯一的事务id,用zxid表示,通常是一个64位的数字。每个zxid对应一次更新操作,从zxid中可以间接识别出zk处理这些事务操作请求的全局顺序。

watcher

  watcher是zk中一个很重要的特性。zk允许用户在指定节点上注册一些watcher,并且在一些特定事件触发的时候,zk服务端会将事件通知到感兴趣的客户端上去。该机制是zk实现分布式协调服务的重要特性。

ACL

  zk采用ACL(Access Control Lists)策略来进行权限控制。zk定义了5中权限:

  • CREATE:创建子节点的权限。
  • READ:获取节点数据和子节点列表的权限。
  • WRITE:更新节点数据的权限。
  • DELETE:删除子节点的权限。
  • ADMIN:设置节点ACL的权限。

注意:CREATE和DELETE都是针对子节点的权限控制。


功能场景

zk是一个高可用的分布式数据管理与协调框架。基于ZAB算法的实现,该框架能够很好的保证分布式环境中数据的一致性。

数据发布/订阅

  数据发布/订阅就是通常所说的配置中心,发布者将数据发布到zk节点上,供订阅者进行数据订阅,进而达到动态获取数据的目的,实现配置信息的集中式管理和动态更新。
  在系统开发中,经常会有这样的需求:系统需要使用一些通用的配置信息,例如服务器列表信息、数据库配置信息等。这些全局配置信息通常有以下三个特性。

  • 数据量通常比较小。
  • 数据内容在运行时动态变化。
  • 集群中各个服务器共享,配置一致。

  对于这样的全局配置信息就可以发布到zk上,上客户端去订阅该消息。发布\订阅系统一般有两种设计模式,分别是推(push)和拉(pull)模式。

  推:服务器端主动将数据更新发给所有订阅的客户端。拉:客户端主动发起请求来获取最新数据,通常客户端采用定时轮询拉取的方式。
  zk采用的是推拉结合的方式。如下:客户端想服务端注册自己需要关注的节点,一旦该节点的数据发生变更,那么服务器端就会向相应的客户端发送watcher事件通知,客户端收到这个消息后,需要主动到服务器端获取最新的数据(推拉结合)。

命名服务

  命名服务是分布式系统中比较常见的一种场景。在分布式系统中,使用命名服务,客户端应用能够根据指定名字来获取资源或者服务的地址、提供者等信息。被命名的实体通常可以是集群中的机器、提供的服务、远程对象等等。较为常见的就是一些分布式服务框架中的服务地址列表。通过在zk里创建顺序节点,能够很容易创建一个全局唯一的路径,这个路径就可以作为一个名字。

master选举

  master选举是zk最典型的应用场景。利用zk的强一致性,能够很好的保证在分布式高并发情况下节点的创建一定能够保证全局唯一性,即zk将保证客户端无法创建一个已经存在的znode。如果多个客户端请求创建一个临时节点,那么最终一定只有一个客户端请求能够创建成功。利用这个特性,能够在分布式环境中进行master选举了。

  成功创建该节点的客户端所在的机器就成为了Master。同时,其他没有成功创建该节点的客户端,都会在该节点上注册一个子节点变更的Watcher,用于监控当前Master机器是否存活,一旦发现当前的Master挂了,那么其他客户端将会重新进行Master选举。这样就实现了Master的动态选举。

分布式锁

  分布式锁是控制分布式系统之间同步访问共享资源的一种方式。分布式锁可以分为排他锁和共享锁两种。

  • 排他锁,简称X锁,又称写锁或者独占锁。如果事务T1对数据对象O1加上了排他锁,那么在整个加锁期间,只允许事务T1对O1进行读取和更新操作,其他任何事务都不能在对这个数据对象进行任何类型的操作,不能再对该对象加锁,直到T1释放了排他锁。排他锁的核心是如何保证当前只有一个事务获得锁,并且锁被释放后,所有正在等待获取锁的事务都能被通知到。
  • 共享锁,简称S锁,又称为读锁。如果事务T1对数据对象O1加上了共享锁,那么T1只能对O1进行读操作,其他事务也能同事对O1加共享锁(排他锁不行),直到O1上的所有共享锁都释放后O1才能被加排他锁。

  总结:++可以多个事务同时获得一个对象的共享锁,有共享锁就不能再加排他锁。++

负载均衡

分布式队列


参考:

  • 从PAXOS到ZOOKEEPER分布式一致性原理与实践

zookeeper伪分布式配置与遇到的问题

发表于 2017-03-12 | 分类于 笔记

  zookeeper提供了单机、分布式和伪分布式三种模式。

1
2
3
4
5
6
#zookeeper的默认配置文件zoo.cfg:
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/tmp/zookeeper
clientPort=2181

  条件有限,以伪分布式为例,将zookeeper文件夹复制三份,基本配置如下:

1
2
3
4
5
6
7
8
9
10
11
#第一个
tickTime=2000
initLimit=5
syncLimit=2
#我本机的目录
dataDir=D:/zookeeper/zookeeper-3.4.9-1/data
dataLogDir=D:/zookeeper/zookeeper-3.4.9-1/logs
clientPort=2181
server.1=localhost:7888:8888
server.2=localhost:7889:8889
server.3=localhost:7889:8890
1
2
3
4
5
6
7
8
9
10
11
#第二个
tickTime=2000
initLimit=5
syncLimit=2
#我本机的目录
dataDir=D:/zookeeper/zookeeper-3.4.9-2/data
dataLogDir=D:/zookeeper/zookeeper-3.4.9-2/logs
clientPort=2182
server.1=localhost:7888:8888
server.2=localhost:7889:8889
server.3=localhost:7889:8890
1
2
3
4
5
6
7
8
9
10
11
#第三个
tickTime=2000
initLimit=5
syncLimit=2
#我本机的目录
dataDir=D:/zookeeper/zookeeper-3.4.9-3/data
dataLogDir=D:/zookeeper/zookeeper-3.4.9-3/logs
clientPort=2183
server.1=localhost:7888:8888
server.2=localhost:7889:8889
server.3=localhost:7889:8890

  伪分布式和分布式配置的区别在于,伪分布式配置IP地址相同,端口号不同。

  其中,localhost:7889:8890,第一个端口号用来通信,第二个端口号用来进行leader选举。

  windows系统使用%zk_home%/bin目录下的zkServer.cmd启动zookeeper。由于在伪分布式下部署了三个节点,所以依次进入每个文件夹中,启动zookeeper。启动的时候可能会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2017-02-09 14:21:38,871 [myid:] - ERROR [main:QuorumPeerMain@85] - Invalid confi
g, exiting abnormally
org.apache.zookeeper.server.quorum.QuorumPeerConfig$ConfigException: Error proce
ssing D:\zookeeper\zookeeper-3.4.9-1\bin\..\conf\zoo.cfg
at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerC
onfig.java:144)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(Qu
orumPeerMain.java:101)
at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain
.java:78)
Caused by: java.lang.IllegalArgumentException: D:\zookeeper\zookeeper-3.4.9-1\da
ta\myid file is missing
at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parseProperties(Q
uorumPeerConfig.java:362)
at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerC
onfig.java:140)
... 2 more
Invalid config, exiting abnormally

  错误原因是没有找到myid这个文件(如11、12行),需要在配置文件dataDir指定的目录下面(我的是:D:\zookeeper\zookeeper-3.4.9-1\data)建立一个myid文件,内容为1。依次在剩下的两个文件夹中也建立一个myid的文件,内容分别为2和3。

  保存后,再次启动,发现又出现异常了,异常比较多,仅截取部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
2017-02-09 14:32:32,467 [myid:1] - WARN  [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:218
1:QuorumCnxManager@400] - Cannot open channel to 3 at election address localhost
/127.0.0.1:8890
java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(DualStackPlainSocketI
mpl.java:85)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.ja
va:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocket
Impl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java
:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:172)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(Quorum
CnxManager.java:381)
at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectAll(Quorum
CnxManager.java:426)
at org.apache.zookeeper.server.quorum.FastLeaderElection.lookForLeader(F
astLeaderElection.java:843)
at org.apache.zookeeper.server.quorum.QuorumPeer.run(QuorumPeer.java:822
)
2017-02-09 14:32:32,623 [myid:1] - INFO [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:218
1:QuorumPeer$QuorumServer@149] - Resolved hostname: localhost to address: localh
ost/127.0.0.1
2017-02-09 14:32:32,623 [myid:1] - INFO [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:218
1:FastLeaderElection@852] - Notification time out: 12800
2017-02-09 14:32:46,468 [myid:1] - WARN [QuorumPeer[myid=1]/0:0:0:0:0:0:0:0:218
1:QuorumCnxManager@400] - Cannot open channel to 2 at election address localhost
/127.0.0.1:8889

  这个异常其实可以忽略,仔细看2、3、31、32行打印出的信息就明白了。出现这个异常的原因是因为,现在只启动了一个zk节点,而在配置文件中却写了三个zk的地址,第一个zk节点还无法与剩下的两个节点进行通信,所以只要把三个zk节点都启动就没问题了。

http and https

发表于 2017-01-29 | 分类于 笔记
  • http是http协议运行在tcp之上。所有传输的内容都是明文,客户端和服务器端都无法验证对方的身份。
  • https是http运行在ssl/tls之上,ssl/tls运行在tcp之上。所有传输的内容都经过加密,加密采用对称加密,但对称加密的秘钥用服务器方的证书进行了非对称加密。此外客户端可以验证服务端的身份,如果配置了客户端验证,服务器方也可以验证客户端的身份。
  • https协议需要到ca申请证书,一般免费证书很少,需要交费。
  • http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
  • http和https使用的完全不同的连接方式,用的端口也不一样,前者是80,后者是443.
  • http的链接简单,是无状态的。
  • https协议有ssl+http协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

TCP

发表于 2017-01-28 | 分类于 笔记

三次握手

TCP如何保证可靠传输

  • 数据报校验
  • 超时重传机制
  • 应答机制
  • 对失序数据包重排序
  • TPC还能提供流量控制

三次握手

image

三次握手过程

  • 第一次握手:client将标志位SYN置为1,随机产生一个值seq=J,并将该数据包发送给server,client进入SYN_SENT状态,等待server确认。
  • 第二次握手:server收到数据包后由标志位SYN=1知道client请求连接,server将标志位SYN和ACK都置为1,ack=J+1,随机产生一个值sep=K,并将该数据包发送给client以确认连接请求,server进入SYN_RCVD状态。
  • 第三次握手:client收到确认后,检查ack是否为J+1,ACK是否为1,如果正确则连接建立成功,client和server进入established状态,完成三次握手,随后client和server之间可以开始传输数据了。

三次握手原因

  为了防止失效的链接请求报文突然又传到了服务端,因而产生错误。例如:“已失效的连接请求报文段”的产生在这样一种情况下:client发出的第一个连接请求报文并没有丢失,而是在某个网络节点长时间滞留,以致延误到连接释放以后的某个时间才到达server。本来这是一个早已失效的报文段。但server收到此失效的连接请求报文段后,就误认为是client再次发出的一个新的连接请求。于是就向client发出确认报文段,同意建立连接。假设不采用“三次握手”,那么只要server发出确认,新的连接就建立了。由于现在client并没有发出建立连接的请求,因此不会理睬server的确认,也不会向server发送数据。当server却以为新的运输连接已经建立,并一直等待client发来数据。这样,sever的很多资源就白白浪费了。采用三次握手可以防止上述现象的发生。例如刚才那种情况,client不会向server发出确认。server由于收不到确认,就知道client并没有要求建立连接。

  通过三次握手可以确认客户端和服务器端的收发功能是否正常。client确认了:自己发送、接收正常,对方发送、接收正常;server确认了:自己发送、接收正常,对方发送、接收正常。

DDos攻击

  client不断向sever发送请求,server会给每个请求创建一个连接,然后向client发送创建链接时的回复,然后进行等待客户端发送第三次握手数据包。DDos攻击就是这样的原理,第一个D表示的是分布式distribute。让server产生大量的等待client回复的连接,浪费系统资源,并且会使正常的请求进不来。

  简单说服务器发送连接请求,首先:

  1. 客户端向服务器端发送连接请求的数据包(第一次握手)。
  2. 服务器向客户端回复连接请求数据包(第二次握手)。然后服务器等待客户端发送tcp/ip连接的第三步数据包(第三次握手)。
  3. 如果客户端不向服务器端发送最后一个数据包,则服务器必须等待30s-2min才能将此连接关闭。当大量的请求只进行到了第二步,而不进行第三步,服务器又有大量资源在等待第三个数据包。最后就造成了DDos攻击。

预防ddos攻击(没有根治办法,除非不用tcp/ip)

  • 确保服务器的系统文件是最新版本,并及时更新系统补丁
  • 关闭不必要的服务
  • 限制同时打开SYN的半连接数目
  • 缩短SYN半连接的time out时间
  • 正确设置防火墙
  • 禁止对主机的非开放服务访问
  • 限制特点IP短地址的访问
  • 启用防火墙防DDos的属性
  • 严格限制对外开放的服务器的向外扫描
  • 运行端口映射程序或端口扫描程序,要认真检查特权端口和非特权端口。
  • 认真检查网络设备和主机/服务器系统的日志。只要日志出现漏洞或是时间变更,那这台机器就可能遭到了攻击。
  • 限制在防火墙外与网络文件共享,这样会给黑客截取系统文件的机会,主机的信息会暴露给黑客,无意给了对方入侵的机会。

四次挥手

image

四次挥手过程

  由于TCP连接时全双工的,因此,每个方向都必须要单独进行关闭,这一原则是当一方完成数据发送任务后,发送一个FIN来终止这一方向的连接,收到一个FIN只是意味着这一方向上没有数据流动了,即不会再收到数据了,但是在这个TCP连接上仍然能够发送数据,直到这一方向也发送了FIN。首先进行关闭的一方将执行主动关闭,而另一方则执行被动关闭。

  • 第一次挥手:client发送一个FIN,用来关闭client到server的数据发送,client进入FIN_WAIT_1状态。
  • 第二次挥手:server收到FIN后,发送一个ACK给client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号,server进入CLOSE_WAIT)。
  • 第三次挥手:server发送一个FIN,用来关闭server到client的数据传送,server进入LAST_ACK状态。
  • 第四次挥手:client收到FIN后,client进入TIME_WAIT状态,接着发送一个ACK给server,确认序号为收到序号+1,server进入CLOSED状态,完成四次挥手。

四次挥手的原因

  TCP协议是一种面向连接的、可靠的、基于字节流的运输层通信协议。TCP是全双工模式,这就意味着,当主机1发出FIN报文段时,只是表示主机1已经没有数据要发送了,主机1告诉主机2,它的数据已经全部发送完毕了;但是,这个时候主机1还是可以接受来自主机2的数据;当主机2返回ACK报文段时,表示它已经知道主机1没有数据发送了,但是主机2还是可以发送数据到主机1的;当主机2也发送了FIN报文段时,这个时候就表示主机2也没有数据要发送了,就会告诉主机1,我也没有数据要发送了,之后彼此就会愉快的中断这次TCP连接。

为什么建立连接是三次握手,而关闭连接却是四次挥手

  这是因为服务器端在LISTEN状态下,收到建立连接请求的SYN报文后,把ACK和SYN放在一个报文里发送给客户端。而关闭连接时,收到对方的FIN报文时,仅仅表示对方不在发送数据了但是还能接受数据,己方也未必全部数据都发送给对方了,所以己方可以立即close,也可以发送一些数据给对方后,再发送FIN报文给对方来表示同意现在关闭连接,因此,己方ACK和FIN一般都会分开发送。

TCP和UDP

  • UDP是无连接的,即发送数据之前不需要建立连接。
  • UDP使用尽最大努力交付,即不保证可靠交付,同时也不使用拥塞控制。
  • UDP是面向报文的,UDP没有拥塞控制,很合适多媒体通信的要求。
  • UDP支持一对一,一对多,多对一和多对多的交互通信。
  • UDP的首部开销小,只有8个字节。
  • TCP是面向连接的运输层协议。每一条TCP连接只能有两个端点,每一条TCP连接只能是点对点的(一对一)。
  • TCP提供可靠交付的服务。
  • TCP提供全双工通信。
  • TCP面向字节流。
  • 首部最低20个字节。

参考:

  • http://blog.csdn.net/renzhenhuai/article/details/12105457
  • http://blog.csdn.net/daguairen/article/details/52673194

HTTP长连接和短连接

发表于 2017-01-28 | 分类于 笔记

HTTP协议与TCP/IP协议的关系

  http长连接和短连接本质上是TCP长连接和短连接。http属于应用层协议,在传输层使用TCP协议,在网络层使用IP协议,并且顺序与发送顺序一致。TCP协议是可靠的、面向连接的。

HTTP协议是无状态

  无状态指的是对于事务没有处理记忆能力,服务器不知道客户端是什么状态。也就是说,在同一个web站点10分钟前打开一个页面和现在打开一个页面,它们之间是没有任何联系的。HTTP是一个无状态的面向连接的协议,无状态不代表HTTP不能保持TCP连接,更不能代表HTTP使用的UDP协议。

长连接、短连接

  在HTTP/1.0中默认使用的是短连接。也就是说,客户端每次和服务器进行http操作,就会建立一次连接,任务结束连接也就中断。比如,访问某个页面,页面中包含图片、css、js等多个资源,这样的话,会建立多次连接。
  而在HTTP/1.1中,默认使用了长连接,保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码 Connection:keep-alive。
  在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用户传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这条已经建立的连接。keep-alive不会永久保持连接,他有一个保持时间,可以在不同的服务器软件中设定。实现长连接需要客户端和服务器端都支持长连接。

长连接和短连接的优缺点

  长连接可以省去较多的TCP建立和关闭操作,减少浪费,节约时间。对于频繁请求资源的客户端适合使用长连接。在长连接的应用场景下,client端一般不会主动关闭连接,当client与server之间的连接一直不关闭,随着客户端连接越来越多,server会保持过多连接。这时候server端需要采取一些策略,如关闭一些长时间没有请求发生的连接,这样可以避免一些恶意连接导致server端服务受损;如果条件允许则可以限制每个客户端的最大长连接数,这样可以完全避免恶意的客户端拖垮整体后端服务。

  短连接对于服务器来说管理较为简单,存在的连接都是有用的连接,不需要额外的控制手段。但如果客户请求频繁,将在TCP的建立和关闭操作上浪费较多时间和带宽。

  短连接的操作步骤是:

建立连接——数据传输——关闭连接…建立连接——数据传输——关闭连接

  长连接的操作步骤是:

建立连接——数据传输…(保持连接)…数据传输——关闭连接


参考

  • http://www.cnblogs.com/cswuyg/p/3653263.html
  • https://www.cnblogs.com/gotodsp/p/6366163.html
  • http://www.cnblogs.com/0201zcr/p/4694945.html

dubbo

发表于 2017-01-06 | 分类于 Dubbo

dubbo的基本需求

  • 动态的注册和发现服务,实现软负载,降低对F5硬件负载的依赖。
  • 理清服务间的依赖关系。
  • 统计每个服务的调用量、相应时间。可以动态调整每个机器的权重。

dubbo的架构

image
节点 | 角色说明
—|—
provider | 暴露服务的服务提供方
consumer | 调用远程服务的服务消费方
registry | 服务注册于发现的注册中心
Monitor | 统计服务的调用次数和调用时间的监控中心
Container| 服务运行容器

调用关系说明

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,在选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。

dubbo架构具有以下几个特点:分别是连通性、健壮性、伸缩性以及未来架构的升级性。

连通性

  • 注册中心负责服务地址的注册与查找,相当于目录服务,服务提供者和消费者只在启动时与注册中心交互,注册中心不转发请求,压力较小。
  • 监控中心负责统计各个服务的调用次数,调用时间等,统计先在内存汇总后每分钟一次发送到监控中心服务器,并以报表展示。
  • 服务提供者向注册中心注册其提供的服务,并汇报调用时间到监控中心,此时间不包含网络开销。
  • 服务消费者向注册中心获取服务提供者地址列表,并根据负载算法之间调用提供者,同时汇报调用时间到监控中心,此时间包含网络开销。
  • 注册中心,服务提供者,服务消费者三者之间均为长连接,监控中心除外。
  • 注册中心通过长连接感知服务提供者的存在,服务提供者宕机,注册中心将立即推送事件通知消费者。
  • 注册中心和监控中心全部宕机,不影响已运行的提供者和消费者,消费者在本地缓存了提供者列表。
  • 注册中心和监控中心都是可选的,服务消费者可以直连服务提供者。

健壮性

  • 监控中心宕掉不影响使用,只是丢失部分采样数据。
  • 数据库宕掉后,注册中心仍能通过缓存提供服务列表查询,但不能注册新服务。
  • 注册中心对等集群,任意一台宕掉后,将自动切换到另一台。
  • 注册中心全部宕掉后,服务提供者和服务消费者仍能通过本地缓存通讯。
  • 服务提供者无状态,任意一台宕掉后,不影响使用。
  • 服务提供者全部宕掉后,服务消费者应有将无法使用,并无限次重连等待服务提供者恢复。

伸缩性

  • 注册中心为对等集群,可动态增加机器部署实例,所有客户端将自动发现新的注册中心。
  • 服务提供者无状态,可动态增加机器部署实例,注册中心将推送新的服务提供者信息给消费者。

升级性

  当服务集群规模进一步扩大,带动IT治理结构进一步升级,需要实现动态部署,进行流动计算,现有分布式服务架构不会带来阻力。下图是未来可能的一种架构:

image

节点 说明
Deployer 自动部署服务的本地代理
Repository 仓库用于存储服务应用发布包
Scheduler 调度中心基于服务压力自动增减服务提供者
Admin 统一管理控制台
Registry 服务注册与发现的注册中心
Monitor 统计服务的调用次数和调用压力的监控中心

基于spring的配置

1.本地配置很简单,和使用本地的service类,没有区别。

1
2
3
4
<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />
<bean id=“xxxAction” class=“com.xxx.XxxAction”>
<property name=“xxxService” ref=“xxxService” />
</bean>

2.远程配置需要将本地的配置拆分成两份,将服务定义部分放在服务提供方remote-provider.xml,将服务引用部分放在服务消费方remote-consumer.xml;并在提供方增加暴露服务配置,在消费方增加引用服务配置。

remote-provider.xml:

1
2
3
4
<!-- 和本地服务一样实现远程服务;加上url="ip:port",相当于直连,不经过注册中心,一般本地调试的时候,会设置成localhost -->
<bean id=“xxxService” class=“com.xxx.XxxServiceImpl” />
<!-- 增加暴露远程服务配置 -->
<dubbo:service interface=“com.xxx.XxxService” ref=“xxxService” />

remote-consumer.xml:

1
2
3
4
5
6
<!-- 增加引用远程服务配置 -->
<dubbo:reference id=“xxxService” interface=“com.xxx.XxxService” />
<!-- 和本地服务一样使用远程服务 -->
<bean id=“xxxAction” class=“com.xxx.XxxAction”>
<property name=“xxxService” ref=“xxxService” />
</bean>

配置方式

xml配置

标签 用途 解释
服务配置 用于暴露一个服务,定义服务的元信息,一个服务可以用多个协议暴露,一个服务也可以注册到多个注册中心
引用配置 用于创建一个远程服务代理,一个引用可以指向多个注册中心
协议配置 用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受
应用配置 用于配置当前的应用信息,不管该应用是提供者还是消费者
模块配置 用于配置当前模块信息,可选
注册中心配置 用于配置连接注册中心相关信息
监控中心配置 用于配置连接监控中心相关信息,可选
提供方配置 当ProtocolConfig和ServerConfig某属性没有配置时,采用此缺省值,可选
消费方配置 当ReferenceConfig某属性没有配置时,采用此缺省值,可选
方法配置 用于ServiceConfig和ReferenceConfig指定方法级的配置信息
参数配置 用于指定方法参数配置

配置覆盖关系

  • 方法级优先,接口级次之,全局配置再次之。
  • 如果级别一样,则消费方优先,提供方次之。

  服务提供方的配置,通过URL经过注册中心传递给消费方。

  下图以timeout参数为例,展示了参数配置的传递过程:

image

属性配置

  如果公共配置很简单,没有多注册中心,多协议等情况,或者想多个 Spring 容器想共享配置,可以使用 dubbo.properties 作为缺省配置。

  Dubbo 将自动加载 classpath 根目录下的 dubbo.properties,可以通过JVM启动参数 -Ddubbo.properties.file=xxx.properties 改变缺省配置位置。

API配置

略

注解配置

略

==实际开发中,使用xml配置居多,至少我们公司是这样。==

dubbo负载均衡策略

Random LoadBalance

  • 随机,按权重设置随机概率。
  • 在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。

RoundRobin LoadBalance

  • 轮循,按公约后的权重设置轮循比率。
  • 存在慢的提供者累积请求的问题,比如:第二台机器很慢,但没挂,当请求调到第二台时就卡在那里,久而久之,所有请求都卡在调第二台上。

LeastActive LoadBalance

  • 最少活跃调用数,相同活跃数的随机,活跃数指调用前后计数差。
  • 使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大。

ConsistentHash LoadBalance

  • 一致性hash,相同参数的请求总是发送到同一提供者。
  • 当某一台提供者挂时,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者,不会引起剧烈变动。
123
dreamlate

dreamlate

for the dream

23 日志
6 分类
39 标签
© 2018 dreamlate
由 Hexo 强力驱动
主题 - NexT.Pisces