Moleculer: Protocol discussions for moleculer-go

Created on 25 Sep 2017  Â·  45Comments  Â·  Source: moleculerjs/moleculer

hi, I'm trying to implement moleculer-go version library .
I'm a little confused by HEARTBEAT and PING/PONG. Since HEARTBEAT already take 5s/15s mark disconnect node as "broken", why still need PING/PONG ?

Is PING/PONG used for upper application layer , HEARTBEAT is designed for internal usage ?

Question

Most helpful comment

take a look
moleculer-go

just can work

All 45 comments

Yes, HEARTBEAT is an internal solution to detect the broken nodes. The PING/PONG is a public solution ˙broker.sendPing(nodeID)`, to detect the network latency & system time lag between remote nodes.

Btw, moleculer-go implementation would be very good :+1: Thanks!

@icebob some mismatch on PROTOCOL doc, please fix it

Subscriptions:
Request | MOL.REQUEST.<nodeID>
Response | MOL.RESPONSE.<nodeID>

but real request topic name is :

MOL.REQ.node-2
MOL.REQB.<action> (if built-in balancer is disabled)
MOL-dev.REQ.node-2 (if namespace is dev)

Thanks. Fixed.

@icebob also, some type is wrong in REQUEST:

params | string | ✔ | JSON encoded ctx.params object.
-- | -- | -- | --
meta | string | ✔ | JSON encoded ctx.meta object.


they are object, not string, string start and end with ". I write all go struct based on PROTOCOL, but it parse REQUEST body error.

So far, DISCOVER, INFO, HEARTBEAT works

@icebob BTW, is subscribe this OK?

var topic = "MOL.REQB." + service.ServiceName + ".>"

No, because the NATS balanced won't work properly. You should use the full action name.

REQUEST Type: yes, it changed in v2. If the serializer is JSONSerializer, the params & meta doesn't encoded to JSON string, just in ProtoBuf & Avro serializers.

when will use MOL.REQB. ? I test with repl, it send REQUEST by MOL.REQ.nodeID
can i not subscribe MOL.REQB. ?

REQB and EVENTB is a new stuff. If you set disableBalancer: true in broker options, the broker will use the transporter (NATS, RabbitMQ) internal balancer. It means, broker doesn't select node for REQ & EVENT, just sends the message to the transporter server, and it will select a target node. In this case the broker sends the packet with the REQB & EVENTB topic name.

right now, I just don't support REQB and EVENTB to keep implement simple.
currently , moleculer-go only support NATS

Also, the RESPONSE data field should be json not string.
Because the go language is static , so i can't define a filed both support string and json

OK, now REQUEST and reply works.
When it basic works with all command , i will publish it to github

Cool! :+1:

take a look
moleculer-go

just can work

Great! :tada:

@icebob
About the EVENTS

1,Should i implement it by NATS Queueing or internal self balance algorithm ?

2,Do i need support BalancedEvent (EVENTB) ?

In NodeJS the EVENT works with the broker self balancing. The EVENTB uses the NATS Queueing balancer. In ServiceBroker has a disableBalancer what switches it. If true all request sends with REQB & events with EVENTB.

@icebob

Thanks , so at least i need support direct event (broker self balancing).

BTW, i run a basic benchmark . Go version handle REQUEST is much faster .
On my device i7 4790K, Ubuntu 14.04, nodejs is about 7000 r/s, go is about 35000 r/s. And memory usage is only 10~25MB.

The result proved my guess that go is better in I/O intensive scenarios, 'nodejs' is better for logic handle. I'm plan to implement a websocket frontend server that can handle 100000+ users on a single process.

Cool result! Yes, go is much faster, I know. Did you try that a NodeJS service calls a Go service?

@icebob yes , that is how i test Go service.

I'm plan to write some nodejs services to handle business logic, some go services to handle frontend client connection and simple but performance need task.

moleculer will be used as internal RPC method.

Awesome!

Sorry, actually testing target is one Nodejs service and one Go service.
Using 7 nodejs moleculer client broker.call services to do the benchmark testing.

@icebob seems the PROTOCOL on REQUEST still has some error:

params | string | ✔ | ctx.params object. (*)
meta | string | ✔ | ctx.meta object. (*)

should be type: object

Thanks. Fixed.

@icebob
is group stand for serviceName in MOL.EVENTB. ?

eg:

service aaa and bbb listen event user.create, it should sub NATS:
SUB MOL.EVENTB.aaa.> aaa aaa-sid
SUB MOL.EVENTB.bbb.> bbb bbb-sid

the emit sender will send event with topic twice:
MOL.EVENTB.aaa.user.create
MOL.EVENTB.bbb.user.create

What is the question?

@icebob
BTW, i used to implement a library like moleculer, named nats-node-rpc and nats-go-rpc, one year ago.
It just works, but lack of document and protocol.

I found that nodejs benchmark is much faster. I don't know if the testing is different or others. later i will compare it with molecular.

@icebob

What is the question?

MOL.EVENTB.<group>.<event> (if built-in balancer is disabled) in PROTOCOL, what group value should i use ? I guess it should be service's name which listen the event.

@icebob need come home from work, talk to you tomorrow .

Yes, the group name comes from service name. Ok!

@icebob
could you make the PROTOCOL more specific about the time value?

timeout | double | ✔ | Request timeout (distributed).
time | int64 | ✔ | Time of sent.
arrived | int64 | ✔ | Timestamp of arrived.

JavaScript's time value often use millisecond, but Go often use Unix-> Second and UnixNano->Nanosecond

@icebob

moleculer nodejs repl process _crash_ if the responser send "success":false but error is null. I know that the "success":false value is wrong, but it should not lead the sender process crash. Need some protection when handle packet.

Any NATS packet should not crash at moleculer framework layer

(BTW, now I change it to use moleculer-go to set Success and Error value, now the bug should not happen. )

NATS _onRequest sendData : {"ver":"2","sender":"moleculer-go-demo","id":"e49a9fde-dddb-40fc-ba63-cc441a18c338","success":false,"data":{"a":111,"b":"abc","c":true},"error":null}
let err = new Error(packet.error.message + ` (NodeID: ${packet.sender})`);

TypeError: Cannot read property 'message' of null
    at Transit._responseHandler (/home/projects/rt-app-framework/server/microservice/node_modules/moleculer/src/transit.js:335:36)

@icebob

I already support most of commands on PROTOCOL except MOL.REQB and MOL.EVENTB.
Do i must support $node.xxx ?
Right now i just return empty Response for those $node.xxx command .

could you make the PROTOCOL more specific about the time value?

I updated in docs.

moleculer nodejs repl process crash if the responser send "success":false but error is null.

Thanks, I will test & fix it.

Do i must support $node.xxx ?

Don't must. It's an option. But you should document in README which function is supported and which is not.

Thanks!

@icebob

timeout | double | ✔ | Request timeout (distributed) in milliseconds.

should be int64

timeout | int64| ✔ | Request timeout (distributed) in milliseconds.

No, it's double because can be floating number.

@icebob

Don't must. It's an option. But you should document in README which function is supported and which is not.

Yes, I wrote it in README. Also i upload a benchmark of Go<-> Go call performance .

Cool! Yesterday I tested and I could call Go service from Moleculer CLI :+1:

@icebob Why double in REQUEST , but int64 in PING and PONG ? They are milliseconds , looks the same for me.

In ping, pong it is a timestamp like 1506603135255
The timeout is a limit value, e.g 280,6ms

@icebob
How to get double value (like 280.6ms) for milliseconds in Nodejs? My experience is that most JavaScript handle time value are seconds and milliseconds as integer. Will you use process.hrtime to get nanoseconds then transfer to double milliseconds value ?

BTW , The Go default basic TIME value is int64 for nanoseconds

// UnixNano returns t as a Unix time, the number of nanoseconds elapsed
// since January 1, 1970 UTC. The result is undefined if the Unix time
// in nanoseconds cannot be represented by an int64 (a date before the year
// 1678 or after 2262). Note that this means the result of calling UnixNano
// on the zero Time is undefined.
func (t Time) UnixNano() int64 {
    return (t.unixSec())*1e9 + int64(t.nsec())
}

I'm using milliseconds every place, but measure the elapsed time with process.hrtime, so the remaining time can be floating

@icebob I don't get it.

timeout | double | ✔ | Request timeout (distributed) in milliseconds.

Do we need any kind of REQUEST's timeout time that precise ? I saw your default value is "timeout":5000. 5s timeout seems reasonable. But do we need "timeout":5000.001 ? In which scenario need that?

I think yes. The timeout has no default value, just I use 5s in examples.
If you make a call which return from memory cache, the elapsed time will be microseconds.
The distributed timeout means every call in a chain decrement the original timeout.

Example:
make a broker.call("test.a", null, { timeout: 500 });
test.a call test.b. test.b call test.c
test.a does something at 34,8ms and call test.b The test.b timeout will be 465,2. test.b does sg at 188,6, so test.c timeout will be only 276,6...etc

@icebob I got it. I changed it to float64 now

Was this page helpful?
0 / 5 - 0 ratings

Related issues

molobala picture molobala  Â·  3Comments

maitrucquynhq111 picture maitrucquynhq111  Â·  3Comments

demetriusnunes picture demetriusnunes  Â·  5Comments

DeividasJackus picture DeividasJackus  Â·  4Comments

abdavid picture abdavid  Â·  4Comments