content/references/java-chassis/en_US/general-development/reactive/index.html (428 lines of code) (raw):
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="shortcut icon" href="../../img/favicon.ico" />
<title>Reactive Programing - ServiceComb Java Chassis Developers Guide</title>
<link rel="stylesheet" href="../../css/theme.css" />
<link rel="stylesheet" href="../../css/theme_extra.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/styles/github.min.css" />
<script>
// Current page data
var mkdocs_page_name = "Reactive Programing";
var mkdocs_page_input_path = "general-development/reactive.md";
var mkdocs_page_url = null;
</script>
<script src="../../js/jquery-3.6.0.min.js" defer></script>
<!--[if lt IE 9]>
<script src="../../js/html5shiv.min.js"></script>
<![endif]-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.5.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body class="wy-body-for-nav" role="document">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side stickynav">
<div class="wy-side-scroll">
<div class="wy-side-nav-search">
<a href="../.." class="icon icon-home"> ServiceComb Java Chassis Developers Guide
</a><div role="search">
<form id ="rtd-search-form" class="wy-form" action="../../search.html" method="get">
<input type="text" name="q" placeholder="Search docs" title="Type search term here" />
</form>
</div>
</div>
<div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<ul>
<li class="toctree-l1"><a class="reference internal" href="../..">Introduction</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Getting Started</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../start/terminology/">Glossary</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../start/architecture/">Architecture</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../start/development-environment/">Development environment</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../start/first-sample/">Develop the first microservice</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Development Service Provider</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/definition/service-definition/">Service definition</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/define-contract/">Service contract definition</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/code-first/">Implicit API definition</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/swagger-annotation/">Use Swagger annotations</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/springmvc/">Develop with SpringMVC</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/jaxrs/">Develop with JAX-RS</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/transparent-rpc/">Develop with Transparent RPC</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/interface-constraints/">Interface definition and data type</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/listen-address-and-publish-address/">Service listening address and publishing address</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/thread-pool/">Thread pool</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="#">Service Configuration</a>
<ul>
<li class="toctree-l2"><a class="reference internal" href="../../build-provider/configuration/ratelimite-strategy/">Rate Limiting Policy</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../build-provider/configuration/downgrade-strategy/">Fallback Policy</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../build-provider/configuration/parameter-validator/">Parameter Validator</a>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/bootup/">Boot-up Process</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-provider/access-log-configuration/">Access Log Configuration</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Writing Service Consumer</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../build-consumer/common-configuration/">Consumer common configuration</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-consumer/using-resttemplate/">Using Rest Template</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-consumer/using-AsyncRestTemplate/">Using AsyncRestTemplate</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-consumer/develop-consumer-using-rpc/">Using with RPC</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-consumer/with-contract/">Contract</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="#">Invoke control</a>
<ul>
<li class="toctree-l2"><a class="reference internal" href="../../build-consumer/circuit-breaker/">Circuit Breaker</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../build-consumer/flow-control/">Flow Control</a>
</li>
<li class="toctree-l2"><a class="reference internal" href="../../build-consumer/fault-injection/">Fault Injection</a>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../build-consumer/3rd-party-service-invoke/">Invoke 3rd-party REST services</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Transports</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../transports/rest-over-servlet/">REST over Servlet</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../transports/rest-over-vertx/">REST over Vertx</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../transports/highway-rpc/">Highway</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../transports/http2/">HTTP2</a>
</li>
</ul>
<p class="caption"><span class="caption-text">General Development</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="../visit-sc/">Access Service Center</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../metrics/">Metrics</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../microservice-invocation-chain/">Microservice invocation chain</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../customized-tracing/">Customized-Tracing</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../local-develop-test/">Local development and testing</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../http-filter/">Http Filter</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../file-upload/">File Uploading</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../file-download/">File Downloading</a>
</li>
<li class="toctree-l1 current"><a class="reference internal current" href="./">Reactive Programing</a>
<ul class="current">
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="../dnsconfig/">DNS Custom Configuration</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../dai-li-she-zhi/">Proxy Settings</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../report-framework-version/">Report framework version</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../cross-app-invocation/">Cross-application invocation</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../secret-field/">Customized serialization and deserialization</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../context/">Using Context to pass control messages</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../produceprocess/">Return value serialization extension</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../CORS/">CORS mechanism</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../AlarmEvent/">Get fuse and instance isolation alarm event information</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../shutdown/">Shutdown gracefully</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../error-handling/">Handling exceptions</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../multienvironment/">Multi-environment isolation between microservice instances</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../thread-model/">Thread Model</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Configuration</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../config/general-config/">General config</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../config/inject-config/">Configuration injection</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Service Capability Open</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../edge/open-service/">Intruductions</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../edge/by-servicecomb-sdk/">Using Edge Service</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../edge/nginx/">Using confd and Nginx as edge services</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../edge/zuul/">Use zuul as edge services</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Service Packing and Running</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../packaging/standalone/">Standalone mode</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../packaging/web-container/">WEB container mode</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Micro Service Security</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../security/tls/">Using TLS</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../security/rsa/">Using RSA certification</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Using java chassis in Spring Boot</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../using-java-chassis-in-spring-boot/using-java-chassis-in-spring-boot/">Intruductions</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../using-java-chassis-in-spring-boot/components-for-spring-boot/">spring boot starter for java-chassis</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../using-java-chassis-in-spring-boot/java-application/">JAVA application development</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../using-java-chassis-in-spring-boot/web-application/">Web development method development</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../using-java-chassis-in-spring-boot/diff-between-java-web/">The difference between JAVA application method and Web development method</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../using-java-chassis-in-spring-boot/diff-spring-mvc/">The difference in Spring MVC mode</a>
</li>
</ul>
<p class="caption"><span class="caption-text">Handlers reference</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../references-handlers/intruduction/">Intruductions</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../references-handlers/loadbalance/">Load Balancing</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../references-handlers/publickey/">Public key authentication</a>
</li>
</ul>
<p class="caption"><span class="caption-text">FAQ</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="../../question-and-answer/question_answer/">Q & A</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../question-and-answer/faq/">FAQ</a>
</li>
<li class="toctree-l1"><a class="reference internal" href="../../question-and-answer/interface-compatibility/">Micro Service Interface Compatibility FAQ</a>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
<nav class="wy-nav-top" role="navigation" aria-label="Mobile navigation menu">
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="../..">ServiceComb Java Chassis Developers Guide</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content"><div role="navigation" aria-label="breadcrumbs navigation">
<ul class="wy-breadcrumbs">
<li><a href="../.." class="icon icon-home" alt="Docs"></a> »</li>
<li>General Development »</li>
<li>Reactive Programing</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div class="section" itemprop="articleBody">
<h2 id="simple-synchronization-mode-producer">Simple Synchronization Mode Producer:</h2>
<p>Sample code:</p>
<pre><code class="language-java">@GetMapping(path = "/hello/{name}")
public String hello(@PathVariable(name = "name") String name){
return "hello " + name;
}
</code></pre>
<p>The corresponding processing flow is as follows:</p>
<p><img alt="" src="../../assets/reactive/normalSync.png" /></p>
<p>This is the traditional typical working model. The core idea is not to block network threads, and to put the business in a separate thread (to simplify the expression, only one thread is drawn in the executor)</p>
<p>In general, this mode is not a big problem.</p>
<h2 id="nested-synchronous-call">Nested synchronous call:</h2>
<p>Not all services are handled simply, you can respond directly, you may need to call other microservices.</p>
<p>Sample code:</p>
<pre><code class="language-java">public interface Intf{
String hello(String name);
}
@GetMapping(path = "/hello/{name}")
public String hello(@PathVariable(name = "name") String name){
return "from remote: hello " + intf.hello(name);
}
</code></pre>
<p>The corresponding processing flow is as follows:</p>
<p><img alt="" src="../../assets/reactive/nestedSync.png" /></p>
<p>According to the characteristics of this process, you can see the following results:</p>
<ul>
<li>
<p>Because it is a synchronous call, the calling thread of "Microservice A" is always in the blocking wait state before "Other microservices" is not answered, and does not process any other transactions.</p>
</li>
<li>
<p>When all threads in the Executor are waiting for a remote response, all new requests can only be queued in the Queue and cannot be processed. At this point, the entire system is equivalent to stop working.</p>
</li>
<li>
<p>To increase the processing power, only increase the number of threads in the Executor, and the operating system can not increase the number of threads indefinitely. The benefit of increasing the number of threads is a parabolic model. After a specific critical value, the system handles The ability will drop, and this threshold will not be too big.</p>
</li>
<li>
<p>When the remote synchronization operation is required multiple times in the business logic, the problem will be bigger than before.</p>
</li>
</ul>
<h2 id="error-optimization-for-nested-synchronous-calls">"Error" optimization for nested synchronous calls:</h2>
<p>For the previous scenario, someone would think that throwing the "Invoke producer method" into another thread pool can solve the problem, including the following:</p>
<ul>
<li>
<p>In the producer method, mark @Async, which is responsible for throwing the call to the method into other thread pools.</p>
</li>
<li>
<p>Transferring threads through business code inside the producer method</p>
</li>
</ul>
<p>Form the following process:</p>
<p><img alt="" src="../../assets/reactive/wrongSyncOptimization.png" /></p>
<p>According to the characteristics of this process, you can see the following results:</p>
<ul>
<li>
<p>"Invoke producer method" must be returned immediately, otherwise, the Executor thread will not be released</p>
</li>
<li>
<p>"Invoke producer method" must provide a new mechanism to inform the calling process of its return value, not the final return value (currently no such mechanism)</p>
</li>
<li>
<p>Although the Executor thread is released, the Customer Executor is blocked, waiting for the remote response, the blocking state of the entire system has not changed, and there is one more thread switching.</p>
</li>
<li>
<p>The mechanism seems to have the only effect is to release the executor thread, so that the executor thread has the opportunity to process other requests, which is equivalent to the concept of quarantine, the slow processing of the business does not affect other services; but the concept of serviceComb can be directly Supported, you can configure the specified business method to monopolize the new executor, so that the whole process is the same as the "nested synchronous call", the process is simpler, and you don't need to do this at the "Invoke producer method" level.</p>
</li>
</ul>
<h2 id="pure-reactive-mechanism">Pure Reactive Mechanism</h2>
<p>Sample code:</p>
<pre><code class="language-java">public interface Intf{
CompletableFuture<String> hello(String name);
}
@GetMapping(path = "/hello/{name}")
public CompletableFuture<String> hello(@PathVariable(name = "name") String name){
CompletableFuture<String> future = new CompletableFuture<>();
intf.hello(name).whenComplete((result, exception) -> {
if (exception == null) {
future.complete("from remote: " + result);
return;
}
future.completeExceptionally(exception);
});
return future;
}
</code></pre>
<p>The corresponding processing flow is as follows:</p>
<p><img alt="" src="../../assets/reactive/pureReactive.png" /></p>
<ul>
<li>
<p>Unlike traditional processes, all functions are executed in the eventloop and no thread switching is performed.</p>
</li>
<li>
<p>After the orange arrow is finished, the occupation of this thread is completed, and it will not block waiting for response. The thread can handle other tasks.</p>
</li>
<li>
<p>After receiving the remote response, the network data drive starts to take the red arrow response process</p>
</li>
<li>
<p>As long as there are tasks, the thread will not stop, the task will be executed all the time, you can make full use of the cpu resources, and will not generate redundant thread switching, to consume the CPU unnecessarily.</p>
</li>
</ul>
<p>Because in synchronous mode, a large number of threads are needed to increase the degree of concurrency, and a large number of threads bring additional consumption of thread switching.</p>
<p>The test data shows that the reactive mode only needs to consume less than half of the CPU of the synchronous mode. And can reach or exceed the tps of the synchronous mode, and the delay is lower.</p>
<h2 id="hybrid-reactive-mechanism">Hybrid Reactive Mechanism</h2>
<p>Reactive requires that all logic executed in the eventloop does not allow any blocking actions, including not limited to wait, sleep, large loops, synchronous query DB, and so on.</p>
<p>The bottom of serviceComb is based on vertx. The vertx ecosystem has reactive drivers for various rich components such as JDBC, MQ, zooKeeper, etc. Under normal circumstances, it can meet the requirements.</p>
<p>However, in some scenarios, there are indeed some synchronization operations that cannot be avoided, such as:</p>
<ul>
<li>
<p>Private security hardened redis, only provides synchronous drive</p>
</li>
<li>
<p>More complex business operations</p>
</li>
<li>
<p>......</p>
</li>
</ul>
<p>At this point, the logic of these synchronizations can be extracted and placed in the thread pool for processing, while other parts still use the reactive process.</p>
<h2 id="some-notes-about-reactive">Some notes about reactive:</h2>
<ul>
<li>Producer:</li>
</ul>
<p>* Whether the producer uses reactive and consumer to call, there is no connection</p>
<p>* When the operation return value is the CompletableFuture type, the default operation is in reactive mode. If you need to force this operation to work in thread pool mode, you need to configure it in microservice.yaml explicitly. If an operation, its schemaId is sid, operationId For asyncQuery, you need to do the following:</p>
<pre><code>servicecomb:
executors:
Provider:
sid.asyncQuery: cse.executor.groupThreadPool
</code></pre>
<p>The cse.executor.groupThreadPool here is the default thread pool built into serviceComb, which can be arbitrarily specified by the user as its custom thread pool.</p>
<ul>
<li>Consumer:</li>
</ul>
<p>* Whether the consumer uses reactive and producer how to implement, there is no connection</p>
<p>* Currently only supports transparent RPC mode, using JDK native CompletableFuture to carry this function</p>
<p>completableFuture's when, then, etc. can be used directly</p>
<p>However, the async series of completableFuture is another thread pool to perform functions. It is not recommended.</p>
<p>Support for RxJava Observable will be added later.</p>
<p>Support for AsyncRestTemplate will be added later.</p>
</div>
</div><footer>
<div class="rst-footer-buttons" role="navigation" aria-label="Footer Navigation">
<a href="../file-download/" class="btn btn-neutral float-left" title="File Downloading"><span class="icon icon-circle-arrow-left"></span> Previous</a>
<a href="../dnsconfig/" class="btn btn-neutral float-right" title="DNS Custom Configuration">Next <span class="icon icon-circle-arrow-right"></span></a>
</div>
<hr/>
<div role="contentinfo">
<!-- Copyright etc -->
</div>
Built with <a href="https://www.mkdocs.org/">MkDocs</a> using a <a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a> provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<div class="rst-versions" role="note" aria-label="Versions">
<span class="rst-current-version" data-toggle="rst-current-version">
<span><a href="../file-download/" style="color: #fcfcfc">« Previous</a></span>
<span><a href="../dnsconfig/" style="color: #fcfcfc">Next »</a></span>
</span>
</div>
<script>var base_url = '../..';</script>
<script src="../../js/theme_extra.js" defer></script>
<script src="../../js/theme.js" defer></script>
<script src="../../search/main.js" defer></script>
<script defer>
window.onload = function () {
SphinxRtdTheme.Navigation.enable(true);
};
</script>
</body>
</html>