ElasticSearch多线程写入实战(一)多线程同步异步写入ES,模拟hadoop文件拆分处理,join与CountDownLatch的区别,多线程读写小练习

本文通过实战演示ElasticSearch的多线程同步和异步写入,包括数据预处理、数据导入ES集群、多线程读写文件的练习,对比synchronized与Lock、CountDownLatch与join的使用,以及探讨在不同场景下的性能优化策略。
摘要由CSDN通过智能技术生成

1、数据预处理

1、网站爬取数据,写为csv
2、添加表头
sed -i ‘1i\时报错:
sed: -i may not be used with stdin
mac中应该写为:【mac自带的sed命令,是基于bsd的,所以与Linux-like下常用的gnu不一样

sed -i "" '1i\
insert value here
' filename.csv

3、处理为json

2、数据导入es集群

public class JsonToES {
    private static final Logger LOGGER = LoggerFactory.getLogger(OpenClose.class);

    public void jsonToES(File[] files) {
        Map<String, Object> hashMap = EsPropertiesUtils.getConf();
        TransportClient client = OpenClose.getInstance(hashMap);
        int idNum = 0;
        for (File f : files) {
            // 一、绝对路径读取文件
            System.out.println(f.getAbsolutePath());
            File file = new File(f.getAbsolutePath());
            // 二、开始一行一行的写
            try (BufferedReader br = new BufferedReader(new FileReader(file))) {
                BulkRequestBuilder bulkRequest = client.prepareBulk();
//                Map<String, Object> valuesMap = new HashMap<>(64, 0.6f);
                String line;
                while ((line = br.readLine()) != null) {
                    bulkRequest.add(client.prepareIndex("taobao", "rates", Integer.toString(idNum)).setSource(line, XContentType.JSON));
//                    valuesMap.clear();
                    if (idNum % 20000 == 0) {
                        System.out.println("++++++++++++++++++++++++++++++++++++");
                        // 三、批量导入,与网速有关
                        bulkRequest.execute().actionGet();
                    }
                    idNum++;
                    System.out.println(idNum);
                }
                // 四、导入每个文件最后不足2000条的数据(但是必须得有数据,否则报错: no requests added)
                // 查阅源码可知,可通过拿到父类requests属性,判断其size来解决[子类调用父类方法获得属性]
                if (bulkRequest.request().requests().size() > 0) {
                    bulkRequest.get();
                }
                // 五、操作下一个文件
            } catch (IOException e) {
                LOGGER.error(":ERROR:堆栈信息====={}", e.getMessage());
            }
        }
        OpenClose.closeClient(client);
    }

    public static void main(String[] args) {
        JsonToES jsonToES = new JsonToES();
        File file = new File("/Users/wanghai/shendeng_back/rates/");
        // 目录下只有我需要读取的文件,故不再进行进一步处理
        File[] files = file.listFiles();
        long begin = System.currentTimeMillis();
        jsonToES.jsonToES(files);
        System.out.println("总耗时: " + (System.currentTimeMillis() - begin) / 1000 + "s");
    }
}

3、优化

之前进行过一次优化实战,但是当时没有以多线程的形式进行优化。这里进行多线程提高写入速度的实战。

3-1、多线程读写文件小练习——写

先热身一下,以多线程的形式读写同一个文件,查看效率差异。
1、没用过Lock,打算不使用synchronized,尝试下Lock

3-1-1、synchronized与Lock的区别与使用
  • 锁类型
    1. 可重入锁:在执行对象中所有同步方法不用再次获得锁
    2. 可中断锁:在等待获取锁过程中可中断
    3. 公平锁: 按等待获取锁的线程的等待时间进行获取,等待时间长的具有优先获取锁权利
    4. 读写锁:对资源读取和写入的时候拆分为2部分处理,读的时候可以多线程一起读,写的时候必须同步地写

synchronized的缺点有
1)不能响应中断;

2)锁的释放由虚拟机来完成,不用人工干预,不过此即使缺点也是优点,优点是不用担心会造成死锁,缺点是由可能获取到锁的线程阻塞之后其他线程会一直等待,性能不高。

  • 区别

synchronized与Lock的部分区别

类别 synchronized Lock
出身 Java的关键字,在JVM层面实现了对临界资源的同步互斥访问 一个类,基于jdk层面实现
锁释放 1、已经获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 有加锁就必须有释放锁,finally中unLock()释放锁使Lock对更具灵活性
锁状态 无法判断 可以判断,tryLock(),获取锁的时候锁被占用就返回false
锁类型 可重入 不可中断 非公平 可重入 可判断 可公平(默认非公平)

more
使用场景
TODO
4线程生产数据2线程数据写入实践
⚠️:该demo的多线程写磁盘的逻辑不好,有待修正,哈哈,但是3-2的测试还是有意义的;
⚠️:这个demo并没有生产意义,因为数据都是写入同一个文件,所以最终还是串行写入,磁头在各个磁盘来回寻道,也许不但不会提高效率,反而降低;
⚠️:生产中可以考虑不同线程读取不同的文件(但是磁头切换寻道可能耗时更多),然后处理数据的是别的线程,也就是获取数据和处理数据使用不同的线程,异步处理。
1、生产数据线程

public class WriteThread implements Runnable {
   

    @Override
    public void run() {
        for (int i = 0; i < 2000000; i++) {
            WriterQueue.getInstance().produce("线程:" + Thread.currentThread().getName() + "的第: " + i + " 条数据  " + UUID.randomUUID().toString() + "  123456789qwertyuiopasdfghjklzxcvbnm中文中文中文中文中文中文中文中文中文中文中文");
        }
    }

    private void sleep(int millis) throws InterruptedException {
        Thread.sleep(millis);
    }

}

2、数据队列
Condtion接口:

  • Condition中的await()方法相当于Object的wait()方法,Condition中的signal()方法相当于Object的notify()方法,Condition中的signalAll()相当于Object的notifyAll()方法
  • 例如下方代码所示,多线程写同一个缓冲区:当向队列中写入数据之后,唤醒”读线程”;当从队列读出数据之后,唤醒”写线程”;并且当缓冲区满的时候,”写线程”需要等待;当缓冲区为空时,”读线程”需要等待。
package<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值