<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: gökhan</title>
    <description>The latest articles on DEV Community by gökhan (@previousdeveloper).</description>
    <link>https://dev.to/previousdeveloper</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F672347%2F4c73ca4d-ba9a-4ed5-9c38-b856077c706e.jpeg</url>
      <title>DEV Community: gökhan</title>
      <link>https://dev.to/previousdeveloper</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/previousdeveloper"/>
    <language>en</language>
    <item>
      <title>Couchbase Java Client Tuning</title>
      <dc:creator>gökhan</dc:creator>
      <pubDate>Thu, 22 Jul 2021 21:42:47 +0000</pubDate>
      <link>https://dev.to/previousdeveloper/couchbase-java-client-tuning-27em</link>
      <guid>https://dev.to/previousdeveloper/couchbase-java-client-tuning-27em</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DVKzeT8t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1296/1%2Arop3esZsaVmmm7aatyk2tQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DVKzeT8t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1296/1%2Arop3esZsaVmmm7aatyk2tQ.png" alt="couchbase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Couchbase is the most popular NoSQL database. In Trendyol, we are using Couchbase to store all microservice data. (Products metadata, Stock, Personalization)&lt;/p&gt;

&lt;p&gt;We will talk about how to tune our &lt;a href="https://github.com/couchbase/couchbase-java-client"&gt;couchbase java client&lt;/a&gt; for more throughput, low memory, and less latency.&lt;/p&gt;

&lt;p&gt;When we profile our application couchbase client has consumed %8.3 cpu when it is idle and SimplePauseDetector create 3 worker thread for tracking latency stats.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C_YWYDUD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2A9IHLNM-km2ZnozXEKjXoyA.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--C_YWYDUD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2A9IHLNM-km2ZnozXEKjXoyA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1&lt;/strong&gt;. Couchbase library is using LatencyUtils. It tracks your application latency status. In Trendyol we use Newrelic for tracking our application latency. We don’t need to track for internal couchbase latency so we disabled for Runtime Metrics Collector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DefaultCouchbaseEnvironment._builder_().runtimeMetricsCollectorConfig(DefaultMetricsCollectorConfig._disabled_())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt;. Another latency tracker is Network Latency Metrics Collector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DefaultCouchbaseEnvironment._builder_().networkLatencyMetricsCollectorConfig(DefaultLatencyMetricsCollectorConfig._disabled_())
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;3&lt;/strong&gt;. Increase configPollFloorInterval value it’s default 50ms.&lt;/p&gt;

&lt;p&gt;This property gets couchbase configuration from the server to detect cluster changes in a timely fashion config polling from couchbase cluster topology. We changed this value as 200ms&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DefaultCouchbaseEnvironment._builder_().configPollFloorInterval(200)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Lqpk_gTD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2Am2GegRlahwP3qZjuzMsMNw.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Lqpk_gTD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2Am2GegRlahwP3qZjuzMsMNw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4&lt;/strong&gt;. Decrease Key-Value timeout (default 2500ms) we generally use 500 ms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5&lt;/strong&gt;. Couchbase java client is using the netty framework for async network operation. You can find more details &lt;a href="https://blog.couchbase.com/couchbase-java-sdk-internals/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For a more high throughput scenario on Linux Netty provides a way to use edge-triggered epoll instead of going through JVM NIO. This provides better throughput, lower latency, and less garbage. We changed it to Linux native transport.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DefaultCouchbaseEnvironment.Builder builder = DefaultCouchbaseEnvironment._builder_();EpollEventLoopGroup elg = new EpollEventLoopGroup(DefaultCouchbaseEnvironment._IO\_POOL\_SIZE_, new DefaultThreadFactory("cb-io", false));ShutdownHook hook = new IoPoolShutdownHook(elg);builder.ioPool(elg, hook);
builder.kvIoPool(elg, hook);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6&lt;/strong&gt;. Disable operation tracing server and client duration. This property provides scope management.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ax73PBKW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2AOGWepq2O1QJAhQ%255C_cUyWZYQ.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ax73PBKW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2AOGWepq2O1QJAhQ%255C_cUyWZYQ.png"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DefaultCouchbaseEnvironment._builder_().operationTracingEnabled(false)
.operationTracingServerDurationEnabled(false)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;7&lt;/strong&gt;. Couchbase is using the &lt;a href="https://github.com/FasterXML/jackson"&gt;jackson&lt;/a&gt; library for encoding and decoding. It doesn’t use the &lt;a href="https://github.com/FasterXML/jackson-modules-base/tree/master/afterburner"&gt;afterburner&lt;/a&gt; module by default.&lt;/p&gt;

&lt;p&gt;The module will add dynamic bytecode generation for standard Jackson POJO serializers and deserializers, eliminating majority of remaining data binding overhead.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bp0p-quE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2APuEFrz2%255C_s5bHP7-q9wL0pw.png" class="article-body-image-wrapper"&gt;&lt;img alt="" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bp0p-quE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%255C%2APuEFrz2%255C_s5bHP7-q9wL0pw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Use always JsonObject for low latency and memory. JsonObject provides us a generic model to parse to pojo class.&lt;/p&gt;

&lt;p&gt;Note: Couchbase &lt;a href="https://issues.couchbase.com/issues/?jql=project+%3D+JCBC+AND+fixVersion+%3D+3.0.0-beta.2"&gt;3.0.0-beta.2&lt;/a&gt; client has uses it by default. &lt;a href="https://issues.couchbase.com/browse/JCBC-1487"&gt;https://issues.couchbase.com/browse/JCBC-1487&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8&lt;/strong&gt;. Use RxJava for batching operations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Observable
        ._from_(ids)
        .observeOn(Schedulers._io_())
        .flatMap(asyncBucket::get)
        .timeout(_BULK\_TIMEOUT\_IN\_MS_, _MILLISECONDS_)
        .onErrorResumeNext(throwable -&amp;gt; {
            _LOGGER_.warn("Data fetched from replica");
            return Observable._from_(ids).flatMap(id -&amp;gt; asyncBucket.getFromReplica(id, ReplicaMode._FIRST_)).timeout(_BULK\_TIMEOUT\_IN\_MS_, TimeUnit._MILLISECONDS_);
        })
        .toList();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Measuring Performance
&lt;/h2&gt;




&lt;p&gt;We can now run all test just one Kubernetes pod it is 1 Gb memory and no limit for cpu. Before start running the test, we warm up the container.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;No Tuning Java Client Result&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ObvrYcnA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AzlZkIiyHMp8GN-38OPNXfg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ObvrYcnA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AzlZkIiyHMp8GN-38OPNXfg.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With standard No Tuning Client, we get around &lt;strong&gt;4328.13&lt;/strong&gt; operations per second. Max rpm is &lt;strong&gt;265k&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Average response time 8*&lt;em&gt;.41&lt;/em&gt;* ms and 3.5 GB read&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wLNKXwig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AiswYCiXa9eY2kUhKUU6qRQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wLNKXwig--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AiswYCiXa9eY2kUhKUU6qRQ.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vjpwziXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AaV5mBQaAtIECICr7K_HXBw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vjpwziXz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AaV5mBQaAtIECICr7K_HXBw.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Tuning Java Client Result&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--D_Qc_Cpd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2Azx-v4ZrpIZU7leJwxWhy0w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D_Qc_Cpd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2Azx-v4ZrpIZU7leJwxWhy0w.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With Tuning Client, we get around &lt;strong&gt;5203.49&lt;/strong&gt; operations per second.&lt;/p&gt;

&lt;p&gt;Max rpm is &lt;strong&gt;313k&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Average response time &lt;strong&gt;6.12&lt;/strong&gt; ms and &lt;strong&gt;4,21&lt;/strong&gt; GB read&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zVX9ifH8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AiZXcgadl3Epij4-LqVT-Rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zVX9ifH8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AiZXcgadl3Epij4-LqVT-Rw.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Resource usage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qAO1Dkjy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AJB5D8hmeXiq6TSkabUe7wg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qAO1Dkjy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/2000/1%2AJB5D8hmeXiq6TSkabUe7wg.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As a result, There are several tuning options for your case. Tuning Couchbase Java Client more than 100k rpm handle with low latency, low cpu, and memory.&lt;/p&gt;

&lt;p&gt;Original article: &lt;a href="https://medium.com/trendyol-tech/couchbase-java-client-tuning-b98690f5a675"&gt;https://medium.com/trendyol-tech/couchbase-java-client-tuning-b98690f5a675&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>couchbase</category>
      <category>jvm</category>
    </item>
  </channel>
</rss>
