[spring-projects/spring-boot]Couchbase 健康检查因超时而失败

2018-10-04 19 views
3

春季启动 - 2.0.5.RELEASE

我在发行说明中看到类似的问题应该得到解决。然而,我在日志中经常(每 30 分钟到 60 分钟)看到这种情况,服务变得不健康,并在大约 30 秒左右恢复健康。

2018-10-04 12:08:01.182  WARN 1 --- [io-8080-exec-15] o.s.b.a.c.CouchbaseHealthIndicator       : Couchbase health check failed
--
  | java.util.concurrent.TimeoutException: null
  | at com.couchbase.client.java.util.Blocking.blockForSingle(Blocking.java:77)
  | at com.couchbase.client.java.bucket.DefaultBucketManager.info(DefaultBucketManager.java:127)
  | at org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator.getBucketInfo(CouchbaseHealthIndicator.java:84)
  | at org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator.doHealthCheck(CouchbaseHealthIndicator.java:75)
  | at org.springframework.boot.actuate.health.AbstractHealthIndicator.health(AbstractHealthIndicator.java:84)
  | at org.springframework.boot.actuate.health.CompositeHealthIndicator.health(CompositeHealthIndicator.java:68)
  | at org.springframework.boot.actuate.health.HealthEndpointWebExtension.getHealth(HealthEndpointWebExtension.java:50)
  | at sun.reflect.GeneratedMethodAccessor149.invoke(Unknown Source)
  | at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  | at java.lang.reflect.Method.invoke(Method.java:498)
  | at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:223)
  | at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:76)
  | at org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation.invoke(AbstractDiscoveredOperation.java:61)
  | at org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$ServletWebOperationAdapter.handle(AbstractWebMvcEndpointHandlerMapping.java:274)
  | at org.springframework.boot.actuate.endpoint.web.servlet.AbstractWebMvcEndpointHandlerMapping$OperationHandler.handle(AbstractWebMvcEndpointHandlerMapping.java:330)
  | at sun.reflect.GeneratedMethodAccessor146.invoke(Unknown Source)
  | at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  | at java.lang.reflect.Method.invoke(Method.java:498)
  | at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
  | at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
  | at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
  | at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891)
  | at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)
  | at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
  | at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
  | at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
  | at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
  | at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
  | at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
  | at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
  | at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
  | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
  | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
  | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
  | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:155)
  | at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:123)
  | at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108)
  | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
  | at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  | at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
  | at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
  | at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
  | at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
  | at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
  | at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
  | at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
  | at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
  | at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
  | at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
  | at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
  | at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806)
  | at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
  | at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
  | at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
  | at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
  | at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
  | at java.lang.Thread.run(Thread.java:748)

回答

9

您指的是https://github.com/spring-projects/spring-boot/issues/13879吗?这是相反的问题,即 Couchbase 宕机并且运行状况指示器会挂起。在您的情况下,如果您确定 Couchbase 已启动,则响应时间太长,并且指示器认为它已关闭。您可以使用management.health.couchbase.timeout增加超时时间。默认值为一秒。请尝试一下,如果有帮助请告诉我们。也许我们应该增加默认值。

2

我尝试了各种不同的超时值,我必须将其更改为60000毫秒,但我仍然偶尔会看到超时问题,最终可能会将其设置为75000毫秒,即之前的默认值。绝对1000ms 不是默认值的理想选择。

5

谢谢。如果 60000 毫秒的超时仍然会导致偶尔出现问题,我会更担心 Couchbase 集群的性能。您是否发现针对集群的应用程序查询的响应时间相似?

关于管理超时,Couchbase 的文档对此有这样的说明,默认值是 75000 毫秒:

9

不,性能明智的集群响应速度非常快,查询结果通常<50毫秒,我所看到的是,当 couchbase 执行一些操作(例如压缩存储桶、更新索引)时,就会发生运行状况检查超时。为了保持日志干净,我将其设置为更高的值。现在重试次数太多了。也许我们需要几次重试,超时时间稍长一些。比如说 3000ms,3 次重试 1000ms backOff。在实际抛出错误之前。

5

我想知道我们是否不应该使用Bucket.ping()它。我在Couchbase 论坛的这个帖子中了解了它。像这样的东西:

PingReport report = this.operations.getCouchbaseBucket().ping(this.timeout,
        TimeUnit.MILLISECONDS);
for (PingServiceHealth serviceHealth : report.services()) {
    PingState state = serviceHealth.state();
    // Decide health based on state being one of OK, TIMEOUT, or ERROR
}

PingReport位于内部包中,但带有注释@InterfaceAudience.Public。这意味着它“旨在由依赖于该库的任何项目或应用程序使用”。然而,它还带有注释,@InterfaceStability.Experimental这意味着它“被认为是实验性的,不能保证兼容性和稳定性”。

2

需要一分钟或更长时间的事情(无论是单个调用,还是在超时后重试的多个调用)的问题是,运行状况端点的调用者将必须等待一分钟或更多的回应。如果负载均衡器在一分钟内放弃并假设应用程序已关闭,我不会感到惊讶。为了变得有用,我真的认为我们需要找到一些东西,既能对 Couchbase 的健康状况给出合理的印象,又能快速做出反应。

3

我同意。仅供参考 - LoadBalancer 在启动时导致与 Couchbase 的连接问题,并且 pod 在设置阈值之前无法恢复正常,因此我们切换到直接连接节点

5

安装了几个 Couchbase 节点后,我了解到我们应该使用Cluster.diagnostics()而不是Bucket.ping().前者几乎立即返回,无论集群的状态如何。如果节点宕机,后者将在整个超时时间内阻塞。

Cluster.diagnostics()返回一个DiagnosticsReport.在该报告中,当集群中的节点关闭时,它的状态会被列为CONNECTING。当节点启动时,它的状态被列为CONNECTED

使用诊断报告的一个缺点是,它将集群视为一个整体,而不管应用程序使用哪些存储桶以及它们如何在集群中复制。可能是托管应用程序正在使用的存储桶的所有节点都已启动,但集群中的某个节点可能已关闭,然后我们会认为 Couchbase 不必要地关闭。但是,我认为如果不在存储桶级别执行某些操作,我们就没有任何方法可以确定这一点,并且这些调用都可能会阻塞很长时间。

我们现在需要弄清楚如何从现在的位置到达我们想要的位置。转向使用Cluster而不是Bucket我们可以从中获取CouchbaseOperations意味着运行状况指示器的类型签名和构造函数需要更改。

6

使用范围DiagnosticsReport太广,因为它检查整个集群的运行状况。使用BucketInfo给我们提供了所需的焦点,但它可能会阻塞一段不可接受的长时间。我们真正需要的是一个桶级别的健康检查,其返回速度与Cluster.diagnostics.如果没有这样的 API,我们得出的结论是,我们没有好的方法来检查 Couchbase 的健康状况。我们将CouchbaseHealthIndicator在 2.0.x 中弃用它,并在 2.1.x 中停止自动配置它。

6

在这里向 @daschl 寻求他的见解,但我认为这种diagnostics()方式实际上可以满足要求。

在 Couchbase 中Cluster,如果一个节点有,它会托管everyServiceType.BINARY的一小部分(如果我没记错的话)。因此,对于最基本的用例(键/值操作),任何具有 BINARY 且未处于该状态的节点都会将集群标记为不健康。 Bucketconnected

健康检查还可以进行配置,让用户决定其他类型的服务是否与他们的工作负载相关(请参阅 enum ServiceType,例如 Spring Data 使用的视图和 N1QL)。

注意:似乎diagnostics()ping()功能是在这个Couchbase RFC中设计的。

7

谢谢你,@simonbasle。 RFC 读起来很有趣。这一部分特别引起了我的注意:

我不确定我们是否比 SDK 更能了解用户的特定工作负载是否健康。希望@daschl 能提供一些意见来证明我错了。

7

@wilkinsona 我认为diagnostics()在这里使用 API 就符合 @simonbasle 所说的要求。请记住,从 IO 角度来看,存储桶范围和集群范围之间的唯一区别是概念上范围仅限于存储桶级别的一些二进制 (kv) 连接。所有其他可能重要的服务(例如 N1QL 查询、fts 等)都属于集群范围,因为我们将信用作为基本身份验证标头发送到那里,并出于效率原因在所有存储桶中共享它们。

所以我认为使用该报告可以准确地了解 SDK 的状态。需要考虑的一件事是,即使它是“集群范围”,它也会以相同的方式影响每个存储桶,因为数据均匀分布在集群中。

如果您想获得良好的聚合状态,我认为最好的方法是以下算法:对于EndpointState返回的每个值,查看LifecycleState.如果它们全部都是idle(即此时尚未使用的套接字池)或者connected集群是“绿色”。

9

以下是来自具有已启动的单个节点的集群的响应:

"details": {
        "couchbase": {
            "details": {
                "endpoints": [
                    {
                        "id": "0x2b1702f5",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:54978",
                        "remote": "/10.0.0.54:8093",
                        "state": "CONNECTED",
                        "type": "QUERY"
                    },
                    {
                        "id": "0x1cd735e",
                        "lastActivity": 4201999,
                        "local": "/10.0.0.54:54977",
                        "remote": "/10.0.0.54:8092",
                        "state": "CONNECTED",
                        "type": "VIEW"
                    },
                    {
                        "id": "0x35e7273e",
                        "lastActivity": 873334,
                        "local": "/10.0.0.54:54976",
                        "remote": "/10.0.0.54:11210",
                        "state": "CONNECTED",
                        "type": "BINARY"
                    }
                ],
                "sdk": "couchbase-java-client/2.5.9 (git: 2.5.9, core: 1.5.9) (Mac OS X/10.13.6 x86_64; Java HotSpot(TM) 64-Bit Server VM 1.8.0_181-b13)"
            },
            "status": "UP"
        }
    },
    "status": "UP"

以及一个已关闭的节点:

{
    "details": {
        "couchbase": {
            "details": {
                "endpoints": [
                    {
                        "id": "0x2b1702f5",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:54978",
                        "remote": "/10.0.0.54:8093",
                        "state": "CONNECTING",
                        "type": "QUERY"
                    },
                    {
                        "id": "0x1cd735e",
                        "lastActivity": 119509421,
                        "local": "/10.0.0.54:54977",
                        "remote": "/10.0.0.54:8092",
                        "state": "CONNECTING",
                        "type": "VIEW"
                    },
                    {
                        "id": "0x35e7273e",
                        "lastActivity": 6186669,
                        "local": "/10.0.0.54:54976",
                        "remote": "/10.0.0.54:11210",
                        "state": "CONNECTING",
                        "type": "BINARY"
                    }
                ],
                "sdk": "couchbase-java-client/2.5.9 (git: 2.5.9, core: 1.5.9) (Mac OS X/10.13.6 x86_64; Java HotSpot(TM) 64-Bit Server VM 1.8.0_181-b13)"
            },
            "status": "DOWN"
        }
    },
    "status": "DOWN"
}

两个节点均已启动:

{
    "details": {
        "couchbase": {
            "details": {
                "endpoints": [
                    {
                        "id": "0x2b1702f5",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:55218",
                        "remote": "/10.0.0.54:8093",
                        "state": "CONNECTED",
                        "type": "QUERY"
                    },
                    {
                        "id": "0x1cd735e",
                        "lastActivity": 311131257,
                        "local": "/10.0.0.54:55123",
                        "remote": "/10.0.0.54:8092",
                        "state": "CONNECTED",
                        "type": "VIEW"
                    },
                    {
                        "id": "0x35e7273e",
                        "lastActivity": 307530,
                        "local": "/10.0.0.54:55217",
                        "remote": "/10.0.0.54:11210",
                        "state": "CONNECTED",
                        "type": "BINARY"
                    },
                    {
                        "id": "0x609e7515",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:55341",
                        "remote": "/10.0.0.13:8093",
                        "state": "CONNECTED",
                        "type": "QUERY"
                    },
                    {
                        "id": "0x6995df17",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:55322",
                        "remote": "/10.0.0.13:8092",
                        "state": "CONNECTED",
                        "type": "VIEW"
                    },
                    {
                        "id": "0x7306c408",
                        "lastActivity": 2766411,
                        "local": "/10.0.0.54:55321",
                        "remote": "/10.0.0.13:11210",
                        "state": "CONNECTED",
                        "type": "BINARY"
                    }
                ],
                "sdk": "couchbase-java-client/2.5.9 (git: 2.5.9, core: 1.5.9) (Mac OS X/10.13.6 x86_64; Java HotSpot(TM) 64-Bit Server VM 1.8.0_181-b13)"
            },
            "status": "UP"
        }
    },
    "status": "UP"
}

以及两个节点,其中一个处于运行状态,一个处于关闭状态:

{
    "details": {
        "couchbase": {
            "details": {
                "endpoints": [
                    {
                        "id": "0x2b1702f5",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:55218",
                        "remote": "/10.0.0.54:8093",
                        "state": "CONNECTED",
                        "type": "QUERY"
                    },
                    {
                        "id": "0x1cd735e",
                        "lastActivity": 373391672,
                        "local": "/10.0.0.54:55123",
                        "remote": "/10.0.0.54:8092",
                        "state": "CONNECTED",
                        "type": "VIEW"
                    },
                    {
                        "id": "0x35e7273e",
                        "lastActivity": 1570432,
                        "local": "/10.0.0.54:55217",
                        "remote": "/10.0.0.54:11210",
                        "state": "CONNECTED",
                        "type": "BINARY"
                    },
                    {
                        "id": "0x609e7515",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:55341",
                        "remote": "/10.0.0.13:8093",
                        "state": "CONNECTING",
                        "type": "QUERY"
                    },
                    {
                        "id": "0x6995df17",
                        "lastActivity": 0,
                        "local": "/10.0.0.54:55322",
                        "remote": "/10.0.0.13:8092",
                        "state": "CONNECTING",
                        "type": "VIEW"
                    },
                    {
                        "id": "0x7306c408",
                        "lastActivity": 5062249,
                        "local": "/10.0.0.54:55321",
                        "remote": "/10.0.0.13:11210",
                        "state": "CONNECTING",
                        "type": "BINARY"
                    }
                ],
                "sdk": "couchbase-java-client/2.5.9 (git: 2.5.9, core: 1.5.9) (Mac OS X/10.13.6 x86_64; Java HotSpot(TM) 64-Bit Server VM 1.8.0_181-b13)"
            },
            "status": "DOWN"
        }
    },
    "status": "DOWN"
}

现在我们只需要决定如何在 2.0.x 中迁移到这个新模型。目前上述的实现是一个全新的健康指标。从技术上讲,这是一个重大更改(运行状况响应的详细信息不同,自动配置的 bean 类型也发生了变化),但我看不到一种方法可以在不进行某种形式的重大更改的情况下立即解决此问题。