[erlang-questions] question re. message delivery
Miles Fidelman
mfidelman@REDACTED
Wed Sep 27 17:34:14 CEST 2017
On 9/27/17 4:08 AM, Joe Armstrong wrote:
> On Wed, Sep 27, 2017 at 2:16 AM, Miles Fidelman
> <mfidelman@REDACTED> wrote:
>> Hi Joe,
>>
>> Hmmm....
>>
>> Joe Armstrong wrote:
>>
>> What I said was "message passing is assumed to be reliable"
>>
>>
>> The key word here is *assumed* my assumption is that if I open a TCP socket
>> and send it five messages numbered 1 to 5 then If I successfully read
>> message
>> 5 and have seen no error indicators then I can *assume* that messages 1 to
>> 4 also arrived in order.
>>
>>
>> Well yes, but with TCP one has sequence numbers, buffering, and
>> retransmission - and GUARANTEES, by design, that if you (say a socket
>> connection) receive packet 5, then you've also received packets 1-4, in
>> order.
>>
>> My understanding is that Erlang does NOT make that guarantee. As stated:
>>
>> - message delivery is assumed to be UNRELIABLE
> That was the short version - Here's the long version.
>
> Actually there is no such thing as "delivering a message" in Erlang.
>
> What "delivering a message means" is "putting the message in the
> mailbox of the receiver and scheduling the process for execution"
Understood. What's less clear are the details of exactly how the
message is copied, and the step by step flow of control. There are a
lot of details spelled out (in the BEAM book) about how this happens on
a single node, but no details at all about how messages are sent between
nodes.
>
> So all sorts of things can go wrong - the message is put in the mailbox
> but an earlier message in the mailbox causes the process to crash
> before the process reaches your message.
Exactly. I'm trying to understand the implementation details. (Call it
an itch I feel compelled to scratch, from a systems engineer who's
worked on a lot of distributed systems, and at one time was involved in
designing & implementing network protocols.)
>
> There *is* a guarantee that if create a link to a process and the process
> dies you get sent a message.
>
> So we can can make the statement "in the absence of errors message passing
> order is preserved"
But, is that true between nodes? There are lots of ways to implement
message passing that don't preserve ordering. Hence my interest in details.
One can imagine all kinds of mechanisms, and failure mode, including
ones where both the sending and receiving processes continue to run just
fine.
- on a single node, sending a message is implemented by spawning a
process that copies the message from the sender's memory space to the
receiver's - easy enough for such a process to die and lose a message,
or for scheduling to lead messages to be delivered out of order
- across nodes, even if TCP is used to move messages, a connection can
fail and be restarted - losing data in the process - again both
processes remain alive and well
The BEAM book details how a message is moved between processes on the
same node (but doesn't actually about who's doing the moving). There's
no description about how messages are moved between nodes. Again, my
interest in details.
>
> What does this mean? If you are linked to a message receiver and see no
> error message then it is alive. If you send a sequences of messages
> to the receiver and see no error messages then the messages have been
> placed in the mailbox in order. This is guarantee (if the code is correct).
Assumes facts not in evidence. Depending on implementation, the
"postman" could die (to use the postal mail analogy).
>
> Note that there is no guarantee that the process will ever read the mailbox.
>
> It's like the postal service - the letters get put in the mailbox but
> there's no guarantee they get taken out, but you get to know if the
> owner of the mailbox dies.
Not a really great analogy. First off, you don't know if the owner of
the mailbox dies (I'm dealing with that right now, still receiving mail
for a dead relative, forwarded from an older address, courtesy of the
post office). Beyond that, you never if a piece of mail falls behind a
piece of sorting equipment. And.. there are plenty of cases of lost
mail showing up days, or even years later.
Now, some forms of mail delivery come with a tracking number - so you
can determine where a piece of mail is. And you can send mail with a
return receipt, and resend if the receipt isn't received in a timely
fashion (which adds the potential for duplicate delivery if the mail is
just delayed, or the receipt gets lost).
>
> The bit that should be reliable is putting the messages in the mailbox in order
> if nothing has crashed (we assume this to be correctly coded)
Which mailbox? The sender's outbox (or the local postbox) - agreed.
The receiver's inbox - now that's the question on the table.
>
> The bit that is unreliable is the guarantee that the message is removed
> from the mailbox and correctly processed.
Also unreliable:
- that a message gets from the sender's outbox to the receiver's inbox
- that messages get placed in the receiver's inbox in order of transmission
>
> I'm not sure where you quoted me from - but there should be some small
> print nearby with the an extended explanation.
The quotes are from your thesis. There is no extended explanation that
I could find, other than that the guarantee of order is a "design decision."
>
> The world "unreliable" means different things to different people.
> TCP might well be reliable by design - but is it correctly implemented?
> I have seen many good designs with bad implementations.
Sure, so let's stick with two very specific uses of the word:
i. the protocol sense: UDP is defined as an unreliable service, TCP is
defined as a reliable one
ii. failure to execute a function, or provide a service, as specified
For the purposes of this discussion, I'm trying to get very clear about
what, exactly is specified, how it's implemented, and what failure modes
might be there.
>
> I've helped design fault-tolerant systems for years - so I'm a trust
> as little as
> possible sort of person. Assume things will crash and clean up later.
Well... me too. But with the focus of how to build distributed systems
that continue to function in the face of "challenged" networks. So my
focus tends to be on what kinds of things might fail, how to detect
those failures, and how to clean up afterwards.
(Side note: I first discovered Erlang while working on distributed
simulation systems, and the protocols used for updating distributed state.)
>
> I was told years ago not to trust processes, a wise man said "if you
> want to know
> if a process has done something, get it to send you a reply message,
> if you don't get the reply message then you can't assume anything about
> the receiving process. So generating unique tags which we send in
> round trips become important ...
Absolutely!
>
> Aside: Telecoms protocols make great use of tags, and timeouts
> you send a request with a tag, wait a relative long time (the timeout) -
> much longer than the operation should take. Then on a timeout
> assume the worse - crash everything and restart.
Well, I assume you mean telephony when you say "telecoms" - in the data
network world we use sequence numbers, and include those numbers in
acknowledgement messages. On the sending end, you resend if you don't
receive and ACK within a timeout window; on the receiving end, you use
sequence numbers to order delivery - and sometimes you request a
retransmission if you detect a missing sequence number.
Where it gets trickier is if a connection (more accurately, an
"association") drops. Things get sort of interesting if you want to run
a reliable telnet or ssh connection from a cell phone in a moving
vehicle - your IP address tends to change as you roam from tower to
tower, so you need something "above" TCP to re-establish connections,
and retransmit packets lost in transit. (Well, my personal experience
is with tactical mesh networks. Cellular data protocols are somewhat
odder than basic TCP/IP).
>
> Works very well in practise - theory wise it's very dodgy - millions of lines
> of code doing this stuff is way to complex to prove anything about.
>
> Since I basically don't trust any of the underlying layers - you have
> to ask what to
> I trust.
>
> Well nothing really - but I have higher levels of trust for some
> things than other.
>
> Round trip confirmations including SHA1 checksums seems pretty good
> to me.
>
> If I say to a server "get me a file called 'foo'" and get something back
> It may of may not be correct.
>
> If I say "get me some data that has the sha1 checksum 34ad34..."
> and get some data back I can check the data and see if it has the correct
> checksum. I don't even need secure sockets. I do need a secure way to
> know the checksum - but that is an entirely different problem.
>
> This boils down to system design - in the latter case I need to place no
> trust in the layers (I need to trust SHA1 so it's not absolute)
Which brings me back to my interest in details of Erlang's message
passing implementation (well actually, the design - let's stay away from
the question of correct implementation).
Cheers,
Miles
--
In theory, there is no difference between theory and practice.
In practice, there is. .... Yogi Berra
More information about the erlang-questions
mailing list