javascript
Spring,Reactor和ElasticSearch:使用伪造的测试数据进行标记
在上一篇文章中,我們創建了一個從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:使用伪造的测试数据进行标记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 安卓手机悬浮窗怎么开(安卓手机悬浮)
- 下一篇: 为什么Spring的健康状况会再次下降,