在启动时阻止应用程序仅意味着阻止应用程序?
Blocking application on startup only means blocking application?
众所周知 Spring Webflux 应用程序不应阻塞应用程序。
只是想知道,如果在启动时有阻塞调用,但在业务逻辑上没有阻塞调用,该应用程序是否被视为阻塞应用程序?只是一个一般性的问题。
我有一个例子,(超级容易重现)我使用 Blockhound 来测试应用程序是否阻塞。
在我的单元和集成测试中实例化 Bloudhound 时,流程已被证明是非阻塞的(非常高兴)。
然而,在启动时实例化 Blockhound,Spring Webflux + Reactive Cassandra 像这样:
package com.webflux.question.blockingg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import reactor.blockhound.BlockHound;
@SpringBootApplication
public class Application {
static {
BlockHound.install();
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
(the Cassandra parts)
package com.webflux.question.blockingg.configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.AbstractReactiveCassandraConfiguration;
import org.springframework.data.cassandra.config.CqlSessionFactoryBean;
import org.springframework.data.cassandra.repository.config.EnableReactiveCassandraRepositories;
import org.springframework.lang.NonNull;
@Configuration
@EnableReactiveCassandraRepositories
public class CassandraConfiguration extends AbstractReactiveCassandraConfiguration {
@Value("${spring.data.cassandra.username}")
private String username;
@Value("${spring.data.cassandra.password}")
private String passPhrase;
@Value("${spring.data.cassandra.keyspace-name}")
private String keyspace;
@Value("${spring.data.cassandra.datacenter}")
private String datacenter;
@Value("${spring.data.cassandra.contact-points}")
private String contactPoints;
@Value("${spring.data.cassandra.port}")
private int port;
@Bean
@NonNull
@Override
public CqlSessionFactoryBean cassandraSession() {
final CqlSessionFactoryBean cqlSessionFactoryBean = new CqlSessionFactoryBean();
cqlSessionFactoryBean.setContactPoints(contactPoints);
cqlSessionFactoryBean.setKeyspaceName(keyspace);
cqlSessionFactoryBean.setLocalDatacenter(datacenter);
cqlSessionFactoryBean.setPort(port);
cqlSessionFactoryBean.setUsername(username);
cqlSessionFactoryBean.setPassword(passPhrase);
return cqlSessionFactoryBean;
}
@NonNull
@Override
protected String getKeyspaceName() {
return keyspace;
}
@Override
protected String getLocalDataCenter() {
return datacenter;
}
@NonNull
@Override
protected String getContactPoints() {
return contactPoints;
}
@Override
protected int getPort() {
return port;
}
}
pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.webflux.question</groupId>
<artifactId>blocking</artifactId>
<version>0.2</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound</artifactId>
<version>1.0.4.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
我在启动时看到下面的内容。
这是否意味着我的应用被阻止了?
事件循环会因此受到伤害吗?
有没有办法解决这个问题?
感谢您的宝贵时间。
Caused by: java.lang.IllegalArgumentException: Error instantiating class AtomicTimestampGenerator (specified by advanced.timestamp-generator.class): Blocking call! java.io.FileOutputStream#writeBytes
at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:239)
at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:94)
at com.datastax.oss.driver.internal.core.context.DefaultDriverContext.buildTimestampGenerator(DefaultDriverContext.java:368)
at com.datastax.oss.driver.internal.core.util.concurrent.LazyReference.get(LazyReference.java:55)
at com.datastax.oss.driver.internal.core.context.DefaultDriverContext.getTimestampGenerator(DefaultDriverContext.java:743)
at com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.init(DefaultSession.java:349)
at com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.access00(DefaultSession.java:300)
at com.datastax.oss.driver.internal.core.session.DefaultSession.lambda$init[=12=](DefaultSession.java:146)
at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
at io.netty.util.concurrent.PromiseTask.run(PromiseTask.java:106)
at io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54)
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: reactor.blockhound.BlockingOperationError: Blocking call! java.io.FileOutputStream#writeBytes
at java.base/java.io.FileOutputStream.writeBytes(FileOutputStream.java)
at java.base/java.io.FileOutputStream.write(FileOutputStream.java:354)
at org.apache.logging.log4j.core.appender.OutputStreamManager.writeToDestination(OutputStreamManager.java:250)
at org.apache.logging.log4j.core.appender.FileManager.writeToDestination(FileManager.java:273)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.writeToDestination(RollingFileManager.java:240)
at org.apache.logging.log4j.core.appender.OutputStreamManager.flushBuffer(OutputStreamManager.java:282)
at org.apache.logging.log4j.core.appender.OutputStreamManager.flush(OutputStreamManager.java:291)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:199)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:190)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:181)
at org.apache.logging.log4j.core.appender.RollingFileAppender.append(RollingFileAppender.java:312)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:543)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:502)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:485)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:460)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:82)
at org.apache.logging.log4j.core.Logger.log(Logger.java:161)
at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2198)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2152)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2135)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2016)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1875)
at org.apache.logging.slf4j.Log4jLogger.info(Log4jLogger.java:179)
at com.datastax.oss.driver.internal.core.time.Clock.getInstance(Clock.java:35)
at com.datastax.oss.driver.internal.core.time.MonotonicTimestampGenerator.buildClock(MonotonicTimestampGenerator.java:109)
at com.datastax.oss.driver.internal.core.time.MonotonicTimestampGenerator.<init>(MonotonicTimestampGenerator.java:43)
at com.datastax.oss.driver.internal.core.time.AtomicTimestampGenerator.<init>(AtomicTimestampGenerator.java:52)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:232)
... 14 more
Datastax团队官方回复:
错误发生在 Spring 构建应用程序上下文时,该错误发生在应用程序启动时。在此阶段通常允许阻塞调用,即使对于反应式/非阻塞应用程序也是如此——否则,例如,您的应用程序将完全无法读取配置文件——因为这是一个阻塞调用。
目前正在积极处理 JAVA-2449。我将更改 Uuids.random() 以使用非阻塞的东西。
我遇到了同样的问题,添加线程谓词使其无法检测到阻塞调用。至少下面不会出错阻塞调用,但会记录跟踪并详细说明实际阻塞的内容。
希望对其他人有所帮助。
static {
BlockHound
.install(builder -> {
builder.blockingMethodCallback(it -> {
new Exception(it.toString()).printStackTrace();
});
});
}
众所周知 Spring Webflux 应用程序不应阻塞应用程序。
只是想知道,如果在启动时有阻塞调用,但在业务逻辑上没有阻塞调用,该应用程序是否被视为阻塞应用程序?只是一个一般性的问题。
我有一个例子,(超级容易重现)我使用 Blockhound 来测试应用程序是否阻塞。 在我的单元和集成测试中实例化 Bloudhound 时,流程已被证明是非阻塞的(非常高兴)。
然而,在启动时实例化 Blockhound,Spring Webflux + Reactive Cassandra 像这样:
package com.webflux.question.blockingg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import reactor.blockhound.BlockHound;
@SpringBootApplication
public class Application {
static {
BlockHound.install();
}
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
(the Cassandra parts)
package com.webflux.question.blockingg.configuration;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.AbstractReactiveCassandraConfiguration;
import org.springframework.data.cassandra.config.CqlSessionFactoryBean;
import org.springframework.data.cassandra.repository.config.EnableReactiveCassandraRepositories;
import org.springframework.lang.NonNull;
@Configuration
@EnableReactiveCassandraRepositories
public class CassandraConfiguration extends AbstractReactiveCassandraConfiguration {
@Value("${spring.data.cassandra.username}")
private String username;
@Value("${spring.data.cassandra.password}")
private String passPhrase;
@Value("${spring.data.cassandra.keyspace-name}")
private String keyspace;
@Value("${spring.data.cassandra.datacenter}")
private String datacenter;
@Value("${spring.data.cassandra.contact-points}")
private String contactPoints;
@Value("${spring.data.cassandra.port}")
private int port;
@Bean
@NonNull
@Override
public CqlSessionFactoryBean cassandraSession() {
final CqlSessionFactoryBean cqlSessionFactoryBean = new CqlSessionFactoryBean();
cqlSessionFactoryBean.setContactPoints(contactPoints);
cqlSessionFactoryBean.setKeyspaceName(keyspace);
cqlSessionFactoryBean.setLocalDatacenter(datacenter);
cqlSessionFactoryBean.setPort(port);
cqlSessionFactoryBean.setUsername(username);
cqlSessionFactoryBean.setPassword(passPhrase);
return cqlSessionFactoryBean;
}
@NonNull
@Override
protected String getKeyspaceName() {
return keyspace;
}
@Override
protected String getLocalDataCenter() {
return datacenter;
}
@NonNull
@Override
protected String getContactPoints() {
return contactPoints;
}
@Override
protected int getPort() {
return port;
}
}
pom:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/>
</parent>
<groupId>com.webflux.question</groupId>
<artifactId>blocking</artifactId>
<version>0.2</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-cassandra-reactive</artifactId>
</dependency>
<dependency>
<groupId>io.projectreactor.tools</groupId>
<artifactId>blockhound</artifactId>
<version>1.0.4.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
我在启动时看到下面的内容。
这是否意味着我的应用被阻止了?
事件循环会因此受到伤害吗?
有没有办法解决这个问题?
感谢您的宝贵时间。
Caused by: java.lang.IllegalArgumentException: Error instantiating class AtomicTimestampGenerator (specified by advanced.timestamp-generator.class): Blocking call! java.io.FileOutputStream#writeBytes
at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:239)
at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:94)
at com.datastax.oss.driver.internal.core.context.DefaultDriverContext.buildTimestampGenerator(DefaultDriverContext.java:368)
at com.datastax.oss.driver.internal.core.util.concurrent.LazyReference.get(LazyReference.java:55)
at com.datastax.oss.driver.internal.core.context.DefaultDriverContext.getTimestampGenerator(DefaultDriverContext.java:743)
at com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.init(DefaultSession.java:349)
at com.datastax.oss.driver.internal.core.session.DefaultSession$SingleThreaded.access00(DefaultSession.java:300)
at com.datastax.oss.driver.internal.core.session.DefaultSession.lambda$init[=12=](DefaultSession.java:146)
at io.netty.util.concurrent.PromiseTask.runTask(PromiseTask.java:98)
at io.netty.util.concurrent.PromiseTask.run(PromiseTask.java:106)
at io.netty.channel.DefaultEventLoop.run(DefaultEventLoop.java:54)
at io.netty.util.concurrent.SingleThreadEventExecutor.run(SingleThreadEventExecutor.java:989)
at io.netty.util.internal.ThreadExecutorMap.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: reactor.blockhound.BlockingOperationError: Blocking call! java.io.FileOutputStream#writeBytes
at java.base/java.io.FileOutputStream.writeBytes(FileOutputStream.java)
at java.base/java.io.FileOutputStream.write(FileOutputStream.java:354)
at org.apache.logging.log4j.core.appender.OutputStreamManager.writeToDestination(OutputStreamManager.java:250)
at org.apache.logging.log4j.core.appender.FileManager.writeToDestination(FileManager.java:273)
at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.writeToDestination(RollingFileManager.java:240)
at org.apache.logging.log4j.core.appender.OutputStreamManager.flushBuffer(OutputStreamManager.java:282)
at org.apache.logging.log4j.core.appender.OutputStreamManager.flush(OutputStreamManager.java:291)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.directEncodeEvent(AbstractOutputStreamAppender.java:199)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.tryAppend(AbstractOutputStreamAppender.java:190)
at org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.append(AbstractOutputStreamAppender.java:181)
at org.apache.logging.log4j.core.appender.RollingFileAppender.append(RollingFileAppender.java:312)
at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:156)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:129)
at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:120)
at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:543)
at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:502)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:485)
at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:460)
at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:82)
at org.apache.logging.log4j.core.Logger.log(Logger.java:161)
at org.apache.logging.log4j.spi.AbstractLogger.tryLogMessage(AbstractLogger.java:2198)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageTrackRecursion(AbstractLogger.java:2152)
at org.apache.logging.log4j.spi.AbstractLogger.logMessageSafely(AbstractLogger.java:2135)
at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:2016)
at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1875)
at org.apache.logging.slf4j.Log4jLogger.info(Log4jLogger.java:179)
at com.datastax.oss.driver.internal.core.time.Clock.getInstance(Clock.java:35)
at com.datastax.oss.driver.internal.core.time.MonotonicTimestampGenerator.buildClock(MonotonicTimestampGenerator.java:109)
at com.datastax.oss.driver.internal.core.time.MonotonicTimestampGenerator.<init>(MonotonicTimestampGenerator.java:43)
at com.datastax.oss.driver.internal.core.time.AtomicTimestampGenerator.<init>(AtomicTimestampGenerator.java:52)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at com.datastax.oss.driver.internal.core.util.Reflection.buildFromConfig(Reflection.java:232)
... 14 more
Datastax团队官方回复:
错误发生在 Spring 构建应用程序上下文时,该错误发生在应用程序启动时。在此阶段通常允许阻塞调用,即使对于反应式/非阻塞应用程序也是如此——否则,例如,您的应用程序将完全无法读取配置文件——因为这是一个阻塞调用。
目前正在积极处理 JAVA-2449。我将更改 Uuids.random() 以使用非阻塞的东西。
我遇到了同样的问题,添加线程谓词使其无法检测到阻塞调用。至少下面不会出错阻塞调用,但会记录跟踪并详细说明实际阻塞的内容。
希望对其他人有所帮助。
static {
BlockHound
.install(builder -> {
builder.blockingMethodCallback(it -> {
new Exception(it.toString()).printStackTrace();
});
});
}