慎用Reactor Notify机制

本文探讨了Reactor模式中的Notify机制存在的问题,包括默认采用ACE_Pipe带来的安全隐患及性能瓶颈,以及Notify机制本身设计上的缺陷。建议在安全敏感环境中谨慎使用,并提供了改进措施。
 

8               慎用Reactor Notify机制

Reactor的模式,有一种辅助的通知机制,Notify机制,简单说就是通过通知发起者调用notify函数,notify的消息被保存在一个管道中,handle_event的处理中会检查这个管道中是否有通知数据,如果有就根据通知的消息,会根据默认的通知消息的类型去调用hanle_input等函数。

从设计的角度将,这个机制无疑是非常优美的,对于Reactor,它在IO驱动以外,提供了一种新的驱动方式。但是从实现角度来讲,这个机制要慎用。原因有两个。

8.1               ACE Reactor的默认Notify方式采用的是ACE_Pipe

ACE Reactor的默认Notify方式采用的是ACE_Pipe,所以ACE_PipeWindowsLinux平台上的问题,Notify机制把ACE_Pipe的缺陷一个不少的继承了,而且问题更加多。

  /**

   * Contains the ACE_HANDLE the ACE_Dev_Poll_Reactor is listening

   * on, as well as the ACE_HANDLE that threads wanting the attention

   * of the ACE_Dev_Poll_Reactor will write to.

   */

  ACE_Pipe notification_pipe_;

原来在调试ACE代码的时候,我发现只要一使用Reactor,即使只使用定时器(除非明确不使用Notify),防火墙都会报警有监听端口。我曾经对此大惑不解,直到读了ACE的这部分原代码。这样做的坏处有很多。第一个是由于采用的阻塞IO。速度会慢很多,第二个由于是单线程的处理,如果在压力极大的情况下,可能出现死锁的问题。比如在有大规模的Notify的情况下,发送缓冲区很可能会被塞满(由于是单线程,这时不会有接受者),同时由于为了简化,ACE_Pipe采用的IO是阻塞的,所以会导致整个程序死锁。第三就是这样的情况下ACE_Pipe会打开一个临时的端口,而且会绑定所有的IP0.0.0.0),如果对于一个安全要求严格的的场景,这个将是一个不可饶恕的错误。【注】

 

【注】在一个安全要求严格的环境下,这个临时端口轻则可以让你的服务器轻易陷于崩溃,重则可以让你整个网络被黑客攻陷。

 

不过还好的是ACE的开发者估计自己也意识倒了这个麻烦。所以提供了另外一种消息队列的方式。你可以通过定义ACE_HAS_REACTOR_NOTIFICATION_QUEUE的宏编译ACE,这样ACE将不使用ACE_Pipe作为Notify消息的管道,而使用一个自己的内存队列保存Notify消息,这个队列是动态扩展的。而且由于是内存操作,性能方面没有太大问题。

 

大体位置在重复编译的卫哨后面,#include /**/ "ace/pre.h"前面。保证这个宏起到作用。

#ifndef ACE_CONFIG_LINUX_H

#define ACE_CONFIG_LINUX_H

 

//使用内存队列作为Notify Queue

#define ACE_HAS_REACTOR_NOTIFICATION_QUEUE

 

#include /**/ "ace/pre.h"

 

这个问题到5.6.1还是存在的,估计由于历史的原因,在很长一段时间也不会得到解决。

8.2               考虑不周的Reactor Notify机制

同上,这也应该是一个BUGReactor Notify的代码有考虑不周的地方。Notify机制的本质是提供了一条消息队列让大家有方法调用Event_handler,但是存在一种可能,在你的通知消息在消息队列的时候,Event_hanlder由于后面的处理可能已经handle_close了。但是ACEdispatch_notify却没有考虑倒这一点(或者说考虑倒这一点也不好解决)。

ACE_Select_Reactor_Notify::dispatch_notify函数的代码。

int

ACE_Select_Reactor_Notify::dispatch_notify (ACE_Notification_Buffer &buffer)

{

…………

ACE_Event_Handler *event_handler =

        buffer.eh_;

 

      bool const requires_reference_counting =

        event_handler->reference_counting_policy ().value () ==

        ACE_Event_Handler::Reference_Counting_Policy::ENABLED;

    //如果此时这个ACE_Event_Handler已经被handle_close了,你如何是好。。。。

      switch (buffer.mask_)

        {

        case ACE_Event_Handler::READ_MASK:

        case ACE_Event_Handler::ACCEPT_MASK:

          result = event_handler->handle_input (ACE_INVALID_HANDLE);

这个bug5.6.1还没有解决。我觉得这个问题是可以解决的(暂时还没有提BUG),但是得到解决的方式却仍然是低效的方案(还记得取消定时器的那个缺陷吗)。

如果你仔细看过上面的几节,你也许会发出惊叹,啊,又是Reactor Notify?对,又是它。看起来我好像一直在和ACENotify机制在做对,但它的确让我吃了无数的苦头。这部分的设计的确有一点画蛇添足的感觉,而且由于跨平台性等原因,这个东东的实现一直不如意。其实自己使用ACE的实现(比如Message_Queue)一套这样的机制应该是易如反掌的事情。不苛求了。

如果你用不到Notify机制,最好在ACE_Reactor初始化的时候彻底关闭Notify机制。很多Reactor的初始化函数都提供了关闭notify pipe的方式。比如ACE_Select_Reactor_Topen函数的disable_notify_pipe参数。当其为1的时候表示关闭notify 管道。

//disable_notify_pipe参数为1时表示关闭NOTIFY PIPE,不使用他

template <class ACE_SELECT_REACTOR_TOKEN> int

ACE_Select_Reactor_T<ACE_SELECT_REACTOR_TOKEN>::open

  (size_t size,

   int restart,

   ACE_Sig_Handler *sh,

   ACE_Timer_Queue *tq,

   int disable_notify_pipe, /*  等于==1表示关闭notify机制 */

   ACE_Reactor_Notify *notify)

 

D:\application\JDK\bin\java.exe -ea -Djacoco-agent.destfile=D:\workspace\CCC00910_MspAI_GCH\target/jacoco.exec -Didea.test.cyclic.buffer.size=1048576 -javaagent:C:\Users\itw00668\AppData\Roaming\JetBrains\IdeaIC2024.2\plugins\mysql-log-plugin\lib\mysql-log-agent-1.1.jar -Dmysql-log.projectId=9bad6d48 "-javaagent:D:\application\Idea\Idea2024\IntelliJ IDEA Community Edition 2024.2.3\lib\idea_rt.jar=55990:D:\application\Idea\Idea2024\IntelliJ IDEA Community Edition 2024.2.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Users\itw00668\.m2\repository\org\junit\platform\junit-platform-launcher\1.8.2\junit-platform-launcher-1.8.2.jar;C:\Users\itw00668\.m2\repository\org\junit\platform\junit-platform-engine\1.8.2\junit-platform-engine-1.8.2.jar;C:\Users\itw00668\.m2\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;C:\Users\itw00668\.m2\repository\org\junit\platform\junit-platform-commons\1.8.2\junit-platform-commons-1.8.2.jar;C:\Users\itw00668\.m2\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;D:\application\Idea\Idea2024\IntelliJ IDEA Community Edition 2024.2.3\lib\idea_rt.jar;D:\application\Idea\Idea2024\IntelliJ IDEA Community Edition 2024.2.3\plugins\junit\lib\junit5-rt.jar;D:\application\Idea\Idea2024\IntelliJ IDEA Community Edition 2024.2.3\plugins\junit\lib\junit-rt.jar;D:\application\JDK\jre\lib\charsets.jar;D:\application\JDK\jre\lib\deploy.jar;D:\application\JDK\jre\lib\ext\access-bridge-64.jar;D:\application\JDK\jre\lib\ext\cldrdata.jar;D:\application\JDK\jre\lib\ext\dnsns.jar;D:\application\JDK\jre\lib\ext\jaccess.jar;D:\application\JDK\jre\lib\ext\jfxrt.jar;D:\application\JDK\jre\lib\ext\localedata.jar;D:\application\JDK\jre\lib\ext\nashorn.jar;D:\application\JDK\jre\lib\ext\sunec.jar;D:\application\JDK\jre\lib\ext\sunjce_provider.jar;D:\application\JDK\jre\lib\ext\sunmscapi.jar;D:\application\JDK\jre\lib\ext\sunpkcs11.jar;D:\application\JDK\jre\lib\ext\zipfs.jar;D:\application\JDK\jre\lib\javaws.jar;D:\application\JDK\jre\lib\jce.jar;D:\application\JDK\jre\lib\jfr.jar;D:\application\JDK\jre\lib\jfxswt.jar;D:\application\JDK\jre\lib\jsse.jar;D:\application\JDK\jre\lib\management-agent.jar;D:\application\JDK\jre\lib\plugin.jar;D:\application\JDK\jre\lib\resources.jar;D:\application\JDK\jre\lib\rt.jar;D:\workspace\CCC00910_MspAI_GCH\target\test-classes;D:\workspace\CCC00910_MspAI_GCH\target\classes;D:\application\Maven\repository\ZA21\bee-starter-logging\5.10.21\bee-starter-logging-5.10.21.jar;D:\application\Maven\repository\ZA21\bee-commons\5.10.21\bee-commons-5.10.21.jar;D:\application\Maven\repository\com\fasterxml\jackson\core\jackson-databind\2.13.3\jackson-databind-2.13.3.jar;D:\application\Maven\repository\com\fasterxml\jackson\core\jackson-annotations\2.13.3\jackson-annotations-2.13.3.jar;D:\application\Maven\repository\com\fasterxml\jackson\core\jackson-core\2.13.3\jackson-core-2.13.3.jar;D:\application\Maven\repository\javax\validation\validation-api\2.0.1.Final\validation-api-2.0.1.Final.jar;D:\application\Maven\repository\ZA21\bee-statement\5.10.21\bee-statement-5.10.21.jar;D:\application\Maven\repository\ZA21\bee-encryption\1.0.0\bee-encryption-1.0.0.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-log4j2\2.7.2\spring-boot-starter-log4j2-2.7.2.jar;D:\application\Maven\repository\org\apache\logging\log4j\log4j-slf4j-impl\2.17.2\log4j-slf4j-impl-2.17.2.jar;D:\application\Maven\repository\org\apache\logging\log4j\log4j-api\2.17.2\log4j-api-2.17.2.jar;D:\application\Maven\repository\org\apache\logging\log4j\log4j-core\2.17.2\log4j-core-2.17.2.jar;D:\application\Maven\repository\org\apache\logging\log4j\log4j-jul\2.17.2\log4j-jul-2.17.2.jar;D:\application\Maven\repository\org\slf4j\jul-to-slf4j\1.7.36\jul-to-slf4j-1.7.36.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-configuration-processor\2.7.2\spring-boot-configuration-processor-2.7.2.jar;D:\application\Maven\repository\com\auth0\java-jwt\3.18.2\java-jwt-3.18.2.jar;D:\application\Maven\repository\com\fasterxml\jackson\datatype\jackson-datatype-jsr310\2.13.3\jackson-datatype-jsr310-2.13.3.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter\2.7.2\spring-boot-starter-2.7.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot\2.7.2\spring-boot-2.7.2.jar;D:\application\Maven\repository\jakarta\annotation\jakarta.annotation-api\1.3.5\jakarta.annotation-api-1.3.5.jar;D:\application\Maven\repository\org\yaml\snakeyaml\2.0\snakeyaml-2.0.jar;D:\application\Maven\repository\LT32\logsdk\2.5.5\logsdk-2.5.5.jar;D:\application\Maven\repository\org\springframework\spring-web\5.3.22\spring-web-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-beans\5.3.22\spring-beans-5.3.22.jar;D:\application\Maven\repository\io\opentracing\opentracing-api\0.33.0\opentracing-api-0.33.0.jar;D:\application\Maven\repository\io\opentracing\contrib\opentracing-spring-web\4.1.0\opentracing-spring-web-4.1.0.jar;D:\application\Maven\repository\io\opentracing\contrib\opentracing-web-servlet-filter\0.4.0\opentracing-web-servlet-filter-0.4.0.jar;D:\application\Maven\repository\io\opentracing\opentracing-util\0.33.0\opentracing-util-0.33.0.jar;D:\application\Maven\repository\io\opentracing\opentracing-noop\0.33.0\opentracing-noop-0.33.0.jar;D:\application\Maven\repository\io\jaegertracing\jaeger-client\1.8.1\jaeger-client-1.8.1.jar;D:\application\Maven\repository\io\jaegertracing\jaeger-core\1.8.1\jaeger-core-1.8.1.jar;D:\application\Maven\repository\io\jaegertracing\jaeger-tracerresolver\1.8.1\jaeger-tracerresolver-1.8.1.jar;D:\application\Maven\repository\io\opentracing\contrib\opentracing-tracerresolver\0.1.8\opentracing-tracerresolver-0.1.8.jar;D:\application\Maven\repository\org\aspectj\aspectjweaver\1.9.7\aspectjweaver-1.9.7.jar;D:\application\Maven\repository\ZA21\bee-starter-tracer\5.10.21\bee-starter-tracer-5.10.21.jar;D:\application\Maven\repository\LT31\09\unique-sql-hashid\9.0.0\unique-sql-hashid-9.0.0.jar;D:\application\Maven\repository\org\apache\commons\commons-lang3\3.12.0\commons-lang3-3.12.0.jar;D:\application\Maven\repository\LT31\09\shindata-druid\1.1.15\shindata-druid-1.1.15.jar;D:\application\Maven\repository\commons-io\commons-io\2.11.0\commons-io-2.11.0.jar;D:\application\Maven\repository\ZA21\bee-starter-management\5.10.21\bee-starter-management-5.10.21.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-actuator-autoconfigure\2.7.2\spring-boot-actuator-autoconfigure-2.7.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-actuator\2.7.2\spring-boot-actuator-2.7.2.jar;D:\application\Maven\repository\ZA21\bee-starter-metrics\5.10.21\bee-starter-metrics-5.10.21.jar;D:\application\Maven\repository\io\opentelemetry\opentelemetry-api-metrics\1.9.1-alpha\opentelemetry-api-metrics-1.9.1-alpha.jar;D:\application\Maven\repository\io\opentelemetry\opentelemetry-api\1.9.1\opentelemetry-api-1.9.1.jar;D:\application\Maven\repository\io\opentelemetry\opentelemetry-context\1.9.1\opentelemetry-context-1.9.1.jar;D:\application\Maven\repository\com\google\code\findbugs\jsr305\3.0.2\jsr305-3.0.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-web\2.7.2\spring-boot-starter-web-2.7.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-json\2.7.2\spring-boot-starter-json-2.7.2.jar;D:\application\Maven\repository\com\fasterxml\jackson\datatype\jackson-datatype-jdk8\2.13.3\jackson-datatype-jdk8-2.13.3.jar;D:\application\Maven\repository\com\fasterxml\jackson\module\jackson-module-parameter-names\2.13.3\jackson-module-parameter-names-2.13.3.jar;D:\application\Maven\repository\org\springframework\spring-webmvc\5.3.22\spring-webmvc-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-aop\5.3.22\spring-aop-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-context\5.3.22\spring-context-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-expression\5.3.22\spring-expression-5.3.22.jar;D:\application\Maven\repository\com\cvicse\embedded\spring-boot-starter-inforsuite\10.0.2.5-CMB01\spring-boot-starter-inforsuite-10.0.2.5-CMB01.jar;D:\application\Maven\repository\org\springframework\cloud\spring-cloud-starter-openfeign\3.1.1\spring-cloud-starter-openfeign-3.1.1.jar;D:\application\Maven\repository\org\springframework\cloud\spring-cloud-starter\3.1.1\spring-cloud-starter-3.1.1.jar;D:\application\Maven\repository\org\springframework\cloud\spring-cloud-context\3.1.1\spring-cloud-context-3.1.1.jar;D:\application\Maven\repository\org\springframework\security\spring-security-rsa\1.0.10.RELEASE\spring-security-rsa-1.0.10.RELEASE.jar;D:\application\Maven\repository\org\springframework\cloud\spring-cloud-openfeign-core\3.1.1\spring-cloud-openfeign-core-3.1.1.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-aop\2.7.2\spring-boot-starter-aop-2.7.2.jar;D:\application\Maven\repository\io\github\openfeign\form\feign-form-spring\3.8.0\feign-form-spring-3.8.0.jar;D:\application\Maven\repository\io\github\openfeign\form\feign-form\3.8.0\feign-form-3.8.0.jar;D:\application\Maven\repository\commons-fileupload\commons-fileupload\1.4\commons-fileupload-1.4.jar;D:\application\Maven\repository\org\springframework\cloud\spring-cloud-commons\3.1.1\spring-cloud-commons-3.1.1.jar;D:\application\Maven\repository\org\springframework\security\spring-security-crypto\5.7.2\spring-security-crypto-5.7.2.jar;D:\application\Maven\repository\io\github\openfeign\feign-core\11.8\feign-core-11.8.jar;D:\application\Maven\repository\io\github\openfeign\feign-slf4j\11.8\feign-slf4j-11.8.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-webflux\2.7.2\spring-boot-starter-webflux-2.7.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-reactor-netty\2.7.2\spring-boot-starter-reactor-netty-2.7.2.jar;D:\application\Maven\repository\io\projectreactor\netty\reactor-netty-http\1.0.21\reactor-netty-http-1.0.21.jar;D:\application\Maven\repository\io\netty\netty-codec-http\4.1.79.Final\netty-codec-http-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-common\4.1.79.Final\netty-common-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-buffer\4.1.79.Final\netty-buffer-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-transport\4.1.79.Final\netty-transport-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-codec\4.1.79.Final\netty-codec-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-handler\4.1.79.Final\netty-handler-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-codec-http2\4.1.79.Final\netty-codec-http2-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-resolver-dns\4.1.79.Final\netty-resolver-dns-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-resolver\4.1.79.Final\netty-resolver-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-codec-dns\4.1.79.Final\netty-codec-dns-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-resolver-dns-native-macos\4.1.79.Final\netty-resolver-dns-native-macos-4.1.79.Final-osx-x86_64.jar;D:\application\Maven\repository\io\netty\netty-resolver-dns-classes-macos\4.1.79.Final\netty-resolver-dns-classes-macos-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-transport-native-epoll\4.1.79.Final\netty-transport-native-epoll-4.1.79.Final-linux-x86_64.jar;D:\application\Maven\repository\io\netty\netty-transport-native-unix-common\4.1.79.Final\netty-transport-native-unix-common-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-transport-classes-epoll\4.1.79.Final\netty-transport-classes-epoll-4.1.79.Final.jar;D:\application\Maven\repository\io\projectreactor\netty\reactor-netty-core\1.0.21\reactor-netty-core-1.0.21.jar;D:\application\Maven\repository\io\netty\netty-handler-proxy\4.1.79.Final\netty-handler-proxy-4.1.79.Final.jar;D:\application\Maven\repository\io\netty\netty-codec-socks\4.1.79.Final\netty-codec-socks-4.1.79.Final.jar;D:\application\Maven\repository\org\springframework\spring-webflux\5.3.22\spring-webflux-5.3.22.jar;D:\application\Maven\repository\io\projectreactor\reactor-core\3.4.21\reactor-core-3.4.21.jar;D:\application\Maven\repository\org\reactivestreams\reactive-streams\1.0.4\reactive-streams-1.0.4.jar;D:\application\Maven\repository\ZA21\bee-starter-web\5.10.21\bee-starter-web-5.10.21.jar;D:\application\Maven\repository\ZA21\bee-starter-healthcheck\5.10.21\bee-starter-healthcheck-5.10.21.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-validation\2.7.2\spring-boot-starter-validation-2.7.2.jar;D:\application\Maven\repository\org\apache\tomcat\embed\tomcat-embed-el\9.0.82\tomcat-embed-el-9.0.82.jar;D:\application\Maven\repository\org\hibernate\validator\hibernate-validator\6.2.3.Final\hibernate-validator-6.2.3.Final.jar;D:\application\Maven\repository\jakarta\validation\jakarta.validation-api\2.0.2\jakarta.validation-api-2.0.2.jar;D:\application\Maven\repository\org\jboss\logging\jboss-logging\3.3.2.Final\jboss-logging-3.3.2.Final.jar;D:\application\Maven\repository\com\fasterxml\classmate\1.5.1\classmate-1.5.1.jar;D:\application\Maven\repository\H0010038\04\config-client-integration-springboot\1.0.0-SNAPSHOT\config-client-integration-springboot-1.0.0-20250626.033408-18.jar;D:\application\Maven\repository\H0010038\04\config-client\1.0.0-SNAPSHOT\config-client-1.0.0-20250626.033408-19.jar;D:\application\Maven\repository\H0010038\04\infra-utils-spi\1.1.0-SNAPSHOT\infra-utils-spi-1.1.0-20240301.071119-6.jar;D:\application\Maven\repository\H0010038\04\config-client-grpc\1.0.0-SNAPSHOT\config-client-grpc-1.0.0-20250626.033408-19.jar;D:\application\Maven\repository\H0010038\04\grpc-client-notify\1.0.0-SNAPSHOT\grpc-client-notify-1.0.0-20250609.084419-19.jar;D:\application\Maven\repository\H0010038\04\grpc-client-lib\1.0.0-SNAPSHOT\grpc-client-lib-1.0.0-20250609.084419-19.jar;D:\application\Maven\repository\com\google\protobuf\protobuf-java\3.19.4\protobuf-java-3.19.4.jar;D:\application\Maven\repository\io\grpc\grpc-protobuf\1.51.0\grpc-protobuf-1.51.0.jar;D:\application\Maven\repository\com\google\api\grpc\proto-google-common-protos\2.9.0\proto-google-common-protos-2.9.0.jar;D:\application\Maven\repository\io\grpc\grpc-protobuf-lite\1.51.0\grpc-protobuf-lite-1.51.0.jar;D:\application\Maven\repository\com\google\guava\guava\20.0\guava-20.0.jar;D:\application\Maven\repository\io\grpc\grpc-stub\1.51.0\grpc-stub-1.51.0.jar;D:\application\Maven\repository\io\grpc\grpc-netty-shaded\1.30.2\grpc-netty-shaded-1.30.2.jar;D:\application\Maven\repository\io\grpc\grpc-core\1.30.2\grpc-core-1.30.2.jar;D:\application\Maven\repository\io\grpc\grpc-api\1.30.2\grpc-api-1.30.2.jar;D:\application\Maven\repository\com\google\android\annotations\4.1.1.4\annotations-4.1.1.4.jar;D:\application\Maven\repository\org\codehaus\mojo\animal-sniffer-annotations\1.18\animal-sniffer-annotations-1.18.jar;D:\application\Maven\repository\io\perfmark\perfmark-api\0.19.0\perfmark-api-0.19.0.jar;D:\application\Maven\repository\io\grpc\grpc-context\1.30.2\grpc-context-1.30.2.jar;D:\application\Maven\repository\H0010038\04\notifier-client\1.1.6-SNAPSHOT\notifier-client-1.1.6-20241011.023044-1.jar;D:\application\Maven\repository\org\apache\httpcomponents\httpmime\4.5.13\httpmime-4.5.13.jar;D:\application\Maven\repository\org\apache\curator\curator-recipes\5.1.0\curator-recipes-5.1.0.jar;D:\application\Maven\repository\org\apache\curator\curator-framework\5.1.0\curator-framework-5.1.0.jar;D:\application\Maven\repository\org\apache\curator\curator-client\5.1.0\curator-client-5.1.0.jar;D:\application\Maven\repository\org\apache\zookeeper\zookeeper\3.6.0\zookeeper-3.6.0.jar;D:\application\Maven\repository\commons-lang\commons-lang\2.6\commons-lang-2.6.jar;D:\application\Maven\repository\org\apache\zookeeper\zookeeper-jute\3.6.0\zookeeper-jute-3.6.0.jar;D:\application\Maven\repository\org\apache\yetus\audience-annotations\0.5.0\audience-annotations-0.5.0.jar;D:\application\Maven\repository\io\netty\netty-transport-native-epoll\4.1.79.Final\netty-transport-native-epoll-4.1.79.Final.jar;D:\application\Maven\repository\commons-codec\commons-codec\1.15\commons-codec-1.15.jar;D:\application\Maven\repository\com\google\code\gson\gson\2.9.0\gson-2.9.0.jar;D:\application\Maven\repository\ZA21\bee-starter-persistence\5.10.21\bee-starter-persistence-5.10.21.jar;D:\application\Maven\repository\org\mybatis\spring\boot\mybatis-spring-boot-starter\2.2.2\mybatis-spring-boot-starter-2.2.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-jdbc\2.7.2\spring-boot-starter-jdbc-2.7.2.jar;D:\application\Maven\repository\org\springframework\spring-jdbc\5.3.22\spring-jdbc-5.3.22.jar;D:\application\Maven\repository\org\mybatis\spring\boot\mybatis-spring-boot-autoconfigure\2.2.2\mybatis-spring-boot-autoconfigure-2.2.2.jar;D:\application\Maven\repository\org\mybatis\mybatis\3.5.9\mybatis-3.5.9.jar;D:\application\Maven\repository\org\mybatis\mybatis-spring\2.0.7\mybatis-spring-2.0.7.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-autoconfigure\2.7.2\spring-boot-autoconfigure-2.7.2.jar;D:\application\Maven\repository\org\apache\tomcat\tomcat-jdbc\9.0.82\tomcat-jdbc-9.0.82.jar;D:\application\Maven\repository\org\apache\tomcat\tomcat-juli\9.0.82\tomcat-juli-9.0.82.jar;D:\application\Maven\repository\LT99\09\tdsql-mysql-connector-java8\1.5.0\tdsql-mysql-connector-java8-1.5.0.jar;D:\application\Maven\repository\ZA21\bee-starter-redis\5.10.21\bee-starter-redis-5.10.21.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-data-redis\2.7.2\spring-boot-starter-data-redis-2.7.2.jar;D:\application\Maven\repository\org\springframework\data\spring-data-redis\2.7.2\spring-data-redis-2.7.2.jar;D:\application\Maven\repository\org\springframework\data\spring-data-keyvalue\2.7.2\spring-data-keyvalue-2.7.2.jar;D:\application\Maven\repository\org\springframework\data\spring-data-commons\2.7.2\spring-data-commons-2.7.2.jar;D:\application\Maven\repository\org\springframework\spring-tx\5.3.22\spring-tx-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-oxm\5.3.22\spring-oxm-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-context-support\5.3.22\spring-context-support-5.3.22.jar;D:\application\Maven\repository\redis\clients\jedis\3.10.0\jedis-3.10.0.jar;D:\application\Maven\repository\org\apache\commons\commons-pool2\2.11.1\commons-pool2-2.11.1.jar;D:\application\Maven\repository\org\projectlombok\lombok\1.18.24\lombok-1.18.24.jar;D:\application\Maven\repository\org\apache\commons\commons-collections4\4.4\commons-collections4-4.4.jar;D:\application\Maven\repository\org\apache\commons\commons-csv\1.10.0\commons-csv-1.10.0.jar;D:\application\Maven\repository\com\alibaba\transmittable-thread-local\2.11.4\transmittable-thread-local-2.11.4.jar;D:\application\Maven\repository\com\github\ben-manes\caffeine\caffeine\2.8.5\caffeine-2.8.5.jar;D:\application\Maven\repository\org\checkerframework\checker-qual\3.4.1\checker-qual-3.4.1.jar;D:\application\Maven\repository\com\google\errorprone\error_prone_annotations\2.4.0\error_prone_annotations-2.4.0.jar;D:\application\Maven\repository\org\apache\httpcomponents\httpclient\4.5.13\httpclient-4.5.13.jar;D:\application\Maven\repository\org\apache\httpcomponents\httpcore\4.4.15\httpcore-4.4.15.jar;D:\application\Maven\repository\commons-logging\commons-logging\1.2\commons-logging-1.2.jar;D:\application\Maven\repository\H0010038\04\ccc-metric-dependency\1.0.9-SNAPSHOT\ccc-metric-dependency-1.0.9-20250220.060300-3.jar;D:\application\Maven\repository\org\slf4j\slf4j-api\1.7.36\slf4j-api-1.7.36.jar;D:\application\Maven\repository\H0010038\04\security-protocol\1.2.0-SNAPSHOT\security-protocol-1.2.0-20250311.063350-1.jar;D:\application\Maven\repository\H0010038\04\security-gct\1.2.0-RELEASE\security-gct-1.2.0-RELEASE.jar;D:\application\Maven\repository\org\bouncycastle\bcprov-jdk15on\1.60\bcprov-jdk15on-1.60.jar;D:\application\Maven\repository\org\bouncycastle\bcpkix-jdk15on\1.60\bcpkix-jdk15on-1.60.jar;D:\application\Maven\repository\ZA33\PCJava\1.17.20220616\PCJava-1.17.20220616.jar;D:\application\Maven\repository\com\payneteasy\ber-tlv\1.0-11\ber-tlv-1.0-11.jar;D:\application\Maven\repository\com\github\jnr\jnr-ffi\2.0.9\jnr-ffi-2.0.9.jar;D:\application\Maven\repository\com\github\jnr\jffi\1.2.11\jffi-1.2.11.jar;D:\application\Maven\repository\com\github\jnr\jffi\1.2.11\jffi-1.2.11-native.jar;D:\application\Maven\repository\org\ow2\asm\asm\5.0.3\asm-5.0.3.jar;D:\application\Maven\repository\org\ow2\asm\asm-commons\5.0.3\asm-commons-5.0.3.jar;D:\application\Maven\repository\org\ow2\asm\asm-analysis\5.0.3\asm-analysis-5.0.3.jar;D:\application\Maven\repository\org\ow2\asm\asm-tree\5.0.3\asm-tree-5.0.3.jar;D:\application\Maven\repository\org\ow2\asm\asm-util\5.0.3\asm-util-5.0.3.jar;D:\application\Maven\repository\com\github\jnr\jnr-x86asm\1.0.2\jnr-x86asm-1.0.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-starter-test\2.7.2\spring-boot-starter-test-2.7.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-test\2.7.2\spring-boot-test-2.7.2.jar;D:\application\Maven\repository\org\springframework\boot\spring-boot-test-autoconfigure\2.7.2\spring-boot-test-autoconfigure-2.7.2.jar;D:\application\Maven\repository\com\jayway\jsonpath\json-path\2.7.0\json-path-2.7.0.jar;D:\application\Maven\repository\net\minidev\json-smart\2.4.8\json-smart-2.4.8.jar;D:\application\Maven\repository\net\minidev\accessors-smart\2.4.8\accessors-smart-2.4.8.jar;D:\application\Maven\repository\jakarta\xml\bind\jakarta.xml.bind-api\2.3.3\jakarta.xml.bind-api-2.3.3.jar;D:\application\Maven\repository\jakarta\activation\jakarta.activation-api\1.2.2\jakarta.activation-api-1.2.2.jar;D:\application\Maven\repository\org\assertj\assertj-core\3.22.0\assertj-core-3.22.0.jar;D:\application\Maven\repository\org\hamcrest\hamcrest\2.2\hamcrest-2.2.jar;D:\application\Maven\repository\org\junit\jupiter\junit-jupiter\5.8.2\junit-jupiter-5.8.2.jar;D:\application\Maven\repository\org\junit\jupiter\junit-jupiter-api\5.8.2\junit-jupiter-api-5.8.2.jar;D:\application\Maven\repository\org\junit\jupiter\junit-jupiter-params\5.8.2\junit-jupiter-params-5.8.2.jar;D:\application\Maven\repository\org\junit\jupiter\junit-jupiter-engine\5.8.2\junit-jupiter-engine-5.8.2.jar;D:\application\Maven\repository\org\mockito\mockito-junit-jupiter\4.5.1\mockito-junit-jupiter-4.5.1.jar;D:\application\Maven\repository\org\skyscreamer\jsonassert\1.5.1\jsonassert-1.5.1.jar;D:\application\Maven\repository\com\vaadin\external\google\android-json\0.0.20131108.vaadin1\android-json-0.0.20131108.vaadin1.jar;D:\application\Maven\repository\org\springframework\spring-core\5.3.22\spring-core-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-jcl\5.3.22\spring-jcl-5.3.22.jar;D:\application\Maven\repository\org\springframework\spring-test\5.3.22\spring-test-5.3.22.jar;D:\application\Maven\repository\org\xmlunit\xmlunit-core\2.9.0\xmlunit-core-2.9.0.jar;D:\application\Maven\repository\org\junit\vintage\junit-vintage-engine\5.8.2\junit-vintage-engine-5.8.2.jar;D:\application\Maven\repository\org\junit\platform\junit-platform-engine\1.8.2\junit-platform-engine-1.8.2.jar;D:\application\Maven\repository\org\opentest4j\opentest4j\1.2.0\opentest4j-1.2.0.jar;D:\application\Maven\repository\org\junit\platform\junit-platform-commons\1.8.2\junit-platform-commons-1.8.2.jar;D:\application\Maven\repository\org\apiguardian\apiguardian-api\1.1.2\apiguardian-api-1.1.2.jar;D:\application\Maven\repository\junit\junit\4.13.2\junit-4.13.2.jar;D:\application\Maven\repository\org\hamcrest\hamcrest-core\2.2\hamcrest-core-2.2.jar;D:\application\Maven\repository\org\mockito\mockito-core\2.23.4\mockito-core-2.23.4.jar;D:\application\Maven\repository\net\bytebuddy\byte-buddy\1.12.12\byte-buddy-1.12.12.jar;D:\application\Maven\repository\net\bytebuddy\byte-buddy-agent\1.12.12\byte-buddy-agent-1.12.12.jar;D:\application\Maven\repository\org\objenesis\objenesis\2.6\objenesis-2.6.jar;D:\application\Maven\repository\org\powermock\powermock-core\2.0.2\powermock-core-2.0.2.jar;D:\application\Maven\repository\org\powermock\powermock-reflect\2.0.2\powermock-reflect-2.0.2.jar;D:\application\Maven\repository\org\javassist\javassist\3.24.0-GA\javassist-3.24.0-GA.jar;D:\application\Maven\repository\org\powermock\powermock-api-mockito2\2.0.2\powermock-api-mockito2-2.0.2.jar;D:\application\Maven\repository\org\powermock\powermock-api-support\2.0.2\powermock-api-support-2.0.2.jar;D:\application\Maven\repository\org\powermock\powermock-module-junit4\2.0.2\powermock-module-junit4-2.0.2.jar;D:\application\Maven\repository\org\powermock\powermock-module-junit4-common\2.0.2\powermock-module-junit4-common-2.0.2.jar;D:\application\Maven\repository\org\jacoco\org.jacoco.agent\0.8.4\org.jacoco.agent-0.8.4-runtime.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit5 com.cmbchina.ccc.msp.mspai.business.AIPracticeBusinessImplTest,ttsWithDifferentConfigs Process finished with exit code -1 Wanted but not invoked: closeableHttpClient.execute( <A i practice business impl test$$ lambda$ 2 5 8/ 3 7 0 1 9 6 5 4 0> ); -> at com.cmbchina.ccc.msp.mspai.business.AIPracticeBusinessImplTest.ttsWithDifferentConfigs(AIPracticeBusinessImplTest.java:310) Actually, there were zero interactions with this mock. Wanted but not invoked: closeableHttpClient.execute( <A i practice business impl test$$ lambda$ 2 5 8/ 3 7 0 1 9 6 5 4 0> ); -> at com.cmbchina.ccc.msp.mspai.business.AIPracticeBusinessImplTest.ttsWithDifferentConfigs(AIPracticeBusinessImplTest.java:310) Actually, there were zero interactions with this mock. at com.cmbchina.ccc.msp.mspai.business.AIPracticeBusinessImplTest.ttsWithDifferentConfigs(AIPracticeBusinessImplTest.java:310) at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68) at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89) at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97) at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87) at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50) at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34) at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at org.junit.runner.JUnitCore.run(JUnitCore.java:115) at org.junit.vintage.engine.execution.RunnerExecutor.execute(RunnerExecutor.java:42) at org.junit.vintage.engine.VintageTestEngine.executeAllChildren(VintageTestEngine.java:80) at org.junit.vintage.engine.VintageTestEngine.execute(VintageTestEngine.java:72) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67) at org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114) at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86) at org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86) at org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:53) at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:57) at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38) at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11) at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35) at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232) at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
07-08
### Reactor 模型的使用原因 Reactor 模型是一种基于事件驱动的编程模式,广泛应用于网络编程和高性能服务器的设计中。其核心思想是通过一个事件循环(Event Loop)来监听并处理各种 I/O 事件,从而实现高效的并发处理能力。 在传统的多线程模型中,每个连接都由一个独立的线程处理,这种方式虽然简单直观,但在高并发场景下会带来严重的资源消耗问题,如线程切换开销大、锁竞争频繁等。相比之下,Reactor 模型通过将所有 I/O 操作集中在一个或多个事件循环线程中执行,能够有效减少线程数量,降低上下文切换成本,并避免锁机制带来的性能损耗[^3]。 此外,在单 Reactor 单线程模型中,所有的 Accept、Read、Write 操作都由一个线程完成。这种方式适用于低并发、小数据量的场景,但对于高负载的应用来说,容易成为性能瓶颈。因此,引入了主从 Reactor 多线程模型,其中主线程仅负责监听连接请求(Acceptor),而具体的 I/O 操作则分发给多个工作线程处理(Event Loop)。这种架构不仅提升了系统的吞吐能力,还能充分利用多核 CPU 的计算能力[^3]。 Redis 是一个典型的采用单线程 Reactor 模型的高性能数据库系统。它通过 I/O 多路复用技术(如 epoll、kqueue 等)结合事件循环实现了极高的并发处理能力。尽管 Redis 主线程是单线程的,但由于其非阻塞式的 I/O 操作和高效的事件调度机制,仍然能够在不依赖多线程的情况下达到非常出色的性能表现[^2]。 另一个典型的例子是 Netty 框架,它采用了多 Reactor 模型来提升网络通信的效率。Netty 中的 Boss Group 负责监听新连接,而 Worker Group 则用于处理已建立连接上的读写操作。这种分工明确的设计方式使得系统可以更高效地响应大量客户端请求,同时保持良好的可扩展性[^1]。 综上所述,Reactor 模型之所以被广泛采用,主要是因为它具备以下优势: - **减少线程数量**:通过事件循环统一管理 I/O 操作,降低了线程创建与销毁的成本。 - **避免锁竞争**:由于大部分操作都在同一个线程内顺序执行,减少了对共享资源的访问冲突。 - **提高并发能力**:主从 Reactor 模型可以在多核环境下充分发挥硬件性能,支持更高的并发连接数。 - **简化编程模型**:开发者无需关心复杂的线程同步问题,只需关注事件回调逻辑即可。 ### 示例代码 下面是一个简单的 Reactor 模型实现,使用 Python 的 `selectors` 模块构建了一个基于 I/O 多路复用的 TCP 服务器: ```python import selectors import socket sel = selectors.DefaultSelector() def accept(sock, mask): conn, addr = sock.accept() print('accepted', conn, 'from', addr) conn.setblocking(False) sel.register(conn, selectors.EVENT_READ, read) def read(conn, mask): data = conn.recv(1000) if data: print('echoing', repr(data), 'to', conn) conn.send(data) else: print('closing', conn) sel.unregister(conn) conn.close() sock = socket.socket() sock.bind(('localhost', 1234)) sock.listen(100) sock.setblocking(False) sel.register(sock, selectors.EVENT_READ, accept) while True: events = sel.select() for key, mask in events: callback = key.data callback(key.fileobj, mask) ``` 该示例展示了如何利用事件循环监听套接字上的读写事件,并根据不同的事件类型调用相应的处理函数。 ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值