roletalk
v1.1.3
Published
WebSocket-based NodeJS framework for peer-to-peer communication between microservices
Downloads
12
Maintainers
Readme
Roletalk: Microservice framework for Node.js
Roletalk is peer-to-peer communication framework for microservices; asynchronous and event-driven. Developed in honor of scalability, simplicity and efficiency.
Essentially, it is peer-to-service framework, which allows you to create multiple services (roles) on single peer and communicate to them with ease.
Roletalk internally uses Websocket for data transferring as TCP framing tool with minimal network overhead. Currently, there is a corresponding wire-compatible GO framework.
Table of Contents
Installation
$ npm install roletalk
API
API referrence is available HERE, generated with Typedoc
Use case
Choose roletalk if you need to build brokerless architecture. Such an approach brings some advantages: minimal RTT (round-trip time), less network transferring, no SPOF (single point of failure). In some scenarios, broker can be a bottleneck also.
Roletalk lets you implement flexible communication patterns:
- Publish-Subscribe,
- Remote Procedure Call (RPC),
- Event (single message with optional payload),
- Pipeline (sequential distributed data processing),
- Bus (many-to-many communication),
- Survey (request-reply to multiple peers).
Features
• Client as service. No matter who establishes a connection. Both listener and dialer of a socket are services. It allows you to deploy services not exposing them to the Internet or behind private networks etc. Of course, such instances should connect to listeners they have network access to.
• Automatic service-recognition. Just connect peers and each of them will know about each other's roles (services), IDs, names and meta info. If a peer's role gets disabled or enabled each connected peer immediately gets informed and rebuilds its internal state.
• Redundant connections support. There could be multiple connections between two peers. All communication is load-balanced between them. With auto-reconnection, this can be useful to keep connected two peers in case when one peer's IP address is changed.
• Binary streams. Transfer large or unknown amounts of data via streams.
• Round-robin client-side load balancing between units implementing a role (service);
• No internal heavy message conversions (json/xml serialization/parsing). Just binary to utf-8/int and vice-versa.
• Optional TLS on transport layer.
• Scalable and simple in-built authentication: each peer can have zero or multiple ID: KEY combinations.
Concept
Structure
Roletalk concept consists of:
- Peer - local node in your peer-to-peer architecture. Peer can have Units, Roles and Destinations.
- Unit - remote node connected to the Peer
- Connection - communication link between Peer and Unit. Each Unit can have one or more connections. If there are redundant connections, communication is load-balanced between them: checking which of them is not busy or choosing random one if no vacant one found. In case of last connection gets aborted Unit gets closed and removed from the Peer
- Role - service registered on Peer. Role can have handlers for each communication type. Role can be active or inactive. When role changes its state all connected units get informed to rebuild their state
- Destination - role registered on Units. Destination includes all connected units which serve corresponding role. If last Unit gets disconnected or disables the role, Destinations gets closed.
All communications is performed via Destinations's methods and is load-balanced among its Units unless Unit is explicitly specified. Unit is chosen for each message / request / stream.
Communication
Roletalk defines three types of communication:
- Message - one-way act of communication. Should be used when no delivery acknowledgement is needed. Successfully sent message means that it has been written to underlying socket
- Request - request in common meaning. Request can only be rejected or replied. Returns error when Unit rejects it, timeout exceeds or Unit disconnects after request was sent.
- Stream - one-way stream of binary data. Streams can be Readable and Writable. If Peer calls Readable (
Destination.Readable()
) then Units handle Writable (Role.OnWritable()
) and vice-versa. Stream sessions begin with Request. After Unit replied for request, data is transferred over connection used for the reply. If connection aborts stream destroys.
Incoming messages are wrapped in Context - object with payload and meta info for all types of incoming messages (message, request, request for stream).
All communication is performed with two basic properties: Role and Event (name of action. Some synonyms in other frameworks: method, path, action) to identify which handler to call. When Unit gets message it forwards it to corresponding role or rejects it if such role isn't specified on the Peer. If role has no handlers for event it rejects it, otherwise call handlers.
Data types
Roletalk uses six data types:
- Binary -
Buffer
- Null -
null
- Bool -
boolean
- String -
string
- Number -
number
- Object -
Object
All communication (except stream sessions) can use data of any type. Type of data should be chosen on stage of designing microservice specification or retrieved by calling Context methods.
Acquaintance
One aditional feature of roletalk is acquaintance. It is could be considered as redunant but it nicely fits the use case of frameworks.
The process of it is simple. You have listener PEER_A which is connected to listener PEER_B. After some PEER_C has connected to PEER_A, PEER_A will send to PEER_C info {ID, ADDRESS, ROLES} of PEER_A. If PEER_C is FRIENDLY, has one or more destination from received ROLES and PEER_C is not connected to peer with provided ID it will start connection to the ADDRESS
Acquantance is enabled by default, but you can set Friendly option to FALSE to disable is.
Security
To achieve strong MITM-protection use HTTPS.
Framework is provided with simple in-built authentication mechanism: preshared ID: KEY pairs. Peers which are supposed to be connected should have at least one common ID: KEY pair.
The authentication process between two peers can be described in a simple few steps:
Each peer sends a list of his auth ID's and randomly generated CHALLENGE to another. If no auth ID:KEY specified peer sends auth confirmation.
Each peer checks if locally registered list of ID's intersects with the one received from remote peer. If no ID matched, sends error and closes conenctions with corresponding code.
Each peer chooses random intersected ID and hashes received CHALLENGE with corresponding KEY for that ID. Sends hashed RESPONSE value in pair with that ID.
Each peer receives RESPONSE with ID and checks if CHALLENGE hashed with corresponding KEY of received ID equals received RESPONSE. In such case sends auth confirmation. Else rejects auth and closes connection.
In case of both peers confirm each others's RESPONSES the handshake process is complete and then connections take part in futher communication. If auth exceeds timeout or some peer sends error and/or closes connection handshake fails.
Contribution
Project is MIT-licensed.
Feel free to open issues and fork.
If you have any ideas or remarks you are welcome to contact the author.