1. 程式人生 > >redis訊息釋出和訂閱的運用與常見錯誤解決方法

redis訊息釋出和訂閱的運用與常見錯誤解決方法

  本文Redis所在系統:Linux,詳細安裝步驟可參考:https://www.cnblogs.com/zhaoyan001/p/6143170.html

  本文運用程式所在系統:windows7

 win7 CRT下 redis的常用命令:

  1 啟動redis 服務端:redis-server

  2 啟動redis 客戶端:redis-cli

  3 關閉redis 服務端:redis-cli -a 123456 shutdown (-a 123456在redis設定了密碼的情況下使用

)

  4 設定redis連線密碼:config set requirepass 123456 (123456 是設定的密碼,關閉伺服器後密碼會失效,需要重新設定

  5 授權登入:auth 123456  (123456 是設定的密碼,當redis設定了密碼時,真正使用redis設定或讀取資料需要密碼授權)

  6  訂閱redis訊息頻道:SUBSCRIBE china (china是頻道名稱,可以同時訂閱多個頻道,以空格隔開)

   

  7 redis頻道上釋出資訊

:publish china hello (china是頻道名稱,hello是訊息內容)

    顯示2表示當前頻道被訂閱的數量有2個,本機Java程式也同時訂閱了china頻道

 

 二  Java運用程式連線遠端Linux環境下redis的常見錯誤

  顯示連線被拒絕

Caused by: redis.clients.jedis.exceptions.JedisConnectionException: java.net.ConnectException: Connection refused: connect

 分析原因:檢視redis.conf檔案內容可以看出,redis預設只執行本機連線

  解決方法:找到如上圖的bind 127.0.0.1,改為bind 0.0.0.0,然後重啟redis 伺服器即可

  2 缺乏授權

redis.clients.jedis.exceptions.JedisDataException: DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted f....

  分析原因:出現授權的問題一般來說連線登入可能出現需要密碼的問題,或者需要取消保護模式的問題,檢視redis.conf檔案內容可以看出模式是保護的模式

 解決方法1:找到 如上圖的protected-mode yes,改為protected-mode no,,然後重啟redis 伺服器即可

 解決方法2:設定redis密碼,此時java運用程式連線也需要使用密碼連線

    最常見的Linux埠對外開放的問題

         因為redis伺服器部署在Linux上,肯定會出現開放埠的常見問題

    開放埠的解決方法:

方法一:命令列方式
               1. 開放埠命令: /sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT
               2.儲存:/etc/rc.d/init.d/iptables save
               3.重啟服務:/etc/init.d/iptables restart
               4.檢視埠是否開放:/sbin/iptables -L -n
    

 方法二:直接編輯/etc/sysconfig/iptables檔案
               1.編輯/etc/sysconfig/iptables檔案:vi /etc/sysconfig/iptables
                   加入內容並儲存:-A RH-Firewall-1-INPUT -m state --state NEW -m tcp -p tcp --dport 8080 -j ACCEPT
               2.重啟服務:/etc/init.d/iptables restart
               3.檢視埠是否開放:/sbin/iptables -L -n

 三 Java訊息訂閱釋出的運用程式案例

  依賴的jar:

 1  訊息訂閱的程式片段

import org.apache.log4j.Logger;
import redis.clients.jedis.JedisPubSub;

/**
 * 訂閱者
 */
public class Subscriber extends JedisPubSub {//注意這裡繼承了抽象類JedisPubSub

    private static final Logger LOGGER = Logger.getLogger(Subscriber.class);

    @Override
    public void onMessage(String channel, String message) {
        LOGGER.info(String.format("onMessage 接收訊息 Message. Channel: %s, Msg: %s", channel, message));
    }

    @Override
    public void onPMessage(String pattern, String channel, String message) {
    	LOGGER.info(String.format("onPMessage 接收訊息 PMessage. Pattern: %s, Channel: %s, Msg: %s",
    	    pattern, channel, message));
    }

    @Override
    public void onSubscribe(String channel, int subscribedChannels) {

        LOGGER.info("onSubscribe 訂閱  channel:"+channel+" ;subscribedChannels:"+subscribedChannels);
    }

    @Override
    public void onUnsubscribe(String channel, int subscribedChannels) {

        LOGGER.info("onUnsubscribe 取消訂閱 channel:"+channel+" ;subscribedChannels:"+subscribedChannels);
    }

    @Override
    public void onPUnsubscribe(String pattern, int subscribedChannels) {

        LOGGER.info("onPUnsubscribe 取消訂閱 channel:"+pattern+" ;subscribedChannels:"+subscribedChannels);
    }

    @Override
    public void onPSubscribe(String pattern, int subscribedChannels) {

        LOGGER.info("onPSubscribe 訂閱  channel:"+pattern+" ;subscribedChannels:"+subscribedChannels);
    }
}

  2 訊息釋出的程式片段

import org.apache.log4j.Logger;
import redis.clients.jedis.Jedis;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * 釋出者
 */
public class Publisher {

    private static final Logger LOGGER = Logger.getLogger(Publisher.class);
    private final Jedis publisherJedis;
    private final String channel;

    public Publisher(Jedis publisherJedis, String channel) {
        this.publisherJedis = publisherJedis;
        this.channel = channel;
    }

    /**
     * 不停的讀取輸入,然後釋出到channel上面,遇到quit則停止釋出。
     */
    public void startPublish() {
        LOGGER.info("Type your message (quit for terminate)");
        try {
            publisherJedis.publish(channel, "先發一條初始資訊aaaaaaaaaaaaaa");
            BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
            while (true) {
                String line = reader.readLine();
                if (!"quit".equals(line)) {
                    publisherJedis.publish(channel, line);
                } else {
                    break;
                }
            }
        } catch (IOException e) {
            LOGGER.error("IO failure while reading input", e);
        }
    }
}

3 主函式

public class MainClass {

    public static final String CHANNEL_NAME = "china";//頻道
    public static final String REDIS_HOST = "192.168.1.11";
    public static final int REDIS_PORT = 6379;

    private final static Logger LOGGER = Logger.getLogger(MainClass.class);
    private final static JedisPoolConfig POOL_CONFIG = new JedisPoolConfig();
    //private final static JedisPool JEDIS_POOL = new JedisPool(POOL_CONFIG, REDIS_HOST, REDIS_PORT, 10000);
    private final static JedisPool JEDIS_POOL = new JedisPool(POOL_CONFIG, REDIS_HOST, REDIS_PORT, 10000,"123456");

    public static void main(String[] args) throws Exception {
        final Jedis subscriberJedis = JEDIS_POOL.getResource();
        final Jedis publisherJedis = JEDIS_POOL.getResource();
        final Subscriber subscriber = new Subscriber();
        //訂閱執行緒:接收訊息
        new Thread(new Runnable() {
            public void run() {
                try {
                    LOGGER.info("Subscribing to \"MyChannel\". This thread will be blocked.");
                    //使用subscriber訂閱CHANNEL_NAME上的訊息,這一句之後,執行緒進入訂閱模式,阻塞。
                    subscriberJedis.subscribe(subscriber, CHANNEL_NAME);//訂閱

                    LOGGER.info("Subscription ended.");
                } catch (Exception e) {
                    LOGGER.error("Subscribing failed.", e);
                }
            }
        }).start();

        Thread.sleep(2000);

        //主執行緒:釋出訊息到CHANNEL_NAME頻道上
        new Publisher(publisherJedis, CHANNEL_NAME).startPublish();//進入釋出訊息程式
        publisherJedis.close();

        //Unsubscribe
        subscriber.unsubscribe(); //取消訂閱
        subscriberJedis.close();
    }
}

  注:命令視窗的訊息釋出和訂閱會與程式中的同步