在上一篇文章中,我们创建了一个从ElasticSearch的API到Reactor的Mono的简单适配器,如下所示:

import reactor.core.publisher.Mono;private Mono indexDoc(Doc doc) {//...
}

现在,我们希望以受控的并发级别运行此方法数百万次。 基本上,我们想看看索引代码在负载下的行为,对其进行基准测试。

用jFairy伪造数据

首先,我们需要一些美观的测试数据。 为此,我们将使用方便的jFairy库。 我们将索引的文档是一个简单的POJO:

@Value
class Doc {private final String username;private final String json;
}

生成逻辑包装在Java类中:

import io.codearte.jfairy.Fairy;
import io.codearte.jfairy.producer.person.Address;
import io.codearte.jfairy.producer.person.Person;
import org.apache.commons.lang3.RandomUtils;@Component
class PersonGenerator {private final ObjectMapper objectMapper;private final Fairy fairy;private Doc generate() {Person person = fairy.person();final String username = person.getUsername() + RandomUtils.nextInt(1_000_000, 9_000_000);final ImmutableMap<String, Object> map = ImmutableMap.<String, Object>builder().put("address", toMap(person.getAddress())).put("firstName", person.getFirstName()).put("middleName", person.getMiddleName()).put("lastName", person.getLastName()).put("email", person.getEmail()).put("companyEmail", person.getCompanyEmail()).put("username", username).put("password", person.getPassword()).put("sex", person.getSex()).put("telephoneNumber", person.getTelephoneNumber()).put("dateOfBirth", person.getDateOfBirth()).put("company", person.getCompany()).put("nationalIdentityCardNumber", person.getNationalIdentityCardNumber()).put("nationalIdentificationNumber", person.getNationalIdentificationNumber()).put("passportNumber", person.getPassportNumber()).build();final String json = objectMapper.writeValueAsString(map);return new Doc(username, json);}private ImmutableMap<String, Object> toMap(Address address) {return ImmutableMap.<String, Object>builder().put("street", address.getStreet()).put("streetNumber", address.getStreetNumber()).put("apartmentNumber", address.getApartmentNumber()).put("postalCode", address.getPostalCode()).put("city", address.getCity()).put("lines", Arrays.asList(address.getAddressLine1(), address.getAddressLine2())).build();}}

相当无聊的代码实际上确实很酷。 每次运行它时,它都会生成随机但合理的JSON,如下所示:

{"address": {"street": "Ford Street","streetNumber": "32","apartmentNumber": "","postalCode": "63913","city": "San Francisco","lines": ["32 Ford Street","San Francisco 63913"]},"firstName": "Evelyn","middleName": "","lastName": "Pittman","email": "pittman@mail.com","companyEmail": "evelyn.pittman@woodsllc.eu","username": "epittman5795354","password": "VpEfFmzG","sex": "FEMALE","telephoneNumber": "368-005-109","dateOfBirth": "1917-05-14T16:47:06.273Z","company": {"name": "Woods LLC","domain": "woodsllc.eu","email": "contact@woodsllc.eu","vatIdentificationNumber": "30-0005081","url": "http://www.woodsllc.eu"},"nationalIdentityCardNumber": "713-79-5185","nationalIdentificationNumber": "","passportNumber": "jVeyZLSt3"
}

整齐! 不幸的是,没有记录jFairy是否是线程安全的,因此以防万一在实际代码中,我正在使用ThreadLocal 。 好的,所以我们只有一个文档,但是我们需要数百万个文档! 使用for -loop太过时了。 您会告诉我们无限的随机人流吗?

import reactor.core.scheduler.Scheduler;
import reactor.core.scheduler.Schedulers;private final Scheduler scheduler = Schedulers.newParallel(PersonGenerator.class.getSimpleName());Mono<Doc> generateOne() {return Mono.fromCallable(this::generate).subscribeOn(scheduler);
}Flux<Doc> infinite() {return generateOne().repeat();
}

generateOne()Mono<Doc>包装阻塞的generate()方法。 另外, generate()parallel Scheduler上运行。 为什么? 事实证明,jFairy在单个内核上还不够快(很多随机数生成,表查找等),因此我不得不并行化数据生成。 通常不应该是一个问题。 但是,当生成伪造数据的速度比接触外部服务器的响应式应用程序慢时,它会告诉您有关基于Netty的Spring Web-flux(!)的性能。

同时调用ElasticSearch

好的,拥有无数好看的假测试数据流,我们现在要在ElasticSearch中对其进行索引。

@PostConstruct
void startIndexing() {index(1_000_000, 1_000);
}private void index(int count, int maxConcurrency) {personGenerator.infinite().take(count).flatMap(this::indexDocSwallowErrors, maxConcurrency).window(Duration.ofSeconds(1)).flatMap(Flux::count).subscribe(winSize -> log.debug("Got {} responses in last second", winSize));
}private Mono<IndexResponse> indexDocSwallowErrors(Doc doc) {return indexDoc(doc).doOnError(e -> log.error("Unable to index {}", doc, e)).onErrorResume(e -> Mono.empty());
}

当应用程序启动时,它将启动对一百万个文档的索引编制。 注意,告诉Reactor(它与RxJava相同)多么容易,它应该调用多达1000个对ElasticSearch的并发请求。 每秒我们计算收到的回复数:

Got 2925 responses in last second
Got 2415 responses in last second
Got 3336 responses in last second
Got 2199 responses in last second
Got 1861 responses in last second

不错! 特别是当您考虑到有多达一千个并发HTTP请求并且我们的应用程序启动时几乎只有30个线程峰值(!),好吧,这是localhost <-> localhost ,有罪! 但是,我们实际上如何知道所有这些呢? 日志记录很好,但是到了二十一世纪,我们可以做得更好! 监视将是下一批的主题。

源代码可在react reactive-elastic-search分支中的github.com/nurkiewicz/elastic-flux中获得。

翻译自: https://www.javacodegeeks.com/2018/01/spring-reactor-elasticsearch-bechmarking-fake-test-data.html

Spring,Reactor和ElasticSearch:使用伪造的测试数据进行标记相关推荐

  1. Spring,Reactor和ElasticSearch:从回调到React流

    Spring 5(以及Boot 2,将在数周内到货)是一次革命. 不是" XML上的注释 "或" Java上的注释类 "的革命. 这是一个真正的革命性框架,可以 ...

  2. Spring,Reactor和ElasticSearch:从回调到反应流

    Spring 5(以及Boot 2,在数周之内到货)是一次革命. 不是" XML上的注释 "或" Java上的注释类 "的革命. 这是一个真正的革命性框架,可以 ...

  3. Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询

    运行环境:JDK 7 或 8,Maven 3.0+ 技术栈:SpringBoot 1.5+,ElasticSearch 2.3.2 本文提纲 一.ES 的使用场景 二.运行 springboot-el ...

  4. Elasticsearch学习(3) spring boot整合Elasticsearch的原生方式

    前面我们已经介绍了spring boot整合Elasticsearch的jpa方式,这种方式虽然简便,但是依旧无法解决我们较为复杂的业务,所以原生的实现方式学习能够解决这些问题,而原生的学习方式也是E ...

  5. Elasticsearch实战篇——Spring Boot整合ElasticSearch

    2019独角兽企业重金招聘Python工程师标准>>> 当前Spring Boot很是流行,包括我自己,也是在用Spring Boot集成其他框架进行项目开发,所以这一节,我们一起来 ...

  6. io.realm:rea_使Java具有响应性的框架和工具包:RxJava,Spring Reactor,Akka和Vert.x概述...

    io.realm:rea 如今,人们需要具有高用户体验的高响应性,交互式应用程序,这通常意味着要处理异步性,尤其是当应用程序涉及高负载,实时数据和多用户时. 由于Java是一种固有的语言,它固有地支持 ...

  7. 使Java具有响应性的框架和工具包:RxJava,Spring Reactor,Akka和Vert.x概述

    如今,人们需要具有高用户体验的高响应性,交互式应用程序,这通常意味着处理异步性,尤其是当这些应用程序涉及高负载,实时数据和多用户时. 由于Java是一种固有的支持命令式编程风格的面向对象语言,因此异步 ...

  8. Spring Reactor教程

    在RESTful服务的世界中,实际上实际上是在幕后进行许多工作,我们通常必须在应用程序中进行很多处理,而实际上并不会影响需要发送给真实用户的响应. 可以被动地做出这些业务决策,以便它们对与应用程序交互 ...

  9. 使用Spring Reactor Core进行分散收集

    我在使用Netflix Rx-Java库方面有良好的工作经验,并且以前曾写过关于使用Rx-Java和Java 8 CompletableFuture解决分散式问题的博客. 在这里,我想探索使用Spri ...

最新文章

  1. OpenCV仿射变换 SURF特征点描述合辑
  2. 渗透知识-SSRF漏洞
  3. javaweb设置servlet
  4. ITK:向索引添加偏移量
  5. 局域网内访问mysql数据库
  6. Linux文件系统选择
  7. 每日一练:完全恢复与不完全恢复概念
  8. 《天天数学》连载37:二月六日
  9. 最新出炉|也许你该看看这份的模型数据
  10. brew update:以下未跟踪的工作树文件将被合并覆盖:
  11. MongoDB聚合运算之mapReduce函数的使用(11)
  12. 作为“创业导师”的天使投资人
  13. unity广告投放技巧_是否需要快速投放动画广告系列? 只要在Unity中做到
  14. 搅拌摩擦焊有限元仿真分析学习笔记
  15. 恢复通讯录显示服务器开小差,手机通讯录误删除怎么恢复?教你几招一看就会...
  16. R语言里的非线性模型:多项式回归、局部样条、平滑样条、 广义相加模型GAM分析
  17. 在线广告原理:从橱窗到互联网广告核心交易模式——RTB
  18. what's the 头寸
  19. 学习ES6-什么是ES6?为什么要学习ES6?
  20. 【阶段总结】《非结构化信息分析应用与实践(筹)》

热门文章

  1. Java压缩技术(五) GZIP相关——浏览器解析
  2. Java NIO系列教程(四) Scatter/Gather
  3. 漫画:什么是人工智能
  4. publiccms按照指定显示的日期格式,格式化日期的写法
  5. springboot项目不加端口号也可以访问项目的方法
  6. myeclipse 2016 ci3破解教程(含软件下载)
  7. IP暴露接口IP白名单设置
  8. mfc定义了变量仍提示未定义标识符_JavaScript-变量
  9. python cmd闪退_使用cmd python模块时,如何使程序正常崩溃?
  10. 用Python开始机器学习(4:KNN分类算法)