最近在学es,需要导入8亿条数据
手上有一个txt大约有8亿条数据的样子,文件有19G左右,一开始百度搜了下,基本都是重复文章,不过也根据写这些文章的大佬慢慢google到了一些方法。
先说下导入机器配置:
cpu: E5 1620V2
内存: 32G(分给es 12G)
硬盘:4x2T raid 0(io大概在600左右)
导入的几种方法:
1、bulk:
ES本地支持的批量导入方式,将json文件post到es进行处理。
将需要导入的数据先生成json文件,格式类似这种
#指定 index {"index":{"_index":"suoy","_id":1}} #字段 {"text_entry":"内容"} {"index":{"_index":"suoy","_id":1}} {"text_entry":"内容"} {"index":{"_index":"suoy","_id":1}} {"text_entry":"内容"} ...........
然后使用curl提交
curl -H 'Content-Type: application/x-ndjson' -XPOST '127.0.0.1:9200/xxxxxxxx/doc/_bulk?pretty' --data-binary @out.json
一开始我是尝试这种方法,用python将数据重新处理了下,生成的文件有48GB......,还花了3-5个小时的样子,导入的时候直接失败~后面,看了下说是文件大小尽量不能超过200MB???这样的话就要分割文件了,虽然可以shell脚本一个一个的提交小文件json,后面想想直接放弃了(嫌麻烦).......
2、logstash:
ES官方的另一个产品,将数据文本转换为ES的数据源。
我的文本一行只有两个字段,用 "----" 分割,花了点时间学logstash直接上手开干,但是导入速度只有9000条/s的样子,一个小时导了大概3200w条数据,导了16个小时大概导了5.2亿条数据,这速度完全不行啊,后面手贱不注意按了 Ctrl+c,嗯.....这下好了,不知道怎么断点续传,又得重新来......
我用的脚本如下,有懂的大佬能否告知下logstash有没有类似BulkProcessor储存到x条数据再执行Bulk的方法?
input { # 从文件读取日志信息 file { path => "/data/sda3/k/log.txt" type => "text" start_position => "beginning" } } filter { mutate { split => ["message", "----"] } if [message][2] { mutate { add_field => { "title" => "%{[message][1]}" "log" => "%{[message][2]}" } } }else{ if [message][0] { mutate { add_field => { "title" => "%{[message][0]}" } } } if [message][1] { mutate { add_field => { "log" => "%{[message][1]}" } } } } } output { elasticsearch{ hosts => "127.0.0.1:9200" index => "logs" user => "elastic" #password => "xxx" #document_type => "_doc" } # 标准输出 #stdout { codec => rubydebug } }
3、Bulk Processor
rest方式采用的是restClient,基于http协议,Bulk Processor使用的是TransportClient,基于Tcp协议。
我这里是将数据jaon序列化后再提交的
配置文件
cluster.name=my-application ip=10.0.2.26 port=9300 # 每x个请求执行一次Bulk setBulkActions=10 # 每5MB Bulk setBulkSize=5 #无论请求多少,我都希望每x秒刷新一次* setFlushInterval=10 # 设置并发请求数 setConcurrentRequests=5 index=logs path=D:\\log.txt
Maven
org.elasticsearch.client transport 7.1.0 org.apache.logging.log4j log4j-core 2.11.1 com.lmax disruptor 3.4.1 com.google.code.gson gson 2.8.5 org.elasticsearch elasticsearch 7.1.0 org.elasticsearch.client elasticsearch-rest-client 7.1.0 org.elasticsearch.client elasticsearch-rest-high-level-client 7.1.0
public static void init(String filepath) throws IOException, InterruptedException { // https://www.elastic.co/guide/en/elasticsearch/client/java-api/current/java-docs-bulk-processor.html /*cluster.name 必须与服务端相同*/ Settings settings = Settings.builder().put("cluster.name", "my-application").build(); // final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); // credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "12346")); //es账号密码(默认用户名为elastic) TransportClient client = new PreBuiltTransportClient(settings) .addTransportAddress(new TransportAddress(InetAddress.getByName(properties.getProperty("ip")), Integer.valueOf(properties.getProperty("port")))); BulkProcessor build = BulkProcessor.builder(client, new BulkProcessor.Listener() { @Override public void beforeBulk(long l, BulkRequest bulkRequest) { /*在批量执行之前调用此方法*/ logger.info("---尝试插入{}条数据---", bulkRequest.numberOfActions()); } @Override public void afterBulk(long l, BulkRequest bulkRequest, BulkResponse bulkResponse) { /*批量执行后调用此方法。例如,您可以检查是否有一些失败的请求response.hasFailures()*/ logger.info("---插入完成-> {}条数据,---", bulkRequest.numberOfActions()); bulkResponse.hasFailures(); } @Override public void afterBulk(long l, BulkRequest bulkRequest, Throwable throwable) { /*批量失败并引发一个 Throwable*/ logger.error("error:" + throwable.getMessage() + " \ncause:" + throwable.getCause()); // logger.info("---尝试插入{}条数据---", bulkRequest.numberOfActions()); } }) /*每x个请求执行一次Bulk*/ .setBulkActions(Integer.valueOf(properties.getProperty("setBulkActions"))) /*每5MB Bulk一次*/ .setBulkSize(new ByteSizeValue(Integer.valueOf(properties.getProperty("setBulkSize")), ByteSizeUnit.MB)) /*无论请求多少,我都希望每5秒刷新一次*/ .setFlushInterval(TimeValue.timeValueSeconds(Integer.valueOf(properties.getProperty("setFlushInterval")))) /*设置并发请求数。值为0表示仅允许执行一个请求。值为1表示允许在累积新的批量请求时执行1个并发请求。*/ .setConcurrentRequests(Integer.valueOf(properties.getProperty("setConcurrentRequests"))) /*设置一个自定义退避策略,该策略最初将等待100毫秒,然后呈指数增长,然后重试最多3次。每当一个或多个批量项目请求失败时,都会尝试重试,EsRejectedExecutionException 并显示,表明有太多的计算资源可用于处理请求。要禁用退避,请通过BackoffPolicy.noBackoff()*/ .setBackoffPolicy( BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(100), 3) ).build(); /*默认情况下BulkProcessor: 将bulkActions设置为 1000 设置bulkSize为 5mb 没有设置flushInterval 将parallelRequests设置为1,这意味着异步执行刷新操作。 将backoffPolicy设置为具有8次重试和50ms启动延迟的指数补偿。总等待时间约为5.1秒。 */ String index = properties.getProperty("index"); logger.info("开始添加数据!"); Gson gson = new Gson(); // 读取日志文件 File file = new File(filepath); BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file)); BufferedReader reader = new BufferedReader(new InputStreamReader(fis, "utf-8"), 10 * 1024 * 1024);// 用10M的缓冲读取文本文件 String line = ""; while ((line = reader.readLine()) != null) { //TODO: write your business Map<String, String> map = new HashMap<>(); /*第一种情况*/ String[] split = line.split("----"); if (split.length > 1) { map.put("qq", split[1]); map.put("phone", split[2]); } if (map.size() > 0) { /*添加数据*/ build.add(new IndexRequest(index, "_doc").source(gson.toJson(map), XContentType.JSON)); } } logger.info("添加数据完成!等待提交......"); /*刷新剩余请求*/ //build.flush(); build.awaitClose(10, TimeUnit.MINUTES); // build.close();
我设置的BulkActions值为 50000 用这种方式导入速度达到了 6w/s的速度,cpu也是全部跑满,完全将性能发挥出来了~
参考文章:
https://www.cnblogs.com/ttzsqwq/p/11077574.html
https://blog.csdn.net/wslyk606/article/details/79413980
导入的txt可以看一下格式吗
我的这个就是每行 "----" 分割