Aumente el rendimiento de la aplicación en 2 veces o el trabajo sin bloqueo con Elasticsearch usando corrutinas de Kotlin

Elasticsearch es un potente motor de búsqueda y un sistema de almacenamiento de documentos distribuido. Con la configuración correcta, es él quien realiza toda la magia de búsqueda, y la aplicación cliente solo necesita generar una solicitud en forma de Consulta DSL y esperar una respuesta.





, , , ? RPS, .





, , !





Elasticsearch. Docker- .





docker run --name elastic -p 9200:9200 --env-file ./docker.env -d docker.elastic.co/elasticsearch/elasticsearch:7.12.0
      
      



docker.env 2 - single-node 1 .





name:





{
    "_index": "record",
    "_type": "_doc",
    "_id": "_Erb8HkByb6IPnpUYTbS",
    "_score": 1.0,
    "_source": {
        "name": "Bob"
    }
}
      
      



Spring Boot . , , :





plugins {
    id("org.springframework.boot") version "2.4.3"
    id ("io.spring.dependency-management") version "1.0.11.RELEASE"
    id("org.jetbrains.kotlin.plugin.spring") version "1.4.20"
    kotlin("jvm") version "1.4.20"
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")

    //     elasticsearch
    implementation("org.elasticsearch:elasticsearch:$esVersion")
    implementation("org.elasticsearch.client:elasticsearch-rest-client:$esVersion")
    implementation("org.elasticsearch.client:elasticsearch-rest-high-level-client:$esVersion")
}
      
      



RestHighLevelClient





fun search(term: String): List<String> {
    val sourceBuilder = SearchSourceBuilder().apply {
         //   ID
         query(QueryBuilders.idsQuery().addIds(term))
    }
    val request = SearchRequest(indexNames, sourceBuilder).apply {
        requestCache(false) //      
    }
    
    return client.search(request, RequestOptions.DEFAULT)
        .let { mapResults(it) }
}
      
      



REST query.





:





INFO 22720 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
      
      



spring-boot-starter-web Tomcat, 1 web-. , .





RPS jmeter - . - Concurrency Thread Group. -, .





:





  • Target Concurrency: 250





  • Ramp Up Time: 30





  • Ramp-Up Steps Count: 250





, 30 , 0 250. .





- Threads VusualVM.





: Address already in use: connect. Windows - jmeter` . .





:





Arroyos en Tomcat
Tomcat

- - , http-nio-8080-exec-* (0-9) 10 199. - , max-threads 200.





, . jmeter - .





Tiempo de respuesta en Tomcat
Tomcat

, , .





, Summary Report, jmeter`:





, 22 . 7 , - 618. , 717 .





.

, , ? , :





  1. query





















: ", , . ? !". , . , elasticsearch-client , !





, . - , . CPS (Continuation-passing style), -, . Roman Elizarov - Deep dive into Kotlin coroutines.





, :





  • spring-boot-starter-web



    spring-boot-starter-webflux







  • . org.jetbrains.kotlinx:kotlinx-coroutines-core, kotlinx-coroutines-reactor kotlinx-coroutines-reactive







  • - , suspendCoroutine. , API , , , Continuation, , . :





suspendCoroutine<SearchResponse> { continuation -> //  
    //  ,        
    val callback = AsyncSearchResponseActionListener(continuation)

    //      
    client.asyncSearch().submitAsync(request, RequestOptions.DEFAULT, callback)
}
      
      



class AsyncSearchResponseActionListener(private val continuation: Continuation<SearchResponse>) :
    ActionListener<AsyncSearchResponse> {
    //     Continuatuion
    override fun onResponse(response: AsyncSearchResponse) = continuation.resume(response.searchResponse)

    //     ,    
    override fun onFailure(ex: Exception) = continuation.resumeWithException(ex)
}
      
      



  • suspendCoroutine, - , suspend.





:





INFO 9868 --- [           main] o.s.b.web.embedded.netty.NettyWebServer  : Netty started on port 8080
      
      



web- webflux, , . , , Reactor.





.

. threads:





Arroyos en Netty
Netty

, , , . , , http- Wait, , Running.





:





Tiempo de respuesta Netty
Netty

:





Entonces podemos concluir que el tiempo de ejecución de las solicitudes ha disminuido, mientras que el número total de tareas completadas y el rendimiento de la aplicación, por el contrario, han aumentado. Ahora, según jmeter, la cantidad de solicitudes para el mismo período de tiempo casi se ha duplicado, ¡de 717 a 1259 por segundo!





Salir

El ancho de banda de la aplicación juega un papel importante en los servicios de alta carga. Para maximizar la utilización de subprocesos y, como consecuencia, aumentar el rendimiento, puede migrar a una estrategia sin bloqueo en la escritura de código. Esto se puede hacer utilizando servidores de aplicaciones alternativos junto con implementaciones de comunicación asincrónica en forma de corrutinas de Kotlin.








All Articles