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);
}