package com.creditease.ns4.gear.watchdog.monitor.collect.log.sink.elasticsearch; import com.creditease.ns.log.NsLog; import com.creditease.ns4.gear.watchdog.common.log.NsLogger; import com.creditease.ns4.gear.watchdog.monitor.collect.log.constant.ElasticSearchHighSinkConstants; import com.creditease.ns4.gear.watchdog.monitor.collect.log.sink.elasticsearch.builder.IndexNameBuilder; import com.creditease.ns4.gear.watchdog.monitor.collect.log.sink.elasticsearch.serializer.ElasticSearchEventSerializer; import com.google.common.base.Preconditions; import com.google.common.base.Throwables; import com.google.common.collect.Lists; import org.apache.commons.lang.StringUtils; import org.apache.flume.*; import org.apache.flume.conf.Configurable; import org.apache.flume.instrumentation.SinkCounter; import org.apache.flume.sink.AbstractSink; import org.apache.http.HttpHost; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.CredentialsProvider; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; import java.nio.charset.Charset; import java.util.List; import static com.creditease.ns4.gear.watchdog.monitor.collect.log.constant.ElasticSearchHighSinkConstants.*; /** * @author outman * @description 高版本的es sink version 6.x * @date 2019/3/5 */ public class ElasticSearchHighSink extends AbstractSink implements Configurable { private static final NsLog logger = NsLogger.getWatchdogCollectLogger(); private static final Charset charset = Charset.defaultCharset(); private final CounterGroup counterGroup = new CounterGroup(); private String[] serverAddresses = null; private String serverUser = null; private String serverPassword = null; private static final int defaultBatchSize = 100; private int batchSize = defaultBatchSize; private String indexName = ElasticSearchHighSinkConstants.DEFAULT_INDEX_NAME; private String indexType = DEFAULT_INDEX_TYPE; private IndexNameBuilder indexNameBuilder; private ElasticSearchEventSerializer eventSerializer; private SinkCounter sinkCounter; private RestHighLevelClient client; //执行event的具体操作 @Override public Status process() throws EventDeliveryException { Status status = Status.READY; Channel channel = getChannel(); Transaction txn = channel.getTransaction(); List<Event> events = Lists.newArrayList(); try { txn.begin(); int count; for (count = 0; count < batchSize; ++count) { //从channel中获取元素,实际是event = queue.poll();如果为空则会抛出异常,会被捕获处理返回null Event event = channel.take(); if (event == null) { break; } //进行批处理到ES events.add(event); } //当达到设置的批次后进行提交 if (count <= 0) { sinkCounter.incrementBatchEmptyCount(); counterGroup.incrementAndGet("channel.underflow"); status = Status.BACKOFF; } else { if (count < batchSize) { sinkCounter.incrementBatchUnderflowCount(); status = Status.BACKOFF; } else { sinkCounter.incrementBatchCompleteCount(); } sinkCounter.addToEventDrainAttemptCount(count); //提交当前批次到ES bulkExecute(events); } txn.commit(); sinkCounter.addToEventDrainSuccessCount(count); counterGroup.incrementAndGet("transaction.success"); } catch (Throwable ex) { try { txn.rollback(); counterGroup.incrementAndGet("transaction.rollback"); } catch (Exception ex2) { logger.error( "Exception in rollback. Rollback might not have been successful.", ex2); } if (ex instanceof Error || ex instanceof RuntimeException) { logger.error("Failed to commit transaction. Transaction rolled back.", ex); Throwables.propagate(ex); } else { logger.error("Failed to commit transaction. Transaction rolled back.", ex); throw new EventDeliveryException( "Failed to commit transaction. Transaction rolled back.", ex); } } finally { txn.close(); } return status; } //初始化执行获取配置信息 @Override public void configure(Context context) { //获取配置信息 if (StringUtils.isNotBlank(context.getString(ElasticSearchHighSinkConstants.HOST_NAMES))) { serverAddresses = StringUtils.deleteWhitespace( context.getString(ElasticSearchHighSinkConstants.HOST_NAMES)).split(","); } Preconditions.checkState(serverAddresses != null && serverAddresses.length > 0, "Missing Param:" + ElasticSearchHighSinkConstants.HOST_NAMES); if (StringUtils.isNotBlank(context.getString(ElasticSearchHighSinkConstants.HOST_USER))) { this.serverUser = context.getString(ElasticSearchHighSinkConstants.HOST_USER); } if (StringUtils.isNotBlank(context.getString(ElasticSearchHighSinkConstants.HOST_PASSWORD))) { this.serverPassword = context.getString(ElasticSearchHighSinkConstants.HOST_PASSWORD); } if (StringUtils.isNotBlank(context.getString(INDEX_NAME))) { this.indexName = context.getString(INDEX_NAME); } if (StringUtils.isNotBlank(context.getString(INDEX_TYPE))) { this.indexType = context.getString(INDEX_TYPE); } if (StringUtils.isNotBlank(context.getString(BATCH_SIZE))) { this.batchSize = Integer.parseInt(context.getString(BATCH_SIZE)); } logger.info("获取到ES配置信息,address:" + StringUtils.join(serverAddresses) + ",index:" + indexName + ",batchSize:" + batchSize); if (sinkCounter == null) { sinkCounter = new SinkCounter(getName()); } String indexNameBuilderClass = DEFAULT_INDEX_NAME_BUILDER_CLASS; if (StringUtils.isNotBlank(context.getString(INDEX_NAME_BUILDER))) { indexNameBuilderClass = context.getString(INDEX_NAME_BUILDER); } Context indexnameBuilderContext = new Context(); try { @SuppressWarnings("unchecked") Class<? extends IndexNameBuilder> clazz = (Class<? extends IndexNameBuilder>) Class .forName(indexNameBuilderClass); indexNameBuilder = clazz.newInstance(); indexnameBuilderContext.put(INDEX_NAME, indexName); indexNameBuilder.configure(indexnameBuilderContext); } catch (Exception e) { logger.error("Could not instantiate index name builder.", e); Throwables.propagate(e); } eventSerializer = new ElasticSearchEventSerializer(); Preconditions.checkState(StringUtils.isNotBlank(indexName), "Missing Param:" + INDEX_NAME); Preconditions.checkState(batchSize >= 1, BATCH_SIZE + " must be greater than 0"); } //启动sink的一些配置 @Override public synchronized void start() { logger.info("start elasticsearch sink......"); HttpHost[] httpHosts = new HttpHost[serverAddresses.length]; for (int i = 0; i < serverAddresses.length; i++) { String[] hostPort = serverAddresses[i].trim().split(":"); String host = hostPort[0].trim(); int port = hostPort.length == 2 ? Integer.parseInt(hostPort[1].trim()) : DEFAULT_PORT; logger.info("elasticsearch host:{},port:{}", host, port); httpHosts[i] = new HttpHost(host, port, "http"); } RestClientBuilder builder = RestClient.builder(httpHosts); if (StringUtils.isNotBlank(serverUser) || StringUtils.isNotBlank(serverPassword)) { final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(serverUser, serverPassword)); builder.setHttpClientConfigCallback(new RestClientBuilder.HttpClientConfigCallback() { @Override public HttpAsyncClientBuilder customizeHttpClient( HttpAsyncClientBuilder httpClientBuilder) { return httpClientBuilder .setDefaultCredentialsProvider(credentialsProvider); } }); } client = new RestHighLevelClient(builder); sinkCounter.start(); super.start(); } //关闭资源 @Override public synchronized void stop() { logger.info("stop elasticsearch sink......"); if (client != null) { try { client.close(); } catch (IOException e) { e.printStackTrace(); } } sinkCounter.stop(); super.stop(); } //ES批处理的方法 public void bulkExecute(List<Event> events) throws Exception { //批量插入数据 BulkRequest request = new BulkRequest(); String indexName = null; for (Event event : events) { //如果没有切换天,那么索引可以服用,无需重复创建 if (StringUtils.isEmpty(indexName) || !indexName.endsWith(indexNameBuilder.getIndexSuffix(event))) { indexName = indexNameBuilder.getIndexName(event); } request.add(new IndexRequest(indexName, indexType).source(eventSerializer.serializer(event), XContentType.JSON)); } BulkResponse bulkResponse = client.bulk(request, RequestOptions.DEFAULT); TimeValue took = bulkResponse.getTook(); logger.debug("[批量新增花费的毫秒]:" + took + "," + took.getMillis() + "," + took.getSeconds() + ",events[" + events.size() + "]"); } }