[Middleware]--ZMQ notes summary (java)

Official website address: https://zeromq.org/get-started/

java-API documentation: https://www.javadoc.io/doc/org.zeromq/jeromq/latest/index.html

ZreoMQ supports many languages, all of which are java.

The pictures in this article are copied and pasted, and there is nothing to draw here. The main thing is to share the code of the message mode.

Original link: Introduction to ZMQ

Official github: code

insert image description here

1. Introduction

A high-performance asynchronous messaging library designed for use in distributed or concurrent applications. It provides a message queue, but unlike message-oriented middleware, a ZeroMQ system can operate without a dedicated message broker.

ZeroMQ supports common messaging patterns (publish/subscribe, request/reply, client/server, etc.), making inter-process messaging as easy as inter-thread messaging. This makes the code clean, modular and very extensible.

The meaning of 0 in ZeroMQ:

0 means no broker, zero latency, zero cost, and zero administration.

In layman's terms, Zero refers to the minimalist culture that permeates the project. We add functionality by removing complexity1 rather than exposing new functionality.


2. Introduce the maven project

    <dependency>
      <groupId>org.zeromq</groupId>
      <artifactId>jeromq</artifactId>
      <version>0.5.2</version>
    </dependency>

    <!-- for the latest SNAPSHOT --><!--最新的,这俩一个就够了-->
    <dependency>
      <groupId>org.zeromq</groupId>
      <artifactId>jeromq</artifactId>
      <version>0.5.3-SNAPSHOT</version>
    </dependency>

    <!-- If you can't find the latest snapshot -->
    <repositories>
      <repository>
        <id>sonatype-nexus-snapshots</id>
        <url>https://oss.sonatype.org/content/repositories/snapshots</url>
        <releases>
          <enabled>false</enabled>
        </releases>
        <snapshots>
          <enabled>true</enabled>
        </snapshots>
       </repository>
    </repositories>

3. Message mode

1. Answer mode

REQ-REP: The client must first use send()send message, and then use recv()receive. If the order is disturbed, an error will be reported. The same is true for the server, which must first receive and then send.

insert image description here

  1. client
public class Client {
    
    
    public static void main(String[] args) {
    
    
       ZContext context = new ZContext(1);
        ZMQ.Socket socket = context.createSocket(SocketType.REQ);
        socket.connect("tcp://localhost:5555");
        while (true) {
    
    
            socket.send("1");
            byte[] recv = socket.recv();
            System.out.println(new String(recv));
        }
        // 这是需要关流的
        context.close();
        socket.close();
    }
}
  1. Server
public class Server {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ZContext context = new ZContext(1);
        ZMQ.Socket socket = context.createSocket(SocketType.REP);
        socket.bind("tcp://*:5555");
        while (true){
    
    
            byte[] recv = socket.recv();
            System.out.println(new String(recv));
            socket.send("接收到了,OKK");
        }
    }
}

2. Subscribe to publish mode

PUB-SUBrecv(): This combination is asynchronous, and the client can only receive messages in a loop body . When using SUB sockets, messages cannot be sent. The same is true for the server, which can only send()send messages, but cannot use PUB sockets to receive messages.

Note: Because it is impossible to know when the SUB starts to receive messages, even if the SUB is opened first, and then the PUB is opened to send messages, the SUB will still lose some messages at this time, because it takes time for the TCP to establish a connection. You can let the PUB sleep for a period of time first, and then send a message after confirming the connection.

[External link picture transfer failed, the source site may have an anti-leeching mechanism, it is recommended to save the picture and upload it directly (img-tXXo7Jwy-1641614318627)(https://secure2.wostatic.cn/static/eMzSj3L63Ye3D5JEbzAQav/image.png)]

  1. client
public class ClientA {
    
    
    public static void main(String[] args) {
    
    
       ZContext context = new ZContext(3);
        ZMQ.Socket socket = context.createSocket(SocketType.SUB);
        socket.connect("tcp://localhost:5555");
        // 设置,指订阅前缀为A 的消息,设置为“” 表示全部接受
        socket.subscribe("A".getBytes());
        while (!Thread.currentThread().isInterrupted()) {
    
    
            byte[] recv = socket.recv();
            System.out.println(new String(recv));
        }
    }
}
public class ClientB {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ZContext context = new ZContext(3);
        ZMQ.Socket socket = context.createSocket(SocketType.SUB);
        socket.connect("tcp://localhost:5555");
        socket.subscribe("B".getBytes());
        while (!Thread.currentThread().isInterrupted()) {
    
    
            byte[] recv = socket.recv();
            System.out.println(new String(recv));
        }
    }
}
  1. Server
public class Server {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ZContext context = new ZContext(1);
        ZMQ.Socket socket = context.createSocket(SocketType.PUB);
        socket.bind("tcp://*:5555");
        // 设置一定的休眠时间,确保能链接上。
        Thread.sleep(1000);
        Scanner sc = new Scanner(System.in);
        while (true) {
    
    
            String next = sc.next();
            socket.send(next.getBytes(StandardCharsets.UTF_8), 0);
        }
    }
}

3. Pipeline mode

PUSH-PULL: Distribute data to all nodes of the downstream link, and the data is evenly distributed (circular release).

insert image description here

  1. Transmitter
//定义最上面的分发任务的
public class Master {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ZContext context = new ZContext(1);
        ZMQ.Socket socket = context.createSocket(SocketType.PUSH);
        // 工人会链接到这个用来接受消息的
        socket.bind("tcp://*:5555");
        // 只执行一次。告诉接收器开始工作
        ZMQ.Socket slink = context.createSocket(SocketType.PUSH);
        slink.connect("tcp://localhost:6666");
        // 设置休眠,保证连接
        Thread.sleep(1000);
        //生成100个任务,分发给工人
        slink.send("开始工作");
        for (int i = 1; i < 101; i++) {
    
    
        // 设置线程休眠,观察动态加入工作
            Thread.sleep(1000)
            socket.send(String.valueOf(i));
        }
    }
}
  1. workers
//定义 工作者,(可以多写几个 )除了执行任务逻辑不同,其他的相同
public class Worker1 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        ZContext context = new ZContext(1);
        //链接发送器
        ZMQ.Socket socket = context.createSocket(SocketType.PULL);
        socket.connect("tcp://localhost:5555");
        //链接接收器
        ZMQ.Socket slink = context.createSocket(SocketType.PUSH);
        slink.connect("tcp://localhost:6666");
        //执行任务
        while (true){
    
    
            //接受数据
            byte[] recv = socket.recv();
            String s = new String(recv);
            System.out.println(s);
            //发送数据
//            Thread.sleep(1000);
            Thread.sleep(100);
            slink.send("A发送的消息:"+s);
        }
    }
}
  1. receiver
//定义接收器
public class Receiver {
    
    
    public static void main(String[] args) {
    
    
        ZContext context  = new ZContext(1);
        ZMQ.Socket socket = context.createSocket(SocketType.PULL);
        socket.bind("tcp://*:6666");
        // 只负责接收数据
        while (true){
    
    
            System.out.println(new String(socket.recv()));
        }
    }
}

Some issues I've encountered:

As described above, the message must be sent under the condition of ensuring the link, otherwise it may happen that all the sent messages are poured into one node, or the message is sent but not received. (This ZMQ is so fast)

And then:

  1. If you stop the receiver, the message will not be lost, the above worker will block, when you restart the receiver, you will find that the message will still be received normally.
  2. When the program is running, if one of the workers goes down, the message will be evenly distributed to other workers; when the downtime worker restarts, after it is connected to the sender, it can still send and receive messages normally. This is the dynamic addition of nodes described above.

There are two other modes on the official website, I don’t seem to be able to use them, and I will continue to share them with you when I use them later.

Guess you like

Origin blog.csdn.net/m0_56186460/article/details/122378288