Flume學習07 — FlumeRpcClientUtils工具類

FlumeRpcClientUtils提供通用的Event操作功能,通過配置文件可以在多個RpcClient之間進行切換。

FlumeRpcClientUtils配置參數

# 可選值default、thrift、default_failover、default_loadbalance
# 其中default使用avro協議
# 如果使用default_failover和default_loadbalance,那麼也只能用avro協議
client.type = default

# 如果client.type值爲default或者thrift,那麼hosts只有一臺主機
# 如果client.type值爲default_failover或者default_loadbalance,那麼hosts至少要配置兩臺主機。
hosts = h1
# hosts = h1,h2,h3

# 主機配置
hosts.h1 = 127.0.0.1:41414
# hosts.h2 = host2.example.org:41414
# hosts.h3 = host3.example.org:41414

# 如果主機連接失敗,是否把主機臨時放入黑名單中,過一段時間再啓用。
# 默認爲false,不放入黑名單。
backoff = false

# 主機連接失敗,下次連接該主機的最大時間間隔,單位毫秒。
# 默認值爲0,相當於30000毫秒。
maxBackoff = 0

# 如果client.type使用default_loadbalance,該模式下主機的輪詢策略。
# 可選策略有round_robin、random或者自定義策略(實現LoadBalancingRpcClient$HostSelector接口)。
# 默認是round_robin
host-selector = round_robin

# 批量發送的數量,該值必須大於0,默認是100。
batch-size = 500

# 連接超時,該值必須大於1000,默認是20000,單位毫秒。
connect-timeout = 20000

# 請求超時,該值必須大於1000,默認是20000,單位毫秒。
request-timeout = 20000

# 消息編碼,默認是utf-8
charset = utf-8

# 如果消息發送失敗,嘗試發送的消息次數,默認爲3次
attemptTimes = 3


import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.flume.Event;
import org.apache.flume.EventDeliveryException;
import org.apache.flume.api.RpcClient;
import org.apache.flume.api.RpcClientFactory;
import org.apache.flume.event.EventBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Flume客戶端工具類
 * 工具類初始化默認讀取配置文件flume-client.properties
 * 配置文件放在classpath下
 * 
 * @author [email protected]
 *
 */
public class FlumeRpcClientUtils {
    private static final Logger logger = LoggerFactory.getLogger(FlumeRpcClientUtils.class);

    private static Properties props = new Properties();

    // 是否已初始化
    private static volatile boolean isInit = false;

    // 發送消息的默認編碼,如果沒有設置編碼,則使用該默認編碼
    private static final String defaultCharsetName = "utf-8";

    // 發送消息的編碼
    private static Charset charset;

    // 如果消息發送失敗,嘗試發送的消息次數,默認爲3次
    private static int attemptTimes = 3;

    private static RpcClient client;

    /**
     * 初始化客戶端配置 客戶端配置必須放在classpath根目錄下的flume-client.properties文件中
     */
    public synchronized static void init() {
        if(isInit){
            return;
        }

        logger.info("初始化配置flume-client.properties");

        // 讀取配置文件
        InputStream is = FlumeRpcClientUtils.class.getClassLoader().getResourceAsStream("flume-client.properties");

        if (is == null) {
            logger.error("找不到配置文件flume-client.properties");
            return;
        }

        try {
            props.load(is);

            // 從配置文件中讀取消息編碼
            String charsetName = props.getProperty("charset");
            if (charsetName != null && !charsetName.equals("")) {
                try {
                    charset = Charset.forName(charsetName);
                } catch (Exception e) {
                    logger.error("編碼charset=" + charsetName + "初始化失敗,使用默認編碼charset=" + defaultCharsetName, e);
                }
            }
            props.remove("charset");

            // 如果編碼爲空,則使用默認編碼utf-8
            if (charset == null) {
                try {
                    charset = Charset.forName(defaultCharsetName);
                } catch (Exception e) {
                    logger.error("默認編碼charset=" + defaultCharsetName + "初始化失敗", e);
                }
            }

            // 讀取消息發送次數配置
            String strAttemptTimes = props.getProperty("attemptTimes");
            if (strAttemptTimes != null && !strAttemptTimes.equals("")) {
                int tmpAttemptTimes = 0;
                try {
                    tmpAttemptTimes = Integer.parseInt(strAttemptTimes);
                } catch (NumberFormatException e) {
                    logger.error("消息發送次數attemptTimes=" + strAttemptTimes + "初始化失敗,使用默認發送次數attemptTimes=" + attemptTimes, e);
                }

                if (tmpAttemptTimes > 0) {
                    attemptTimes = tmpAttemptTimes;
                }
            }
            props.remove("attemptTimes");

            // 初始化Flume Client
            // 根據不同的client.type,實例也不一樣
            client = RpcClientFactory.getInstance(props);

            isInit = true;
        } catch (IOException e) {
            logger.error("配置文件flume-client.properties讀取失敗", e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                }
            }
        }
    }

    /**
     * 發送一條記錄,如果發送失敗,該方法會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * 建議使用appendBatch以獲得更好的性能。
     * 
     * @param data 發送內容
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean append(String data) {
        boolean flag = false;
        Event event = EventBuilder.withBody(data, charset);
        int current = 0;

        while (!flag && current < attemptTimes) {
            current++;
            try {
                client.append(event);
                flag = true;
            } catch (EventDeliveryException e) {
                logger.error("發送失敗,當前已嘗試" + current + "次", e);
                logger.error("失敗消息" + data);
            }
        }

        return flag;
    }

    /**
     * 發送一條記錄,如果發送失敗,該方法會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * 建議使用appendBatch以獲得更好的性能。
     * 
     * @param event 發送內容
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean append(Event event){
        boolean flag = false;

        int current = 0;

        while (!flag && current < attemptTimes) {
            current++;
            try {
                client.append(event);
                flag = true;
            } catch (EventDeliveryException e) {
                logger.error("發送失敗,當前已嘗試" + current + "次", e);
                logger.error("失敗消息" + new String(event.getBody(), charset));
            }
        }

        return flag;
    }

    /**
     * 發送一條記錄,如果發送失敗,該方法會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * 建議使用appendBatch以獲得更好的性能。
     * 
     * @param data 發送內容
     * @param headers 發送的頭文件
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean append(String data, Map<String, String> headers){
        Event event = EventBuilder.withBody(data, charset);

        if(headers != null){
            event.setHeaders(headers);
        }

        return append(event);
    }

    /**
     * 以批量的方式發送一條記錄,該記錄不會立即發送,而是會放到內存隊列中,直到隊列中的記錄數達到batchSize纔會發送。
     * 如果發送失敗,會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * 
     * appendBatch性能遠高於append,建議使用。
     * 
     * @param data 單個記錄
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean appendBatch(String data){
        List<String> items = new ArrayList<String>();
        items.add(data);
        return appendBatch(items);
    }

    /**
     * 以批量的方式發送一條記錄,該記錄不會立即發送,而是會放到內存隊列中,直到隊列中的記錄數達到batchSize纔會發送。
     * 如果發送失敗,會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * 
     * appendBatch性能遠高於append,建議使用。
     * 
     * @param data 單個記錄
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean appendBatch(String data, Map<String, String> headers){
        List<Event> events = new ArrayList<Event>();
        Event event = EventBuilder.withBody(data, charset);
        event.setHeaders(headers);
        events.add(event);
        return appendBatchEvent(events);
    }

    /**
     * 以批量的方式發送一條記錄,該記錄不會立即發送,而是會放到內存隊列中,直到隊列中的記錄數達到batchSize纔會發送。
     * 如果發送失敗,會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * 
     * appendBatch性能遠高於append,建議使用。
     * 
     * @param data 單個記錄
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean appendBatch(Event event){
        List<Event> events = new ArrayList<Event>();
        events.add(event);
        return appendBatchEvent(events);
    }

    /**
     * 批量發送多條記錄,如果發送失敗,會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * appendBatch性能遠高於append,建議使用。
     * 
     * @param items 內容列表
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean appendBatch(List<String> items){
        return appendBatch(items, null);
    }

    /**
     * 批量發送多條記錄,如果發送失敗,會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * appendBatch性能遠高於append,建議使用。
     * 
     * @param items 內容列表
     * @param headers 頭部內容
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean appendBatch(List<String> items, Map<String, String> headers){
        boolean flag = false;

        // 如果參數不符合要求,則退出
        if(items == null || items.size() < 1){
            return flag;
        }

        List<Event> events = new LinkedList<Event>();

        if(headers != null){
            for(String item : items){
                Event event = EventBuilder.withBody(item, charset);
                event.setHeaders(headers);
                events.add(event);
            }
        }else{
            for(String item : items){
                events.add(EventBuilder.withBody(item, charset));
            }
        }

        // 當前嘗試發送的次數
        int current = 0;

        while (!flag && current < attemptTimes) {
            current++;
            try {
                client.appendBatch(events);
                flag = true;
            } catch (EventDeliveryException e) {
                logger.error("批量發送失敗,當前已嘗試" + current + "次", e);
            }
        }

        return flag;
    }

    /**
     * 批量發送多條記錄,如果發送失敗,會嘗試多次發送,嘗試次數在attemptTimes中設置,默認3次。
     * appendBatch性能遠高於append,建議使用。
     * 
     * @param events 內容列表
     * @return 發送成功返回true,失敗返回false
     */
    public static boolean appendBatchEvent(List<Event> events){
        boolean flag = false;

        // 如果參數不符合要求,則退出
        if(events == null || events.size() < 1){
            return flag;
        }

        // 當前嘗試發送的次數
        int current = 0;

        while (!flag && current < attemptTimes) {
            current++;
            try {
                client.appendBatch(events);
                flag = true;
            } catch (EventDeliveryException e) {
                logger.error("批量發送失敗,當前已嘗試" + current + "次", e);
            }
        }

        return flag;
    }

    public static int getBatchSize(){
        return client.getBatchSize();
    }
}


示例代碼

// 初始化
FlumeRpcClientUtils.init();

for(int i = 0; i < 10; i++){
    String data = "發送第" + i + "條數據";
    FlumeRpcClientUtils.append(data);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章