<?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: LEO Qin</title>
    <description>The latest articles on DEV Community by LEO Qin (@ppsrap).</description>
    <link>https://dev.to/ppsrap</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%2F1005375%2Fbb3eb76e-a67d-447c-826a-d3f34ff543dd.jpg</url>
      <title>DEV Community: LEO Qin</title>
      <link>https://dev.to/ppsrap</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ppsrap"/>
    <language>en</language>
    <item>
      <title>Four deployment strategies under Microservices</title>
      <dc:creator>LEO Qin</dc:creator>
      <pubDate>Sun, 25 Jun 2023 08:08:25 +0000</pubDate>
      <link>https://dev.to/ppsrap/four-deployment-strategies-under-microservices-1533</link>
      <guid>https://dev.to/ppsrap/four-deployment-strategies-under-microservices-1533</guid>
      <description>&lt;p&gt;Blue and green release&lt;/p&gt;

&lt;p&gt;Blue and Green Release Features&lt;/p&gt;

&lt;p&gt;Precautions for blue-green release&lt;/p&gt;

&lt;p&gt;Rolling Publishing&lt;/p&gt;

&lt;p&gt;Rolling Release Features&lt;/p&gt;

&lt;p&gt;Rollover Release Notes&lt;/p&gt;

&lt;p&gt;Grayscale publishing&lt;/p&gt;

&lt;p&gt;A/B testing &lt;/p&gt;




&lt;p&gt;Assuming you are the Twitter project manager, the new version has undergone significant changes compared to the old version, including design of service architecture, front-end UI, etc. After testing, there are no obstacles to functionality. How can users switch to the new version at this time?&lt;/p&gt;

&lt;h2&gt;
  
  
  Blue and Green Release Features
&lt;/h2&gt;

&lt;p&gt;Obviously, there is no such issue with the first release of the application, and this kind of thinking about how to release will only appear in subsequent version iterations.&lt;/p&gt;

&lt;p&gt;In the blue-green deployment, there are two systems in total: one is the service system being provided (i.e. the old version mentioned above), marked as "green"; The other set is a system ready for release, marked as "blue". Both systems are fully functional and running, but the system version and external service situation are different. The old system that is providing services to the outside world is a green system, while the newly deployed system is a blue system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kFqCE_Cj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64b05k22v76nxwry8er5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kFqCE_Cj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64b05k22v76nxwry8er5.png" alt="Image description" width="800" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The blue system does not provide external services, what is it used for?&lt;br&gt;
Used for pre release testing. If any issues are found during the testing process, they can be directly modified on the blue system without interfering with the system being used by users.&lt;br&gt;
After repeated testing, modification, and verification, the blue system determines that it meets the online standards and directly switches users to the blue system. After switching, for a period of time, the blue and green systems still coexist, but the user is already accessing the blue system. During this period, observe the working status of the blue system (new system), and if there are any problems, directly switch back to the green system.&lt;br&gt;
When it is confirmed that the blue system that provides services to the outside world is working properly and the green system that does not provide services to the outside world is no longer needed, the blue system officially becomes the new green system that provides services to the outside world. The original green system can be destroyed, releasing resources for deployment of the next blue system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Blue and Green Release Features
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The purpose of blue-green deployment is to reduce interruption time during publication and enable quick recall of publications.&lt;/li&gt;
&lt;li&gt;Only when the two systems are not coupled can there be 100% guarantee of no interference&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Precautions for blue-green release
&lt;/h2&gt;

&lt;p&gt;Blue green deployment is just one of the online strategies, and it is not a universal solution that can handle all situations. The premise for the simple and fast implementation of blue-green deployment is that the target system is very cohesive. If the target system is quite complex, careful consideration should be given to how to switch, whether the data of the two systems needs to be synchronized, and so on.&lt;br&gt;
When you switch to the blue environment, it is necessary to properly handle unfinished business and new business. If your database backend cannot handle it, it will be a relatively troublesome problem;&lt;br&gt;
It may be necessary to process "Microservices architecture application" and "traditional architecture application" at the same time. If the two are not well coordinated in the blue-green deployment, the service may still be stopped.&lt;br&gt;
It is necessary to consider the issue of synchronous migration/rollback between database and application deployment in advance.&lt;br&gt;
Blue green deployment requires infrastructure support.&lt;br&gt;
Performing blue green deployment on non isolated infrastructure (VM, Docker, etc.) poses a risk of destruction for both blue and green environments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Rolling Publishing
&lt;/h2&gt;

&lt;p&gt;Typically, one or more servers are taken out of service, updated, and put back into use. Cycle through until all instances in the cluster are updated to the new version.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aiRQ5bzg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46pxkebubmcb864enctu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aiRQ5bzg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/46pxkebubmcb864enctu.png" alt="Image description" width="800" height="309"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Release process:
&lt;/h2&gt;

&lt;p&gt;Compared to the need for a complete set of machines for blue-green publishing, rolling publishing only requires one machine (for understanding, it may actually be multiple machines). We only need to deploy some functions on this machine, and then replace the running machine, as shown in the figure above. The updated functions are deployed on Server1, and then Server1 replaces the running server. The replaced physical machine can continue to deploy the new version of Server2, Then replace the working Server2, and so on, until all servers are replaced, and the service update is complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rolling Release Features
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;This deployment method is more resource efficient compared to blue green deployment - it does not require running two clusters or twice the number of instances. 
2.We can partially deploy, for example, upgrading by only taking out 20% of the cluster at a time.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Rollback difficulties
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Rollover Release Notes
There is no confirmed feasible environment for rolling publishing. Using blue-green deployment, we can clearly know that the old version is feasible, while using rolling release, we cannot be certain.&lt;/li&gt;
&lt;li&gt;Modified the existing environment.&lt;/li&gt;
&lt;li&gt;Rolling back is difficult. For example, in a certain release, we need to update 100 instances, 10 instances at a time, and each deployment takes 5 minutes. When scrolling to the 80th instance, a problem was discovered and a rollback was needed, which was a painful and lengthy process.&lt;/li&gt;
&lt;li&gt;Sometimes, we may also dynamically scale the system. If the system automatically expands/shrinks during deployment, we also need to determine which node is using which code. Despite some automated operation and maintenance tools, they are still terrifying.&lt;/li&gt;
&lt;li&gt;Because it is a gradual update, there will be a brief inconsistency between the old and new versions when we launch the code. If there are high requirements for online scenarios, we need to consider how to ensure compatibility.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Grayscale publishing
&lt;/h2&gt;

&lt;p&gt;Grayscale publishing, also known as canary publishing. It refers to a publishing method that can smoothly transition between black and white. AB test is a grayscale publishing method that allows some users to continue using A and some users to start using B. If users have no objections to B, gradually expand the scope and migrate all users to B. Grayscale publishing can ensure the overall stability of the system, and problems can be detected and adjusted at the initial grayscale to ensure their impact. What we commonly refer to as canary deployment is also a way of grayscale publishing.&lt;/p&gt;

&lt;p&gt;Specifically, on the server, more control can be done in practical operations, such as setting a lower weight for the initial 10 updated servers, controlling the number of requests sent to these 10 servers, and gradually increasing the weight and number of requests. A smooth transition approach, this control is called "traffic segmentation".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fOWYnYU7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5yytdnd7krofuf1bb52g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fOWYnYU7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5yytdnd7krofuf1bb52g.png" alt="Image description" width="800" height="387"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Prepare the artifacts for deployment at each stage, including: build artifacts, Test script, configuration files, and deployment Manifest file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deploy the 'Canary' server into the server for testing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Remove the 'Canary' server from the load balancing list.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Upgrade the "Canary" application (eliminate existing traffic and deploy it).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test automation of applications.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Add the 'Canary' server back to the load balancing list (connectivity and health checks).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If the online usage test of 'Canary' is successful, upgrade the remaining other servers. (Otherwise, roll back)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  A/B testing
&lt;/h2&gt;

&lt;p&gt;A/B testing and blue-green release, rolling release, and canary release are completely different things.&lt;br&gt;
Blue green release, rolling release, and canary are release strategies, with the goal of ensuring the stability of the newly launched system and focusing on the bugs and hidden dangers of the new system.&lt;br&gt;
A/B testing is an effectiveness test, where multiple versions of services are available for external service at the same time. These services have undergone sufficient testing and meet the online standards, with differences but no distinction between old and new (they may have been deployed in a blue and green manner when they were launched).&lt;br&gt;
A/B testing focuses on the actual performance of different versions of services, such as conversion rates and order status.&lt;br&gt;
During A/B testing, multiple versions of services are running simultaneously online, and these services often have some differences in experience, such as different page styles, colors, and operational processes. Relevant personnel select the most effective version by analyzing the actual performance of each version of the service.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How does the anti-corrosion layer work in DDD?</title>
      <dc:creator>LEO Qin</dc:creator>
      <pubDate>Tue, 11 Apr 2023 08:26:37 +0000</pubDate>
      <link>https://dev.to/ppsrap/how-does-the-anti-corrosion-layer-work-in-ddd-5ff8</link>
      <guid>https://dev.to/ppsrap/how-does-the-anti-corrosion-layer-work-in-ddd-5ff8</guid>
      <description>&lt;p&gt;&lt;strong&gt;Gateway&lt;/strong&gt;&lt;br&gt;
In domain-driven design , there are several recommended architectures . But they all have a common feature: the outermost layer is a gateway (some are also called adapters).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Southbound and Northbound&lt;/strong&gt;&lt;br&gt;
For the gateway, it is actually divided into southbound and northbound. According to the concept of northbound and southbound, the northbound gateway corresponds to input, and the southbound gateway corresponds to output. For example, the controller interface, message queue monitoring interface, RPC interface, etc. provided by a service are all northbound gateways, which are used to accept and monitor other incoming requests; while a service calls the downstream DB, MQ producer, and http of other services. , RPC interface, etc., are all southbound gateways.&lt;/p&gt;

&lt;h2&gt;
  
  
  The role of anti-corrosion layer
&lt;/h2&gt;

&lt;p&gt;Anti-corrosion layer service&lt;br&gt;
The concept of anti-corrosion layer originally originated from DDD, and was later used in the architecture of microservices. As the name suggests, the main function of the anti-corrosion layer is to "prevent the architecture from rot". The principle of entropy increase is also applicable in the software field. With continuous iteration, the code and architecture will always tend to be chaotic. Therefore, it is necessary to consider in advance the future of this possible change and add a layer of anti-corrosion.&lt;/p&gt;

&lt;p&gt;In microservices, the anti-corrosion layer refers to extracting a single service for anti-corrosion, which is mainly used in scenarios such as system migration. In DDD, the anti-corrosion layer can actually be called an "adaptation layer", which is used to isolate upstream and downstream dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v1Af6EUS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tkyqra1cg3698ivinknh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v1Af6EUS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tkyqra1cg3698ivinknh.png" alt="Image description" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;^Anti-corrosion layer in microservices^&lt;br&gt;
Anti-corrosion layer code&lt;br&gt;
In addition to being a separate service, each microservice should also have its own anti-corrosion layer code.&lt;/p&gt;

&lt;p&gt;In large teams, many microservices will be split. Due to various reasons such as business development or architecture upgrade, it is very likely that some services and some interfaces will be upgraded at a certain time. At this time, the general approach is to find the upstream and downstream dependencies, and then notify them to use the new interface.&lt;/p&gt;

&lt;p&gt;But this brings up a problem: if an upstream service calls this interface in a large number of places in the code, the transformation cost will become very high, and this kind of transformation between systems is difficult to test and the risk is high. At this time, if the upstream service has its own adaptation layer before calling, then he only needs to change the code of the adaptation layer.&lt;/p&gt;

&lt;p&gt;And if you can’t push forward the transformation of upstream services, you can also adapt within your own services. This can be regarded as the first layer of adaptation for the northbound gateway itself, but this approach is not very recommended, and it is not conducive to your own later iterations.&lt;/p&gt;

&lt;p&gt;The recommended practice is: all southbound gateways should be adapted as much as possible, especially to call external interfaces; all northbound gateways should be as simple as possible, without adaptation, and the upstream should adapt themselves.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T2Xkxyas--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wuu1m8da8y4363fb0gk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T2Xkxyas--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wuu1m8da8y4363fb0gk.png" alt="Image description" width="203" height="573"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to write anti-corrosion layer
&lt;/h2&gt;

&lt;p&gt;The code of the anti-corrosion layer generally applies the "adapter pattern" . Generally, the interfaces exposed by other microservices will be provided to other microservices in the form of SDK. These services are generally called xxService and xxClient. The anti-corrosion layer code is a layer of packaging on this basis, generally called xxWapper and xxAdapter. Among them, Request and Response will also be included. But the workload of redefining a class by yourself is relatively large, so the original structure is generally reused directly by inheritance or combination, and when it is necessary to overwrite the field, a new field is defined on this basis, and then transferred Go to the new field.&lt;/p&gt;

&lt;p&gt;For example, there is a field called id in the original response. Suddenly one day, the upstream abandoned this field and changed it to projectId, whose business meaning is consistent with the original id. If there is no anti-corrosion layer, then all places where this response is used must modify the code. And if there is an anti-corrosion layer, you can rewrite the getId method in the anti-corrosion response and return the projectId of the parent class, without any changes in the business code.&lt;/p&gt;

&lt;p&gt;In addition, you can also define the structure you need by yourself, and use tools such as "mapStruct" to automatically convert data.&lt;/p&gt;

&lt;p&gt;Pros and Cons of Corrosion&lt;br&gt;
Writing an anti-corrosion layer also comes at a price. The biggest price is "additional development costs" . So if your upstream and downstream are relatively small and relatively stable, you can actually do without an anti-corrosion layer.&lt;/p&gt;

&lt;p&gt;In large teams, it is valuable to pay these additional development costs, because the upstream and downstream relationships of large teams are very complicated. They may not be in the same team, and they may often perform iterative upgrades. From my own experience, interface changes It happens quite often.&lt;/p&gt;

&lt;p&gt;Although we advocate not to modify the original interface, do not modify field names, method names, etc. But occasionally it is found that some things designed before are unreasonable and not conducive to long-term maintenance. If we design a v2 interface based on the new model and maintain the original v1 interface, the maintenance cost will increase. Therefore, the upstream that used the v1 interface is generally pushed to switch to v2, and then the v1 interface is offline. At this time, it is very important for the caller to have an anti-corrosion layer, which can reduce the cost of modification.&lt;/p&gt;

</description>
      <category>ddd</category>
      <category>microservices</category>
    </item>
    <item>
      <title>Troubleshooting a JVM GC Long Pause</title>
      <dc:creator>LEO Qin</dc:creator>
      <pubDate>Thu, 06 Apr 2023 05:30:30 +0000</pubDate>
      <link>https://dev.to/ppsrap/troubleshooting-a-jvm-gc-long-pause-10c8</link>
      <guid>https://dev.to/ppsrap/troubleshooting-a-jvm-gc-long-pause-10c8</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Initially, there was an abnormality in garbage collection of a certain application online, and some instances in the application experienced particularly long Full GC time, lasting about 15-30 seconds. On average, it occurred once every two weeks.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvzfbdp27hp7ofh9r628.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdvzfbdp27hp7ofh9r628.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7ajgacsrk5lxzcjrxlu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs7ajgacsrk5lxzcjrxlu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;JVM parameter configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-Xms2048M –Xmx2048M –Xmn1024M –XX:MaxPermSize=512M
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvzd0uep7s3cpruwje36.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgvzd0uep7s3cpruwje36.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Analyze GC logs.
The GC log records the execution time and result of each GC. By analyzing the GC logs, you can optimize heap and GC settings, or improve the object allocation pattern of the application.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this case, the reason for Full GC is Ergonomics, because UseAdaptiveSizePolicy is enabled, and the JVM is adapting and adjusting itself, causing Full GC.&lt;/p&gt;

&lt;p&gt;This log mainly reflects the changes before and after GC, but it is currently not clear what is causing the issue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1dy0qhviqc0htvicsv0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd1dy0qhviqc0htvicsv0.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To enable GC logs, the following JVM startup parameters need to be added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/export/log/risk_pillar/gc.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The meanings of common Young GC and Full GC logs are as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveof98dioez15ijcoior.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fveof98dioez15ijcoior.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Further investigate server performance metrics.
After obtaining the GC execution time, investigate the metrics with abnormal values at this time point through a monitoring platform. It was ultimately discovered that around 5:06 (the time of GC), CPU usage increased significantly, while SWAP showed a release of resources and a turning point in the growth of memory resources.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpbh9bkirbf948j2x24h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpbh9bkirbf948j2x24h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Did the JVM use swap?&lt;br&gt;
Was the sudden increase in CPU usage and the release of swap space to memory caused by GC?&lt;br&gt;
To verify whether the JVM used swap, we checked the process memory resource usage under the "proc" directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for i in (cd/proc;ls∣grep"[0−9]"∣awk′0 &amp;gt;100');
do awk '/Swap:/{a=a+2}END{print '"i"',a/1024"M"}' /proc/$i/smaps 2&amp;gt;/dev/null;
done | sort -k2nr | head -10 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  head -10" means to retrieve the top 10 processes with high memory usage. The first column of the output represents the process ID, and the second column represents the size of the process's swap usage. We can see that there is indeed a process using 305MB of swap space.
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4x4r2jp2hlbd9ij3rmb5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4x4r2jp2hlbd9ij3rmb5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here's a brief introduction to what swap is:&lt;/p&gt;

&lt;p&gt;Swap refers to a swapping partition or file, which is primarily used to trigger memory recycling when there is pressure on memory usage. At this point, some of the data in memory may be swapped to the swap space so that the system does not run out of memory and cause OOM or other fatal situations.&lt;/p&gt;

&lt;p&gt;When a process requests memory from the OS and finds that there is not enough, the OS will swap out temporarily unused data from memory and place it in the swap partition, a process called "swap out". When the process needs this data again and the OS finds that there is free physical memory, it will swap the data back into physical memory from the swap partition, a process called "swap in".&lt;/p&gt;

&lt;p&gt;To verify that there is a necessary relationship between GC time and swap operations, I surveyed more than a dozen machines, focusing on GC logs with long duration, and confirmed that the time points of GC and swap operations are indeed consistent.&lt;/p&gt;

&lt;p&gt;Furthermore, by checking the swappiness parameter of each instance of the virtual machine, a common phenomenon is that instances with longer Full GC are configured with the parameter vm.swappiness = 30 (a larger value means a greater tendency to use swap), while instances with relatively normal GC times are configured with the parameter vm.swappiness = 0 (maximizing the reduction of using swap).&lt;/p&gt;

&lt;p&gt;Swappiness can be set to a value between 0 and 100. It is a Linux kernel parameter that controls the relative weight of memory usage during swap.&lt;/p&gt;

&lt;p&gt;swappiness=0: maximum use of physical memory, followed by swap space&lt;br&gt;
swappiness=100: active use of swap partition, and timely swapping of data on memory to swap space&lt;/p&gt;

&lt;p&gt;The corresponding physical memory usage rate and swap usage are shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjo9p4bgeu073pgxuqif.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgjo9p4bgeu073pgxuqif.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbrajmrfhe3phr2y6cwd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbrajmrfhe3phr2y6cwd.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Problem analysis:&lt;br&gt;
When the memory usage reaches the waterline (vm.swappiness), Linux will move some temporarily unused memory data to the disk swap to free up more available memory space. When data in the swap area is needed, it will be moved back into memory. When the JVM performs garbage collection, it needs to traverse the used memory in the corresponding heap partition. If part of the heap content has been swapped to the swap space during GC, when it is traversed, it needs to be swapped back to memory. Because it requires accessing the disk, it will be much slower than accessing physical memory, and the GC pause time will be very long, which can cause Linux to lag behind in swapping area recovery (memory-to-disk swapping operations are very CPU and system IO intensive). In high-concurrency/QPS services, this lag can be fatal (STW).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Questions:&lt;br&gt;
Will the JVM with swap enabled always take longer to perform GC?&lt;br&gt;
If the JVM dislikes swap so much, why doesn't it prohibit its use?&lt;br&gt;
What is the working mechanism of swap? This server has 8GB of physical memory and uses swap memory, which means that physical memory is not enough, but according to the free command, the actual physical memory usage does not seem to be that high, while Swap has occupied nearly 1G.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zw5twluiaacgi0x3zjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3zw5twluiaacgi0x3zjt.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;free：The amount of remaining memory excluding buff/cache&lt;/p&gt;

&lt;p&gt;shared：Shared memory.&lt;/p&gt;

&lt;p&gt;buff/cache：The number of memory used for buffering and caching (frequently caused by programs frequently accessing files).&lt;/p&gt;

&lt;p&gt;available：The real amount of available remaining memory.&lt;/p&gt;

&lt;p&gt;5.Further thoughts&lt;br&gt;
One may consider what it means to disable swap disk cache.&lt;/p&gt;

&lt;p&gt;In fact, it is not necessary to be so radical. It is important to note that the world is never simply binary, and everyone tends to choose somewhere in between. Some lean towards 0, while others towards 1.&lt;/p&gt;

&lt;p&gt;Clearly, with regard to the swap issue, the JVM can choose to minimize its usage to reduce its impact. It is important to understand how Linux memory recovery works in order to reduce any possible concerns.&lt;/p&gt;

&lt;p&gt;Let's first take a look at how swap is triggered.&lt;/p&gt;

&lt;p&gt;Linux triggers memory recovery in two scenarios: when there is not enough free memory during memory allocation, and when a daemon process (kswapd process) periodically checks the system's memory and initiates memory recovery when the available memory drops below a specific threshold.&lt;/p&gt;

&lt;p&gt;6.Speculation&lt;br&gt;
Due to the short intervals of GC in real-time services, the things in memory have no chance to be swapped to swap and are immediately recovered during GC. When GC is performed, data from the swap partition does not need to be swapped back to physical memory, but is calculated entirely based on memory, which makes it much faster. The selection strategy for which memory data to swap into the swap partition is likely to be similar to the LRU algorithm (least recently used).&lt;/p&gt;

&lt;p&gt;Lowering the heap size appropriately can also solve the problem.&lt;/p&gt;

&lt;p&gt;This also indirectly indicates that when deploying Java services on Linux systems, memory allocation should not simply be large and comprehensive, but should consider the memory requirements of the JVM for Java permanent generation, Java heap (young and old generations), thread stack, and Java NIO in different scenarios.&lt;/p&gt;

&lt;p&gt;7.Conclusion&lt;br&gt;
In conclusion, when swap and GC occur at the same time, GC time will be very long, causing serious JVM stuttering, and in extreme cases, service crashes.&lt;/p&gt;

&lt;p&gt;The main reason is that when the JVM performs GC, it needs to traverse the used memory of the corresponding heap partition. If a part of the heap has been swapped to swap at the time of GC, it must be swapped back to memory when traversing this part. In more extreme cases, if another part of the heap in memory needs to be swapped to swap due to insufficient memory space, the entire heap partition will be written to SWAP in turn during the process of traversing the heap partition, resulting in excessively long GC time. The size of the swap area should be limited online, and if the swap usage ratio is high, it should be investigated and resolved. When appropriate, the heap size can be lowered or physical memory can be added.&lt;/p&gt;

&lt;p&gt;Therefore, when deploying Java services on Linux systems, it is important to be cautious about memory allocation.&lt;/p&gt;

</description>
      <category>jvm</category>
      <category>java</category>
      <category>springcloud</category>
    </item>
    <item>
      <title>A Bloody Case Caused by a Thread Pool Rejection Strategy</title>
      <dc:creator>LEO Qin</dc:creator>
      <pubDate>Tue, 10 Jan 2023 15:16:35 +0000</pubDate>
      <link>https://dev.to/ppsrap/a-bloody-case-caused-by-a-thread-pool-rejection-strategy-15j5</link>
      <guid>https://dev.to/ppsrap/a-bloody-case-caused-by-a-thread-pool-rejection-strategy-15j5</guid>
      <description>&lt;h2&gt;
  
  
  Conduct an in-depth analysis of the full gc problem of the online business of the inventory center, and combine the solution method and root cause analysis of this problem to implement the solution to such problems
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Event review&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Starting from 7.27, the main site, distributors, and other business parties began to report that orders occasionally timed out. We began to analyze and troubleshoot the cause of the problem, and were shocked to find that full gc occasionally occurred online, as shown in the figure below. If you continue to let it go, it will inevitably affect the core link and user experience of Yanxuan trading orders, resulting in transaction losses. The development of the inventory center responds quickly, actively investigates and solves problems, and handles problems in the bud to avoid capital losses.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ma0qcvbr79dssuwzhhl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1ma0qcvbr79dssuwzhhl.png" alt="Image description" width="800" height="226"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feiqznrwil8sx5eej8nmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feiqznrwil8sx5eej8nmt.png" alt="Image description" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88200hhuhdrwu4kseq31.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F88200hhuhdrwu4kseq31.png" alt="Image description" width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Emergency hemostasis&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For frequent full gc, based on experience, we boldly guess that it may be caused by some interfaces generating large objects and calling them frequently. In an emergency, first ensure that the core functions of the system are not affected, and then troubleshoot the problem. Generally, there are three methods, as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Expansion&lt;br&gt;
There are generally two ways to expand capacity, one is to increase the size of the heap memory, and the other is to expand the capacity of the application machine; in essence, it is to delay the number and frequency of full gc occurrences, try to ensure the core business, and then troubleshoot the problem.&lt;br&gt;
Limiting&lt;br&gt;
Current limiting can be regarded as a kind of service degradation. Current limiting is to limit the input and output traffic of the system to achieve the purpose of protecting the system. Generally, current limiting can be done at the proxy layer and application layer.&lt;br&gt;
Reboot&lt;br&gt;
It is a relatively violent method. A little carelessness may cause data inconsistency. It is not recommended unless necessary.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our application current limit is aimed at the application interface level. Since we don't know the specific cause of the problem and the problem is still in the bud, we don't directly limit the current, but directly expand the capacity and restart it incidentally. We temporarily expanded the heap memory in an emergency, increased the heap memory size of some machines from 6g to 22g, and restarted the application to make the configuration parameters take effect.&lt;br&gt;
After emergency expansion of some machines (73 and 74) on 7.27, we can find that full gc did not occur within 2 days after the expansion, providing us with fault tolerance time for further investigation;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p6u9iyyjpygfrdu2hyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6p6u9iyyjpygfrdu2hyq.png" alt="Image description" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Problem analysis&lt;/strong&gt;&lt;br&gt;
3.1 Status Quo Challenges&lt;/p&gt;

&lt;p&gt;Since there is no OOM, there is no on-site memory snapshot, so it is difficult to determine the cause of the problem, and the main inventory service involves too much logic (the core business logic has more than 100,000 lines of code, which are all running daily), and the business logic is complex. The volume is large, and there are a small number of slow requests, which increases the difficulty of troubleshooting. Since there is no relatively complete infrastructure, we do not have a global call monitoring platform to observe what happened to the application before and after the full gc. We can only find the truth of the problem by analyzing the link call situation on the problem machine.&lt;/p&gt;

&lt;p&gt;3.2 Appearance reasons&lt;br&gt;
Essentially, we need to look at what the application system does when full gc occurs, that is to say, what is the last straw that crushes the camel?&lt;br&gt;
We have done a lot of analysis on the application logs at the time point before the full gc occurred, combined with the slow SQL analysis, as long as the business frequently operates the [internal and external procurement and outbound] business for a period of time, the system will trigger a full gc, and the time point is relatively consistent, so , the preliminary judgment may be caused by internal and external procurement and outbound business operations. Through the analysis of the business code analysis, it is found that the inventory change will load 100,000 pieces of data into the memory after intervention and interception, with a total of about 300M.&lt;br&gt;
In this regard, we urgently contacted the dba on 7.28 to migrate part of the business data to other databases to avoid further impact on the business, and then optimize the business process in the future! !&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyom4qdywlkq3y15jr1sq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyom4qdywlkq3y15jr1sq.png" alt="Image description" width="800" height="429"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4hdz1j2a8eitpczjklk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi4hdz1j2a8eitpczjklk.png" alt="Image description" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the migration, we found that there was no full gc on the day, and no business feedback interface timed out. On July 29, we found that machine 73 (upgraded configuration) did not have full gc, and machine 154 continued to have full gc on July 29. Observe every The amount of memory that can be reclaimed by a gc is not much, which means that the memory is not released in time, and there may be a leak problem!&lt;/p&gt;

&lt;p&gt;3.3 Root cause of the problem&lt;br&gt;
At that time, we dumped the memory snapshots many times, and did not find similar problems. Fortunately, the 155 machine was upgraded last (the backup machine, mainly used to process timing tasks, and was reserved for reference and comparison), which brought us closer to the root of the problem. because.&lt;br&gt;
To further analyze the reason, we analyzed the heap memory snapshot of one of the machines (155), and found an interesting phenomenon, that is, there are a large number of threads blocking waiting threads;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5vxizvsgugo7izionnl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fo5vxizvsgugo7izionnl.png" alt="Image description" width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsslkui1ilb77s09afub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhsslkui1ilb77s09afub.png" alt="Image description" width="800" height="476"&gt;&lt;/a&gt;&lt;br&gt;
Each blocked thread will hold about 14M of memory. It is these threads that cause the memory leak. So far we have finally found the cause of the problem and verified our guess, that is, a memory leak has occurred!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3.4 Cause Analysis&lt;/strong&gt;&lt;br&gt;
3.4.1 Business Description&lt;br&gt;
From 4.2, we locate the problem code. In order to facilitate our understanding of this part of the business (pull the SKU quantity information from the database, every 500 SKUs form a SyncTask, and then cache it in redis for use by other business parties, execute it every 5 minutes ) to give an overview.&lt;/p&gt;

&lt;p&gt;3.4.2 Business code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3.4.2 Business code
@Override
public String sync(String tableName) {
    // Generate data version number
    DateFormat dateFormat = new SimpleDateFormat("YYYYMMdd_HHmmss_SSS");
    // Start the Leader thread to complete execution and monitoring
    String threadName = "SyncCache-Leader-" + dateFormat.format(new Date());
    Runnable wrapper = ThreadHelperUtil.wrap(new PrimaryRunnable(cacheVersion, tableName,syncCachePool));
    Thread core = new Thread(wrapper, threadName); // Create new thread
    core.start();
    return cacheVersion;
}
private static class PrimaryRunnable implements Runnable {
    private String cacheVersion;
    private String tableName;
    private ExecutorService syncCachePool;
    public PrimaryRunnable(String cacheVersion, String tableName,ExecutorService syncCachePool) {
        this.cacheVersion = cacheVersion;
        this.tableName = tableName;
       this.syncCachePool = syncCachePool;
    }
    @Override
    public void run() {
       ....
        try {
            exec();
            CacheLogger.doFinishLog(cacheVersion, System.currentTimeMillis() - leaderStart);
        } catch (Throwable t) {
            CacheLogger.doExecErrorLog(cacheVersion, System.currentTimeMillis() - leaderStart, t);
        }
    }
    public void exec() {
        // Query data and build synchronization task
        List&amp;lt;SyncTask&amp;gt; syncTasks = buildSyncTask(cacheVersion, tableName);
        // Synchronize task submission thread pool
        Map&amp;lt;SyncTask, Future&amp;gt; futureMap = Maps.newHashMap();
        for (SyncTask task: syncTasks) {
            futureMap.put(task, syncCachePool.submit(new Runnable() {
                @Override
                public void run() {
                    task.run();
                }
            }));
        }

        for (Map.Entry&amp;lt;SyncTask, Future&amp;gt; futureEntry: futureMap.entrySet()) {
            try {
                futureEntry.getValue().get(); // Block getting synchronization task results
            } catch (Throwable t) {
                CacheLogger.doFutureFailedLog(cacheVersion, futureEntry.getKey());
                throw new RuntimeException(t);
            }
        }
    }
}
/**
 * Deny Policy Class
 */
private static class RejectedPolicy implements RejectedExecutionHandler {
    static RejectedPolicy singleton = new RejectedPolicy();
    private RejectedPolicy() {
    }
    @Override
    public void rejectedExecution(Runnable runnable, ThreadPoolExecutor executor) {
        if (runnable instanceof SyncTask) {
            SyncTask task = (SyncTask) runnable;
            CacheLogger.doRejectLog(task);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The current queue size is 1000, and the maximum number of threads is 20, which means that the thread pool can handle at least 51w data, and the current number of sku is about 54w. If the task takes time, all remaining tasks may be put into the queue, and there may be threads Insufficient pool queue condition. Insufficient queue size will trigger the rejection policy. Currently, the rejection policy in our project is similar to DiscardPolicy (when a new task is submitted, it will be discarded directly without any notification to you)&lt;/p&gt;

&lt;p&gt;From the analysis here, we summarize the causes of the problem as follows:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;First, when the task is submitted to the thread pool and the rejection policy is triggered, the state of the FutureTask is in the New state, and calling the get() method will reach LockSupport.park(this), blocking the current thread and causing a memory leak;&lt;/li&gt;
&lt;li&gt;The reason is that the thread pool is not used properly. There are two main problems. One is that there is a problem with the selection of the rejection strategy. Abnormal termination (in addition, there is no need to obtain task results in the project, and there is actually no need to use the submit method to submit tasks).&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;3.4.4 Getting to the bottom of it&lt;br&gt;
After analyzing this point, we can say that we have found the cause of the problem, that is to say, when FutureTask gets the execution result, it calls LockSupport.park(this) and blocks the main thread. When will the current thread be woken up? Let's move on to the code.&lt;br&gt;
That is, when the task currently assigned by the existing worker thread Worker is executed, it will call the getTask() method of the Worker class to get the task from the blocking queue, and execute the run() method of the task. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Problem solving&lt;/strong&gt;&lt;br&gt;
By optimizing the thread pool configuration and business process l, such as increasing the size of the thread pool queue, repairing the rejection strategy, optimizing the business process to avoid large objects, and executing tasks at off-peak times, a series of combined measures ensure the stable execution of tasks.&lt;br&gt;
4.1 Thread pool configuration optimization&lt;br&gt;
Increase thread pool queue size, fix rejection policy&lt;/p&gt;

&lt;p&gt;4.1.1 Modify the deny policy&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;The main purpose of the custom rejection strategy used in the project is to print out the task information contained in the rejection task, such as skuId, etc., and then manually update it to prevent abnormal inventory data provided to other services;&lt;/li&gt;
&lt;li&gt;From the previous article, we have already seen that the runnable type is FutureTask, so the if judgment in the picture will never be established. This custom rejection policy is like the default rejection policy in the thread pool. I will give you any notice, relatively speaking, there is a certain risk, because we did not know that this task would be discarded when we submitted it, which may cause data loss);&lt;/li&gt;
&lt;li&gt;After the modification, when the queue is full, the rejection strategy will be triggered immediately and an exception will be thrown, so that the parent thread will not be blocked all the time to obtain the result of the FutureTask.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;ps: The Runnable in the thread is currently packaged in the project. If you use native classes, you can obtain the rejected tasks in the rejection policy through reflection. Just get the rejection task information, you can ignore it.&lt;/p&gt;

&lt;p&gt;4.1.2 Increase the queue size&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;The maximum number of threads in the thread pool is 20, the queue size is 1000, the current number of skus is 54w, and each task has 500 skuIds. If the execution time of each task is a little longer, it can only process 51w skus at most, plus 3 tasks Common thread pool, set the queue size to 3000;&lt;/li&gt;
&lt;li&gt;After the queue is adjusted, it can prevent some SKUs from not synchronizing the inventory data to the cache in time.
4.2 Business Process Optimization
Optimize the large objects that appear in internal and external procurement to reduce the problem of requesting 300M large objects each time. At the same time, the execution time of the three scheduled tasks in the public thread pool is staggered to avoid mutual interference between tasks after the increase in sku.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;Summarize precipitation
5.1 Summary of full gc solutions&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;What should we do when encountering frequent full gc online? The first thing that comes to mind is to deal with it urgently first, and then analyze the reasons. We have three options for emergency treatment: restart, current limit, and capacity expansion.&lt;/li&gt;
&lt;li&gt;Secondly, clarify the direction. Generally speaking, there are two main reasons for full gc, one is application resource allocation problems, and the other is program problems. In terms of resource configuration, we need to check whether the jvm parameter configuration is reasonable; most of the full gc is caused by program problems. There are two main reasons. One is that the program has large objects, and the other is that there is a memory leak;&lt;/li&gt;
&lt;li&gt;The most important point is to analyze the dump file, but to ensure that the memory snapshot at the time of the incident is obtained, the analysis software can use MAT and VisualVM. For the problem we encountered, we can actually use jstack to obtain all the threads of the current process for analysis;&lt;/li&gt;
&lt;li&gt;In case of full gc, a timely alarm should be issued to avoid the development response lagging behind the business. In addition, in practice, we should set JVM parameters reasonably, so as to avoid full gc as much as possible. In this troubleshooting, we also adjusted the jvm parameters, which will be discussed later Corresponding articles have been published.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;5.2 Notes on using thread pool&lt;/p&gt;

&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;If you do not need to obtain task results synchronously, try to use the execute method to submit tasks, and handle exceptions carefully to prevent frequent destruction and creation of threads;&lt;/li&gt;
&lt;li&gt;If you need to use the submit method to submit the task, try to use the timeout method to obtain the result synchronously, so as to avoid the problem of memory leak caused by the continuous blocking problem;&lt;/li&gt;
&lt;li&gt;Use the rejection policy carefully, and be familiar with the possible problems in the combination of the rejection policy and the thread submission method. For example, DiscardPolicy and submit methods may cause blocking and waiting for results;&lt;/li&gt;
&lt;li&gt;Thread pool threads must be recognizable, that is, they have their own naming rules to facilitate troubleshooting.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;

</description>
      <category>watercooler</category>
    </item>
  </channel>
</rss>
