The framework I am using here is Dubbo version 2.7.8. Its underlying thread pool management is handled through a class called ExecutorRepository. This class is responsible for creating and managing the thread pool in Dubbo. Through this extended interface, we can Obtain the busin

2024/05/1807:49:34 technology 1314

Dubbo is an excellent microservice framework. It is widely used in the Internet, finance and insurance, technology companies, manufacturing, retail logistics and other fields due to its high performance, simplicity and ease of use, and easy expansion. Today, the Dubbo framework has become a commonly used technical framework in Internet development.

In the DUBBO framework, when the client calls the server, after the request arrives at the server, there will be a dedicated thread pool to receive parameters and process them. Therefore, if you want to implement Dubbo's thread pool monitoring, you need to first understand the underlying implementation principle of dubbo for the business thread pool.

View of the thread pool at the bottom of Dubbo

The framework I am using here is Dubbo version 2.7.8. Its underlying management of the thread pool is handled through a class called ExecutorRepository. This class is responsible for creating and managing the thread pool in Dubbo. , through this extended interface, we can obtain the business thread pool object that Dubbo is actually running. The specific processing logic part of

is as follows:

package org.idea.Dubbo.monitor.core.collect;import org.apache.dubbo.common.extension.ExtensionLoader;import org.apache.dubbo.common.threadpool.manager.DefaultExecutorRepository ;import org.apache.dubbo.common.threadpool.manager.ExecutorRepository;import java.lang.reflect.Field;import java.util.concurrent.Concurrentmap;import java.util.concurrent.ExecutorService;import java.util.concurrent. ThreadPoolExecutor;/** * @Author idea * @Date created in 7:04 pm 2022/6/29 */public class DubboThreadPoolCollector {/** * Get Dubbo's thread pool* @return */public static ThreadPoolexecutor getDubboThreadPoolInfo(){ //dubbo thread pool number monitoring try {ExtensionLoaderExecutorRepository executorRepositoryExtensionLoader = ExtensionLoader.getExtensionLoader(ExecutorRepository.class);DefaultExecutorRepository defaultExecutorRepository = (DefaultExecutorRepository) executorRepositoryExtensionLoader.getDefaultExtension();Field dataField =tension defaultExecutor Repository.getClass().getDeclaredField("data");dataField .setAccessible(true);ConcurrentMapString, ConcurrentMapInteger, ExecutorService data = (ConcurrentMapString, ConcurrentMapInteger, ExecutorService) dataField.get(defaultExecutorRepository);ConcurrentMapInteger, ExecutorService executorServiceConcurrentMap = data.get("java.util.concurrent.ExecutorService");//Get to the default thread pool model ThreadPoolExecutor threadPoolExecutor = (ThreadPoolExecutor) executorServiceConcurrentMap.get(9090);return ThreadPoolExecutor;} catch (Exception e) {e.printStackTrace();}return null;}}

Okay, now we know how to The information of the Dubbo thread pool is viewed in real time in the code. The next thing to do is how to collect the data of these thread pools and report it. Finally, the reported and stored data will be displayed in the form of statistical chart .

Below we will display the data according to the three steps of collection, reporting and display .

collects data

There are two ways to collect data, as follows:

  • starts a scheduled task in the background, and then queries the parameter information of the thread pool every second.
  • Every time a request arrives at the provider, it checks some thread pool parameter information.

There may be some differences in the data collected using two different modes. The following is a comparison of the two methods:

Statistical method implementation difficulty Possible problems scheduled task collection data Data in the execution gap of simple scheduled tasks cannot be collected , leading to data distortion. The arrival of request is a little more complicated to collect data. Data needs to be collected every time a request is made, which will cause a certain loss in performance.

Through analysis of actual business scenarios, in fact, the performance loss of the second method to the application is very small or even negligible, so it is more appropriate to use this method to collect data.

Let’s take a look at how to implement data collection in this way.

First we need to define a filter ourselves:

package org.idea.dubbo.monitor.core.filter;import org.apache.dubbo.common.constants.CommonConstants;import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.rpc.*;import org.idea.dubbo.monitor.core.DubboMonitorHandler;import java.util.concurrent.ThreadPoolExecutor;import static org.idea.dubbo.monitor.core.config.CommonCache.DUBBO_INFO_STORE_CENTER ;/** * @Author idea * @Date created in 2:33 pm 2022/7/1 */@Activate(group = CommonConstants.PROVIDER)public class DubboRecordFilter implements Filter {@Overridepublic Result invoke(Invoker? invoker, Invocation invocation ) throws RpcException {ThreadPoolExecutor threadPoolExecutor = DubboMonitorHandler.getDubboThreadPoolInfo();//Query statistics thread pool when requesting. When the request volume is too small, this data may not be accurate, but if the request volume is large, it will be close to accurate. DUBBO_INFO_STORE_CENTER.reportInfo(9090,threadPoolExecutor.getActiveCount(),threadPoolExecutor.getQueue().size());return invoker.invoke(invocation);}}

The code for DUBBO_INFO_STORE_CENTER is as follows:

and in dubbo's spi configuration file Specify them in:

dubboRecordFilter=org.idea.dubbo.monitor.core.filter.DubboRecordFilter

When the provider adds this filter, if a request reaches the server, the collection operation will be triggered through this filter.

package org.idea.dubbo.monitor.core.collect;import org.idea.dubbo.monitor.core.bo.DubboInfoStoreBO;import java.util.Map;import java.util.concurrent.ConcurrentHashMap;/** * Dubbo data Storage Center * * @Author idea * @Date created in 11:15 AM 2022/7/1 */public class DubboInfoStoreCenter {private static MapInteger, DubboInfoStoreBO dubboInfoStoreBOMap = new ConcurrentHashMap();public void reportInfo(Integer port, Integer corePoolSize, Integer queueLength) {synchronized (this) {DubboInfoStoreBO dubboInfoStoreBO = ​​dubboInfoStoreBOMap.get(port);if (dubboInfoStoreBO != null) {boolean hasChange = false;int currentMaxPoolSize = dubboInfoStoreBO.getMaxCorePoolSize();int currentMaxQueueLength = dubboInfoSt oreBO.getMaxCorePoolSize();if (corePoolSize currentMaxPoolSize) {dubboInfoStoreBO.setMaxCorePoolSize(corePoolSize);hasChange = true;}if (queueLength currentMaxQueueLength) {dubboInfoStoreBO.setMaxQueueLength(queueLength);hasChange = true;}if (hasChange) {dubboInfoStoreBOMap.put(port, dubboInfoSt oreBO);} } else {dubboInfoStoreBO = ​​new DubboInfoStoreBO();dubboInfoStoreBO.setMaxQueueLength(queueLength);dubboInfoStoreBO.setMaxCorePoolSize(corePoolSize);dubboInfoStoreBOMap.put(port, dubboInfoStoreBO);}}} public DubboInfoStoreBO getInfo(Integer port){return du bboInfoStoreBOMap.get(port );}public void cleanInfo(Integer port) {dubboInfoStoreBOMap.remove(port);}}

Note that this collection class will only collect data for a period of time, and then clear and reset it periodically. The reason why

does this is to use this Map to count the maximum number of threads and the maximum number of queues within a specified time, and then clear these peak data after they are reported to the storage center.

Regarding the definition of the DubboInfoStoreCenter object, I placed it in a class called CommonCache, as follows:

package org.idea.dubbo.monitor.core.config;import org.idea.dubbo.monitor.core.store.DubboInfoStoreCenter ;/** * @Author idea * @Date created in 12:15 pm 2022/7/1 */public class CommonCache {public static DubboInfoStoreCenter DUBBO_INFO_STORE_CENTER = new DubboInfoStoreCenter();}

So in the above filter, we Its collection interface can be called directly through static class reference.

Okay, now overall, we have implemented the real-time collection of thread pool data in the filter, and temporarily stored it in a Map table. The data of this map mainly records the threads within a certain period of time. The peak value of the pool is used by the collector role.

So next, let’s take a look at the main operations performed by the reporter module.

Before reporting data

before reporting data, the most important thing is to choose the appropriate storage component. First of all, the volume of data reported is not large. We can set the collection time to 15 seconds, and then design a reporting task to collect data from the dubbo thread pool every 15 seconds. Then it needs to be reported 5760 times a day. Assuming that one record is stored in one report, the data that needs to be stored in one day is not particularly large.

and the stored service data actually does not need to be retained for too long. Generally, one week of storage is enough, so in the end I chose redis for storage in this area.

The framework I am using here is Dubbo version 2.7.8. Its underlying thread pool management is handled through a class called ExecutorRepository. This class is responsible for creating and managing the thread pool in Dubbo. Through this extended interface, we can Obtain the busin - DayDayNews

There are three main data fields that we actually pay attention to every time. I have organized their definitions into the following object:

package org.idea.dubbo.monitor.core.bo;/** * @Author idea * @Date created in 7:17 PM 2022/6/29 */public class ThreadInfoBO {private Integer activePoolSize;private Integer queueLength;private long saveTime;public Integer getActivePoolSize() {return activePoolSize;}public void setActivePoolSize(Integer activePoolSize) {this.activePoolSize = activePoolSize ;}public Integer getQueueLength() {return queueLength;}public void setQueueLength(Integer queueLength) {this.queueLength = queueLength;}public long getSaveTime() {return saveTime;}public void setSaveTime(long saveTime) {this.saveTime = saveTime ;}@Overridepublic String toString() {return "ThreadInfoBO{" +", queueLength=" + queueLength +", saveTime=" + saveTime +'}';}}

will then start a thread task, every 15 seconds A round of data reporting actions will be performed:

package org.idea.dubbo.monitor.core.report;import com.alibaba.fastjson.JSON;import org.idea.dubbo.monitor.core.bo.DubboInfoStoreBO;import org.idea .dubbo.monitor.core.bo.ThreadInfoBO;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.Beans.factory.annotation.Autowired;import org.springframework.boot.CommandLineRunner;import java. util.concurrent.ExecutorService;import java.util.concurrent.Executors;import static org.idea.dubbo.monitor.core.config.CommonCache.DUBBO_INFO_STORE_CENTER;/** * @Author idea * @Date created in 12:13 PM 2022 /7/1 */public class DubboInfoReportHandler implements CommandLineRunner {@Autowiredprivate IReportTemplate reportTemplate;private static final Logger LOGGER = LoggerFactory.getLogger(DubboInfoReportHandler.class);public static ExecutorService executorService = Executors.newFixedThreadPool(1);public static int DUBBO_PORT = 9090 ;@Overridepublic void run(String... args) throws Exception {executorService.submit(new Runnable() {@Overridepublic void run() {while (true) {try {Thread.sleep(10000);DubboInfoStoreBO dubboInfoStoreBO = ​​DUBBO_INFO_STORE_CENTER. getInfo(DUBBO_PORT);ThreadInfoBO threadInfoBO = new ThreadInfoBO();threadInfoBO.setSaveTime(System.currentTimeMillis());if(dubboInfoStoreBO!=null){threadInfoBO.setQueueLength(dubboInfoStoreBO.getMaxQueueLength());threadInfoBO.setActivePoolSize(dubboInfoStore BO.getMaxCorePoolSize ());} else { //This situation may be that there is no traffic request to the provider during the corresponding time period threadInfoBO.setQueueLength(0);threadInfoBO.setActivePoolSize(0);}//Here is the reporting device reporting data to redis reportTemplate.reportData(JSON.toJSONString(threadInfoBO));//After reporting, the data in the map will be reset here DUBBO_INFO_STORE_CENTER.cleanInfo(DUBBO_PORT);LOGGER.info(" =========== Dubbo Thread pool data reporting =========== ");} catch (Exception e) {e.printStackTrace();}}}});}}

Please pay attention to the threads of Dubbo applications The pool reporting task should wait until the entire SpringBoot application is successfully started before triggering, otherwise there may be some data inaccuracies. So when defining the Bean initialization thread, I chose the CommandLineRunner interface.

If you look at the code carefully, you may see such a type:

org.idea.dubbo.monitor.core.report.IReportTemplate

This class defines the basic actions of the data reporter. The following is its specific code:

package org.idea. dubbo.monitor.core.report;/** * Report template* * @Author idea * @Date created in 7:10 pm 2022/6/29 */public interface IReportTemplate {/** * Report data* * @return * /boolean reportData(String json);}

implementation class part is as follows:

package org.idea.dubbo.monitor.core.report.impl;import org.idea.dubbo.monitor.core.report.IReportTemplate;import org. idea.qiyu.cache.redis.service.IRedisService;import org.springframework.stereotype.Component;import javax.annotation.Resource;import java.time.LocalDate;import java.util.concurrent.TimeUnit;/** * @Author idea * @Date created in 7:12 pm 2022/6/29 */@Componentpublic class RedisTemplateImpl implements IReportTemplate {@Resourceprivate IRedisService redisService;private static String queueKey = "dubbo:threadpool:info:";@Overridepublic boolean reportData(String json ) {redisService.lpush(queueKey + LocalDate.now().toString(), json);redisService.expire(queueKey + LocalDate.now().toString(),7, TimeUnit.DAYS);return true;}}

Here I use a list structure to store these data indicators, and set an expiration time of one week. The final format after being stored in redis is as follows:

The framework I am using here is Dubbo version 2.7.8. Its underlying thread pool management is handled through a class called ExecutorRepository. This class is responsible for creating and managing the thread pool in Dubbo. Through this extended interface, we can Obtain the busin - DayDayNews

Data display

Okay, now we have completed the thread pool For monitoring, you only need to design a management console to extract the reported data from the cache and display the page. The logic implemented by

is relatively simple. You only need to define the data structure required for the statistical chart, and then return it in the controller layer. For example, as shown in the following figure:

The framework I am using here is Dubbo version 2.7.8. Its underlying thread pool management is handled through a class called ExecutorRepository. This class is responsible for creating and managing the thread pool in Dubbo. Through this extended interface, we can Obtain the busin - DayDayNews

The final effect displayed is as follows:

The framework I am using here is Dubbo version 2.7.8. Its underlying thread pool management is handled through a class called ExecutorRepository. This class is responsible for creating and managing the thread pool in Dubbo. Through this extended interface, we can Obtain the busin - DayDayNews

With the number of requests for the dubbo interface Changes occur, and the statistical chart can show the data changes of dubbo thread pool. If you want the statistical chart to display data in real-time, you only need to write a regularly called function in js.

Here I am using the echart plug-in for chart rendering. I choose the simplest statistical chart type. You can also choose the appropriate model for rendering on echart’s official website according to your specific needs. Here is echart Official website address: https://echarts.apache.org/examples/zh/index.html

Original link: https://mp.weixin.qq.com/s/3rYAQaZq4OcegtHugJjNow

technology Category Latest News