Jgroups的传输协议有UDP、TCP 等,在这些传输协议上,为可靠性提供了UNICAST、UNICAST2、UNICAST3、pbcast.NAKACK、pbcast.NAKACK2五种自定义协议,其中前三种用于点对点传输,后两种用于多播。下边来看下其如何做到可靠性保证:
1. UNICAST: 主动重发、逐个确认,有如下3个步骤:
A B
1): |-------------send msg------------->|
2): |<----------- ack-----------------------|
3): |-------------retransmit------------->|
假设是节点A向B节点发送消息
1): A向B发送消息,同时在内存中保存消息(用于重发)。
2): 如果B收到消息会立刻返回一个确认ack,A收到确认后从内存中删除相应的信息。
3): 在发送方A,会启动一个定时器定时检测有多少消息已被确认,没被确认的消息要逐个重发。
这种方式的优缺点为:(+:优点 -: 缺点)
+. 占用内存小,因为正常情况下,每条消息发送之后会立刻得到确认,然后立刻被丢弃。
+. 简单。在传输过程丢失消息或者确认消息丢失,一定周期A会重发消息。
-. 频繁的通信,每一条消息对应一条确认消息。
-. 没有必要的消息重发。试想,如果因为网络延迟A没及时收到确认消息或者确认消息根本就丢失了,则A就重发消息,其实这是没必要的。
1. UNICAST2: 被动重发,主要是为了解决UNICAST的两个缺点,有如下3个步骤:
A B
1): |-------------send msg------------>|
2): |<---interval need retransmit----|
3): |------------ retransmit------------>|
4): |<--------interval stable msg-----|
假设是节点A向B节点发送消息
1): A向B发送消息,同时在内存中保存消息(用于重发)。
2): B收到消息不会返回确认消息,而是启动定时线程,定时检测有消息丢失就向A请求重发。
3): A收到重发请求,向B重发丢失的消息。
4): B定时计算收到消息总量大小到达一定量后,向A发送清理B已经收到的消息的请求,A收到消息则删除内存中B已经收到的消息。
这种方式的优缺点为:(+:优点 -: 缺点):
+. 减少没必要的消息确认。
+. 消息传输速度快。
-. 第一条和最后一条消息有可能没有可靠性保证。
试想,如果A向B发送的第一条消息丢失了,直到B收到后续的消息才会检测到第一条消息丢失,才要求A重发,如果A只发送这一条消息呢? 类似的,如果A发送[1...5] 条消息,而消息5丢失,B只收到[1....4]消息,那么B无法要求A重发消息5,因为其不知道A到底发送了消息没有,只有B收到后续的消息才能检测到消息5丢失,才会要求A重发;或者直到B向A发送清理资源的消息后,A才重发消息5,而这过程很长。
所以我们要对第一条消息和最后一条消息来进行特殊处理。对于第一条消息,接收方收到后一定要立刻返回确认消息,在发送方如果没有收到第一条消息的确认消息,则会定时重发第一条消息,如下图。
A B
1): |-------------send msg------------->|
2): |<-----------ack first msg----------|
3): |-------------resend first msg---->|
4): |<------------need retransmit------|
5): |------------retransmit-------------->|
6): |<-------interval stable msg-------|
对于最后一条消息的情况,接收方每次收到消息,在批量删除已被正确分发的消息后,向发送方发出一条清除资源的消息,发送方收到这条消息后重发丢失的消息。如下图:
A B
1): |-------------send msg------------->|
2): |<-----------ack first msg----------|
3): |-------------resend first msg---->|
4): |<------------stable msg------------|
5): |<------------need retransmit------|
6): |------------retransmit miss msg->|
7): |<-------interval stable msg-------|
因为这个特殊处理,每次收到一条消息就会立刻发送一条清除资源消息,这么看来,和UNICAST中每次收到消息就返回确认消息,并没有减少网络通信?! 其实,还是有区别的,这里,在时间T0,如果收到5条消息,只发送一条清除资源消息。
总体上看,UNICAST2并没有比UNICAST有太多的优势,反倒复杂很多。 如果把UNICAST和UNICAST2结合起来,会如何? UNICAST3由此应运而生.
1. UNICAST: UNICAST和UNICAST2的结合,目的是提供可靠性保证同时减少网络通信和资源。
A B
1): |-------------send msg----------------------->|
2): |<-----------interval ack-----------------------|
3): |<-----------interval need retransmit--------|
4): |--------------retransmit miss msg---------->|
5): |<-----------interval retransmit last msg---|
假设是节点A向B节点发送消息
1): A向B发送消息,同时在内存中保存消息(用于重发)。
2): B收到消息不是立刻返回确认消息ack,而是,定时向A发送确认,而且只确认最新的正确分发的消息
3): B启动一个定时线程,定时检测有消息丢失就向A请求重发。
4): A收到重发请求,向B重发丢失的消息。
5): 在发送方A,会启动一个定时器定时检测有多少消息已被确认,有消息没被确认则重发最后的那条消息(不像UNICAST重发所有消息)。
所以,因为接收方周期且经过合并的发送确认消息,比UNICAST减少了很多网络通信。 而且,在发送方定时检测丢失消息,只重发最后的消息,减少没必要的消息重发,而且解决了UNICAST2的第一条及最后一条消息丢失的问题。