nats java client 的多线程处理细节

nats java client 的设计的时候默认是由一个单线程的Dispatcher处理的,这样就会有一个问题,除非我们的服务运行的比较快,否则就会有一个阻塞任务造成服务不可用的问题

默认参考处理

  • 代码

我只摘取部分代码

public void run() {
        try {
            while (running.get() && !Thread.interrupted()) {
                NatsMessage msg = this.incoming.pop(this.waitForMessage);
                if (msg != null) {
                    NatsSubscription sub = msg.getNatsSubscription();
                    if (sub != null && sub.isActive()) {
                        MessageHandler handler = nonDefaultHandlerBySid.get(sub.getSID());
                        if (handler == null) {
                            handler = defaultHandler;
                        }
                        // A dispatcher can have a null defaultHandler. You can't subscribe without a handler,
                        // but messages might come in while the dispatcher is being closed or after unsubscribe
                        // and the [non-default] handler has already been removed from subscriptionHandlers
                        if (handler != null) {
                            sub.incrementDeliveredCount();
                            this.incrementDeliveredCount();

                            try {
                                handler.onMessage(msg);
                            } catch (Exception exp) {
                                connection.processException(exp);
                            } catch (Error err) {
                                connection.processException(new Exception(err));
                            }

                            if (sub.reachedUnsubLimit()) {
                                connection.invalidate(sub);
                            }

可以看到如果任务阻塞,其他也就只能等着,因为就是单线程的

造成的影响

一个是处理会排队阻塞,一个是如果在web 系统中使用,比如基于nats 的micro service 会造成整个服务不可用

解决方法

机制上官方是提供了支持配置的线程池,同时还与一个开启支持线程池的Dispatcher

  • 参考配置

配置之后会有一个无界的线程池,一般场景够用,但是也可以自己调整

options = new Options.Builder().useDispatcherWithExecutor()
  • 内部实际处理

可以看到每次消息的处理都是基于线程池的,这样机制上就可以可以规避因为特定处理慢,造成整个服务不稳定

public void run() {
        try {
            while (running.get() && !Thread.interrupted()) {
                NatsMessage msg = this.incoming.pop(this.waitForMessage);
                if (msg != null) {
                    NatsSubscription sub = msg.getNatsSubscription();
                    if (sub != null && sub.isActive()) {
                        MessageHandler handler = nonDefaultHandlerBySid.get(sub.getSID());
                        if (handler == null) {
                            handler = defaultHandler;
                        }
                        // A dispatcher can have a null defaultHandler. You can't subscribe without a handler,
                        // but messages might come in while the dispatcher is being closed or after unsubscribe
                        // and the [non-default] handler has already been removed from subscriptionHandlers
                        if (handler != null) {
                            sub.incrementDeliveredCount();
                            this.incrementDeliveredCount();

                            MessageHandler finalHandler = handler;
                            connection.getExecutor().execute(() -> {
                                try {
                                    finalHandler.onMessage(msg);
                                } catch (Exception exp) {
                                    connection.processException(exp);
                                } catch (Error err) {
                                    connection.processException(new Exception(err));
                                }

                                if (sub.reachedUnsubLimit()) {
                                    connection.invalidate(sub);
                                }
                            });

说明

以上是结合源码的一个简单说明,实际上边说的参数还是很重要的,否则可能会造成服务看着不稳定,实际就是一个简单的配置参数

参考资料

https://javadoc.io/static/io.nats/jnats/2.24.1/io/nats/client/Options.html#useDispatcherWithExecutor--

https://javadoc.io/static/io.nats/jnats/2.24.1/io/nats/client/Options.Builder.html

https://javadoc.io/static/io.nats/jnats/2.24.1/io/nats/client/Dispatcher.html

https://github.com/nats-io/nats.java/blob/main/src/main/java/io/nats/client/impl/DispatcherFactory.java

https://github.com/nats-io/nats.java/blob/main/src/main/java/io/nats/client/impl/NatsDispatcherWithExecutor.java#L18

posted on 2026-01-11 08:00  荣锋亮  阅读(10)  评论(0)    收藏  举报

导航