Redis study of ten Notes: Redis as Message Queuing

This blog is highly recommended:

Java PDF e-book collection of HD free download

https://www.cnblogs.com/yuxiang1/p/12099324.html

 

Redis not only as a cache server may also serve as the message queue. It's a list of types of natural support as a message queue. As shown below:

Since Redis list is implemented using a doubly linked list, save the head and tail nodes, inserting and removing elements in the list on both sides of the head and tail are very fast.

Redis can be directly used to achieve the List message queue simply and rpop or two instructions lpush rpush and lpop. A simple example is as follows:

 

Storing terminal message (message producers):

package org.yamikaze.redis.messsage.queue;
 import org.yamikaze.redis.test.MyJedisFactory;
import redis.clients.jedis.Jedis;
 
java.util.concurrent.TimeUnit import;
 
/**
 * Message Producer
 * @author yamikaze
 */
public class Producer extends Thread {
 
    public static final String MESSAGE_KEY = "message:queue";
    private Jedis jedis;
    private String producerName;
    private volatile int count;
 
    public Producer(String name) {
        this.producerName = name;
        init();
    }
 
    private void init() {
        jedis = MyJedisFactory.getLocalJedis();
    }
 
    public void putMessage(String message) {
        Long size = jedis.lpush(MESSAGE_KEY, message);
        . The System OUT .println (producerName + " : the number of the current message is not treated as: " + size);
        count++;
    }
 
    public int getCount() {
        return count;
    }
 
    @Override
    public void run() {
        try {
            while (true) {
                putMessage(StringUtils.generate32Str());
                TimeUnit.SECONDS.sleep(1);
            }
        } catch (InterruptedException e) {
 
        } catch (Exception e) {
            e.printStackTrace ();
        }
    }
 
    public static void main(String[] args) throws InterruptedException{
        Producer producer = new Producer("myProducer");
        producer.start();
 
        for(; ;) {
            . The System OUT .println ( " main: number of stored message: " + producer.getCount ());
            TimeUnit.SECONDS.sleep(10);
        }
    }
}

 

Messaging end (message consumer):

package org.yamikaze.redis.messsage.queue;
 
import org.yamikaze.redis.test.MyJedisFactory;
import redis.clients.jedis.Jedis;
 
/**
 * Message Consumers
 * @author yamikaze
 */
public class Customer extends Thread{
 
    private String customerName;
    private volatile int count;
    private Jedis jedis;
 
    public Customer(String name) {
        this.customerName = name;
        init();
    }
 
    private void init() {
        jedis = MyJedisFactory.getLocalJedis();
    }
 
    public void processMessage() {
        String message = jedis.rpop(Producer.MESSAGE_KEY);
        if(message != null) {
            count++;
            handle(message);
        }
    }
 
    public void handle(String message) {
        . The System OUT .println (the customerName + " message is being processed, the content of the message is: " + + Message " This is the first " + + COUNT " article " );
    }
 
    @Override
    public void run() {
        while (true) {
            processMessage();
        }
    }
 
    public static void main(String[] args) {
        Customer customer = new Customer("yamikaze");
        customer.start();
    }
}

 

However, the above examples news consumers have a problem that needs to be called constantly rpop way to see whether List pending messages. Each call will initiate a connection, which can cause unnecessary waste. You might use Thread.sleep () methods allow consumers to re-thread from time to time consumption, but this has two problems:

1, if the producer consumer spending faster than the speed, queue size will always increase over time take up a lot of memory space.

2, if the sleep time is too long, so can not handle some of the timeliness of news, sleep time is too short, the connection will cause relatively large overhead.

So you can use brpop directive, which returns only when there is an element, it will not block until a timeout returns null, then the consumer can end processMessage can be changed to this:

public void processMessage() {
    /**
     * Brpop support for multiple lists (queues)
     * Brpop instruction queue priority is supported, such as in this example MESSAGE_KEY priority higher than TestKey (order determination).
     * If there are elements of both lists, will give priority to high-return element of the priority list, so here priority return MESSAGE_KEY
     * 0 means no waiting restrictions, it would have been blocked here
     * / 
    List <String> messages jedis.brpop = ( 0 , Producer.MESSAGE_KEY, " TestKey " );
     IF (! Messages.size () = 0 ) {
         // Since this instruction can monitor multiple Key, it is returned a list
         // list consisting of 2, 1) a list of names, 2) data 
        String = the keyName messages. GET ( 0 );
         // if the return message is MESSAGE_KEY 
        IF (Producer.MESSAGE_KEY.equals (the keyName)) {
            String message = messages.get(1);
            handle(message);
        }
 
    }
    System.out.println("=======================");
}

 

You can then run the Customer, empty the console, you can see that the program has no output, blocked the brpop here. Then open Redis client, enter commands client list, two connections can view the current.

Publish / subscribe model

In addition to providing support for Redis message queue, but also provides a set of commands used to support publish / subscribe model.

1, released

Instructions for publishing a PUBLISH message, PUBLISH channel message format

The return value indicates the number subscribed to the message.

2, subscription

Instructions for receiving a SUBSCRIBE message format SUBSCRIBE Channel

After use SUBSCRIBE command can see into the subscription model, but does not receive a message sent publish, because before going to subscribe will receive the only issue in the news. In this mode other instructions, you can only see the reply. Reply divided into three types:

1, if subscribe, second value represents subscription channel, and the third value represents the first of several channels to subscribe to? (Understood as the serial number?)

2, if Message (message), the second channel is generating the message, the third message is

3. If unsubscribe, unsubscribe second value represents the channel, and the third value represents the number of subscriptions to the current client.

UNSUBSCRIBE commands can be used to unsubscribe, if not parameter will unsubscribe all subscriptions by the SUBSCRIBE command channel.

Redis also supports wildcard subscription-based message, using instructions PSUBSCRIBE (pattern subscribe), for example:

Try again push message will get the following results:

可以看到publish指令返回的是2,而订阅端这边接收了两次消息。这是因为PSUBSCRIBE指令可以重复订阅频道。而使用PSUBSCRIBE指令订阅的频道也要使用指令PUNSUBSCRIBE指令退订,该指令无法退订SUBSCRIBE订阅的频道,同理UNSUBSCRIBE也不能退订PSUBSCRIBE指令订阅的频道。同时PUNSUBSCRIBE指令通配符不会展开。

例如:PUNSUBSCRIBE * 不会匹配到 channel.*, 所以要取消订阅channel.*就要这样写PUBSUBSCRIBE channel.*。

代码示范如下:

package org.yamikaze.redis.messsage.subscribe;
 
import org.yamikaze.redis.messsage.queue.StringUtils;
import org.yamikaze.redis.test.MyJedisFactory;
import redis.clients.jedis.Jedis;
 
/**
 * 消息发布方
 * @author yamikaze
 */
public class Publisher {
 
    public static final String CHANNEL_KEY = "channel:message";
    private Jedis jedis;
 
    public Publisher() {
        jedis = MyJedisFactory.getLocalJedis();
    }
 
    public void publishMessage(String message) {
        if(StringUtils.isBlank(message)) {
            return;
        }
        jedis.publish(CHANNEL_KEY, message);
    }
 
    public static void main(String[] args) {
        Publisher publisher = new Publisher();
        publisher.publishMessage("Hello Redis!");
    }
}
简单的发送一个消息。

消息订阅方:

package org.yamikaze.redis.messsage.subscribe;
 
import org.yamikaze.redis.test.MyJedisFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
 
import java.util.concurrent.TimeUnit;
 
/**
 * 消息订阅方客户端
 * @author yamikaze
 */
public class SubscribeClient {
 
    private Jedis jedis;
    private static final String EXIT_COMMAND = "exit";
 
    public SubscribeClient() {
        jedis = MyJedisFactory.getLocalJedis();
    }
 
    public void subscribe(String ...channel) {
        if(channel == null || channel.length <= 0) {
            return;
        }
        //消息处理,接收到消息时如何处理
        JedisPubSub jps = new JedisPubSub() {
            /**
             * JedisPubSub类是一个没有抽象方法的抽象类,里面方法都是一些空实现
             * 所以可以选择需要的方法覆盖,这儿使用的是SUBSCRIBE指令,所以覆盖了onMessage
             * 如果使用PSUBSCRIBE指令,则覆盖onPMessage方法
             * 当然也可以选择BinaryJedisPubSub,同样是抽象类,但方法参数为byte[]
             */
            @Override
            public void onMessage(String channel, String message) {
                if(Publisher.CHANNEL_KEY.equals(channel)) {
                    System.out.println("接收到消息: channel : " + message);
                    //接收到exit消息后退出
                    if(EXIT_COMMAND.equals(message)) {
                        System.exit(0);
                    }
 
                }
            }
 
            /**
             * 订阅时
             */
            @Override
            public void onSubscribe(String channel, int subscribedChannels) {
                if(Publisher.CHANNEL_KEY.equals(channel)) {
                    System.out.println("订阅了频道:" + channel);
                }
            }
        };
        //可以订阅多个频道 当前线程会阻塞在这儿
        jedis.subscribe(jps, channel);
    }
 
    public static void main(String[] args) {
        SubscribeClient client = new SubscribeClient();
        client.subscribe(Publisher.CHANNEL_KEY);
        // not unsubscribe method
         // corresponding method is also not punsubscribe 
    }
}

 

Run the client, and then run the Publisher to send a message, output:

to sum up:

List of use Redis data structures can be quickly and easily make a message queue, while providing a Redis BRPOP and BLPOP instructions to solve the waste of resources and other issues frequently called Jedis and lpop method of rpop caused. In addition, Redis provides instructions for publish / subscribe model of message passing can be achieved, inter-process communication. v

Guess you like

Origin www.cnblogs.com/yuxiang1/p/12197947.html