REIDS idées et mettre en œuvre les files d'attente en mode message

annuaire

avant-propos

Caractéristiques 1 file d'attente

2 Utiliser la liste simple file d'attente

2.1 idées

2.2 file d'attente des commandes simples liées

2.3 RedisTemplate Opération Liste file d'attente de messages mis en œuvre

3 SortedSet implémenté en utilisant la file d'attente de retard

Latence 3.1 Queueing scénarios d'application

3.2 idées

3,3 retard de file d'attente de commandes en relation obtenue

3.4 opération RedisTemplate SortedSet atteindre Latency Queuing

4 environnement Spring Boot en connexion Redis met en œuvre la publish / subscribe

4.1 deux producteurs

4.2 Message de configuration de l'écouteur

4.3 Producteur

4.4 Résultats des tests


avant-propos

       Redis est maintenant la plus populaire base de données valeur clé, il y a beaucoup de scénarios, y compris un cache, un verrou distribué, compteur, etc., décrits ici sont mis en œuvre en utilisant la file d'attente de messages Redis. Un middleware de file d'attente de message dédié, y compris RabbitMQ, RocketMQ, kafka autres, ils appartiennent tous à poids lourd. Dans le projet, si la demande est pas nécessaire d'utiliser le middleware de messagerie poids lourds, les files d'attente de messages peuvent être mis en œuvre à l'aide Redis.

Caractéristiques 1 file d'attente

       la structure de données de file d' attente est une chaîne linéaire, il y a deux opérations de base, enqueue et dequeue - mise en attente est l' écriture de données à la queue, une donnée de dequeue est retiré de la tête de file d' attente, on dit souvent qu'une FIFO (First Input First Out), FIFO .

 

2 Utiliser la liste simple file d'attente

2.1 idées

        Liste des éléments de type Redis dans la liste peut être insérée dans l' en- tête ( à gauche) ou un pied de page (extrême droite), bien sûr, la même chose peut également supprimer des éléments de l' en- tête ou le pied de page. Sur la base de cette caractéristique, en supposant Liste des plus à gauche élément est la tête de l'équipe , l'élément le plus à droite est la queue , puis à droite de l'élément de liste est inséré dans l'équipe , à gauche est la liste la plus d'éliminer les éléments de l'équipe .

2.2 file d'attente des commandes simples liées

        Juste, le type de liste Redis pour soutenir ces opérations, la commande , on utilisera l' Rpush, Lpop, Blpop. Dans lequel, RPUSH valeurs de commande pour un ou plusieurs inséré à la queue de la liste (à droite), peuvent être utilisés ici en file d' attente. Lpop BLPOP et commandes sont disponibles pour dequeuing, dans lequel Lpop commande est utilisée pour retirer et renvoyer le premier élément de la liste, lorsque la clé spécifiée ne pas exister, les rendements nuls; BLPOP supprime également et retourne le premier élément de la liste, et commande Lpop est différent, il bloque jusqu'à ce qu'un délai d' attente ou attendre que la découverte d'éléments peuvent apparaître lorsque Blpop aucun élément dans la liste.

2.3 RedisTemplate Opération Liste file d'attente de messages mis en œuvre

        Ici, la file d'attente de messages en utilisant de simples SpringBoot + RedisTemplate, le code se compose de deux parties, le producteur (en file d'attente) et le consommateur (dequeue).

        Le premier est l'équipe (producteur) code ici équivaut à utiliser Rpush « simpleQueue » Liste des trois valeurs écrites dans « Java », « C ++ » et « Python » est la clé.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;


@RunWith(SpringRunner.class)
@SpringBootTest
public class MessageSender {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void sendMessage() {
        // 往队列的最右边添加元素
        redisTemplate.opsForList().rightPushAll("simpleQueue", "Java", "C++", "Python");
    }
}

       Ensuite , l'équipe (consommateurs) Code redisTemplate.opsForList (). LeftPop ont des méthodes plus surchargées, le libellé ici est l'équivalent d'appeler commande Blpop, et définir le délai à temps de 60 secondes, un moyen de bloquer l' élément pop-up.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.QueryTimeoutException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.TimeUnit;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MessageListener {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void listenMessage() {
        while(true) {
            try {
                String message = redisTemplate.opsForList().leftPop("simpleQueue", 60, TimeUnit.SECONDS);
                System.out.println("已消费队列" + message);
            } catch (QueryTimeoutException e) {
                System.out.println("60秒内没有新的消息,继续。。。");
            }
        }
    }
}

 

3 SortedSet implémenté en utilisant la file d'attente de retard

Latence 3.1 Queueing scénarios d'application

  • Toutes les commandes créées si non utilisé dans les 15 minutes, automatiquement annulées;
  • Envoyer un SMS, 11 envoyer le message entier, effectué à nouveau pendant 2 minutes;
  • Les utilisateurs sous les ordres de mets à emporter, les entreprises ne sont pas des ordres à 5 minutes, nous avons besoin d'annuler automatiquement l'ordre.        

3.2 idées

       Tel qu'il est utilisé ici, les Redis SortedSet implémentations de type queue délai. Tout d' abord, il est le même que celui de cordes SortedSet et types de collections d'éléments, et ne permet pas d' éléments en double et Set La différence est que un double score associé à chaque type d'élément sera SortedSet, Redis par une fraction de ce genre en tant que membre de SortedSet, De plus , cela peut être répété valeur fractionnelle.

       Maintenant, il y a une telle demande, va créer plus de 15 minutes d'un ordre de fermeture, en fonction des caractéristiques SortedSet peut le faire.

       Dans nos producteurs ici une SortedSet collection pour la file d' attente de retard, Key est une constante, définie ici comme orderId. Lorsque vous créez une commande, le numéro de commande est écrit dans la clé de orderId SortedSet, qui est, la valeur du numéro d'ordre de valeur stockée, repoussé quinze minutes lorsque l'horodatage dépôt score de création de la commande.

       Du côté des consommateurs de la clé pour obtenir tous les éléments de la collection sur la base traversant ces éléments marquera inférieure à la valeur actuelle de la valeur d'horodatage de suppression, et de consommer ces messages.

3,3 retard de file d'attente de commandes en relation obtenue

       Latence sera utilisé Queueing pour réaliser la commande associée SortedSet sont:

  • Zadd : pour un ou plusieurs éléments et ajoutée à la valeur de point de consigne commandé;
  • Zrangebyscore: Renvoie la liste des membres de la section de fraction spécifié d'éléments, les résultats sont disposées dans l' ordre croissant en fonction du score;
  • Zrem : la suppression d' un ou plusieurs éléments de la collection.

3.4 opération RedisTemplate SortedSet atteindre Latency Queuing

        Toujours est SpringBoot + RedisTemplate, comprend les producteurs et les consommateurs du code, de commande cours RedisTemplate package fait, le nom de l'API Redis nom de la commande elle-même est différent.

        producteur:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Calendar;
import java.util.Random;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MessageSender {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void sendMessage() {
        // 时间戳取当前时间往后推15分钟,存入sorted-set的score值
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.MINUTE, 15);
        double millisecond = calendar.getTimeInMillis();
        // 以简单的方式模拟订单号
        Random random = new Random();
        int orderId = Math.abs(random.nextInt());
        redisTemplate.opsForZSet().add("orderId", String.valueOf(orderId), millisecond );
        System.out.println("发送订单任务,订单ID为===============" + orderId);
    }
}

        Les consommateurs:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.Iterator;
import java.util.Set;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MessageListener {
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Test
    public void listenMessage() {
        while(true){
            Set<ZSetOperations.TypedTuple<String>> orderIdSet = redisTemplate.opsForZSet().rangeWithScores("orderId", 0, -1);
            if(orderIdSet == null || orderIdSet.isEmpty()){
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                    break;
                }
                continue;
            }
            Iterator<ZSetOperations.TypedTuple<String>> iterator = orderIdSet.iterator();
            ZSetOperations.TypedTuple<String> next = iterator.next();
            Double score = next.getScore();
            if(score == null) {
                continue;
            }
            double nowTime = System.currentTimeMillis();
            if(nowTime >= score) {
                String value = next.getValue();
                redisTemplate.opsForZSet().remove("orderId", value);
                System.out.println("已成功处理一条订单,订单id为" + value);
            }
        }
    }
}

 

4 environnement Spring Boot en connexion Redis met en œuvre la publish / subscribe

        Publier / Souscrire à savoir Publier / SUBSCRIBE , il est un mode de messagerie de communication. Dans ce mode , vous pouvez avoir plusieurs consommateurs souscrivent à un certain nombre de canaux, le producteur envoie un message au canal, abonné au canal de tous les consommateurs recevront le message.

        Redis lui - même soutient publication / abonnement, abonnez - vous à des canaux de commande ABONNER, poster des messages de commande pour PUBLIER, après les deux consommateurs abonnez - vous à la même chaîne, sinon un producteur a annoncé que , par exemple, réalisé avec Spring Boot + RedisTemplate fonctionnel et testé.

4.1 deux producteurs

        Définition des deux producteurs, les producteurs des deux méthodes ont un consommateur de message.

/**
 * 消费者一
 */
public class SubscribeOne {
    public void receive(String message) {
        System.out.println("这里是一号订阅客户端,接收到信息:" + message);
    }
}
/**
 * 消费者二
 */
public class SubscribeTwo {
    public void receive(String message) {
        System.out.println("这里是二号订阅客户端,接收到信息:" + message);
    }
}

4.2 Message de configuration de l'écouteur

        Dans cette configuration, le conteneur définit un écouteur de messages message d'écoute avec deux adaptateurs.

import com.bigsea.Controller.ChatController;
import com.bigsea.subscribe.SubscribeOne;
import com.bigsea.subscribe.SubscribeTwo;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.listener.adapter.MessageListenerAdapter;
import org.springframework.stereotype.Component;

@Component
public class subscribeConfig {
    private static final String RECEIVE_NAME = "receive";
    /**
     * 消息监听适配器一
     * @return MessageListenerAdapter
     */
    @Bean
    public MessageListenerAdapter listenerAdapterOne() {
        return new MessageListenerAdapter(new SubscribeOne(), RECEIVE_NAME);
    }

    /**
     * 消息监听适配器二
     * @return MessageListenerAdapter
     */
    @Bean
    public MessageListenerAdapter listenerAdapterTwo() {
        return new MessageListenerAdapter(new SubscribeTwo(), RECEIVE_NAME);
    }

    /**
     * 定义消息监听者容器
     * @param connectionFactory 连接工厂
     * @param listenerAdapterOne MessageListenerAdapter
     * @param listenerAdapterTwo MessageListenerAdapter
     * @return RedisMessageListenerContainer
     */
    @Bean
    public RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,
                                                   MessageListenerAdapter listenerAdapterOne,
                                                   MessageListenerAdapter listenerAdapterTwo) {
        RedisMessageListenerContainer listenerContainer = new RedisMessageListenerContainer();
        listenerContainer.setConnectionFactory(connectionFactory);
        listenerContainer.addMessageListener(listenerAdapterOne, new PatternTopic(ChatController.CHAT_NAME));
        listenerContainer.addMessageListener(listenerAdapterTwo, new PatternTopic(ChatController.CHAT_NAME));
        return listenerContainer;
    }
}

4.3 Producteur

        Les producteurs ont annoncé canal « myMessage », deux consommateurs est surveillent également ce canal.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/chat")
public class ChatController {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public static final String CHAT_NAME = "myMessage";

    private static final int MESSAGE_COUNT = 10;

    @GetMapping("/pub")
    public void publish() {
        for(int i = 1; i <= MESSAGE_COUNT; i++) {
            stringRedisTemplate.convertAndSend(CHAT_NAME, "发布的第" + i + "条消息");
        }
    }
}

4.4 Résultats des tests

        Cela a commencé une application Boot Spring, directement dans le navigateur via l'URL pour accéder aux résultats d'impression de la console sont les suivantes.

这里是一号订阅客户端,接收到信息:发布的第1条消息
这里是一号订阅客户端,接收到信息:发布的第2条消息
这里是二号订阅客户端,接收到信息:发布的第2条消息
这里是二号订阅客户端,接收到信息:发布的第1条消息
这里是一号订阅客户端,接收到信息:发布的第3条消息
这里是二号订阅客户端,接收到信息:发布的第3条消息
这里是二号订阅客户端,接收到信息:发布的第4条消息
这里是一号订阅客户端,接收到信息:发布的第4条消息
这里是二号订阅客户端,接收到信息:发布的第5条消息
这里是一号订阅客户端,接收到信息:发布的第5条消息
这里是一号订阅客户端,接收到信息:发布的第6条消息
这里是二号订阅客户端,接收到信息:发布的第6条消息
这里是一号订阅客户端,接收到信息:发布的第7条消息
这里是二号订阅客户端,接收到信息:发布的第7条消息
这里是一号订阅客户端,接收到信息:发布的第8条消息
这里是二号订阅客户端,接收到信息:发布的第8条消息
这里是一号订阅客户端,接收到信息:发布的第9条消息
这里是二号订阅客户端,接收到信息:发布的第9条消息
这里是二号订阅客户端,接收到信息:发布的第10条消息
这里是一号订阅客户端,接收到信息:发布的第10条消息

 

Publié 48 articles originaux · louange gagné 66 · vues 20000 +

Je suppose que tu aimes

Origine blog.csdn.net/y506798278/article/details/104858995
conseillé
Classement