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 accountwcx@qq.com
 *
 */
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);
}
展开阅读全文

没有更多推荐了,返回首页