文档章节

记一次线上故障的排查过程

AbeJeffrey
 AbeJeffrey
发布于 2017/08/08 21:32
字数 3056
阅读 5.5K
收藏 2

背景:新功能开发测试完成后,准备发布上线,当发布完第三台机器时,监控显示其中一台机器CPU突然飙升到300%,Dubbo活动线程数直接飙到1000+,不得不停止发布,立马回滚出问题的机器,回滚之后恢复正常;继续观察另外两台已经发布的机器,最终,无一幸免,只能全部回滚了。

下面是我的故障排查过程:

监控日志分析

首先查看故障时间点的应用日志,发现大量方法耗时较久,其中filterMission方法尤为显著,耗时长达30S+。说明下,filterMission是当前服务中QPS较高的接口(日均调用量2个亿),所以导致故障的可能性也较高。于是重新review了一遍filterMission的实现,其中并无复杂的计算逻辑,没有大量数据的处理逻辑,也不存在锁的争用,本次需求更是不涉及filterMission的改造,排除filterMission导致故障发生。

从日志中也可以发现,大量请求发生超时,这些都只能说明系统负载过重,并不能定位问题的症结所在。

Code Review

从应用日志找不到原因所在,只能再做一次code review了。首先检查系统中是否存在同步代码逻辑的使用,主要是为了排除发生死锁的可能;检查具有复杂运算逻辑的代码;同时,将本次修改的代码和上一版本进行比对,也没找出什么问题。(事实证明,Review不够仔细)

线程Dump分析

到此,从日志中暂时也分析不出问题,盲目看代码也无法具体定位问题了,现在只能重新发布一台机器,出现问题时让运维将应用程序的线程堆栈dump出来,分析jstack文件。开始分析dump文件前,先巩固下基础吧。

线程状态

图中各状态说明:

New: 新建状态,当线程对象创建时存在的状态;

Runnable:ready-to-run,可运行状态,调用thread.start()后,线程变成为Runnable状态,还需要获得CPU才能运行;

Running:正在运行,当调用Thread.yield()或执行完时间片,CPU会重新调度;注意:Thread.yield()调用之后,线程会释放CPU,但是CPU重新调度可能让线程重新获得时间片。

Waiting:调用thread.join()、object.wait()和LockSupport.park()线程都会进入该状态,表明线程正处于等待某个资源或条件发生来唤醒自己;thread.join()、object.wait()需要Object的notify()/notifyAll()或发生中断来唤醒,LockSupport.park()需要LockSupport.unpark()来唤醒,这些方法使线程进入Runnable状态,参与CPU调度。

thread.join():作用是等待线程thread终止,只有等thread执行完成后,主线程才会继续向下执行;从join()实现可知,主线程调用thread.join()之后,只有thread.isAlive()返回true,才会调用object.wait()使主线程进入等待状态,也就是说,thread.start()未被调用,或thread已经结束,object.wait()都不会被调用。也就是说,必须先启动线程thread,调用thread.join()才会生效;若主线程在waiting状态被唤醒,会再次判断thread.isAlive(),若为true,继续调用object.wait()使进入waiting状态,直到thread终止,thread.isAlive()返回false。

object.wait():作用是使线程进入等待状态,只有线程持有对象上的锁,才能调用该对象的wait(),线程进入等待状态后会释放其持有的该对象上的锁,但会仍然持有其它对象的锁。若其他线程想要调用notify()、notifyAll()唤醒该线程,也需要持有该对象的锁。

LockSupport.park():挂起当前线程,不参与线程调度,除非调用LockSupport.unpark()重新参与调度。

Timed_Waiting:调用Thread.sleep(long)、LockSupport.parkNanos(long)、thread.join(long)或obj.wait(long)等都会使线程进入该状态,与Waiting的区别在于Timed_Waiting的等待有时间限制;

Thread.sleep():让当前线程停止运行指定的毫秒数,该线程不会释放其持有的锁等资源。

Blocked:指线程正在等待获取锁,当线程进入synchronized保护的代码块或方法时,没有获取到锁,则会进入该状态;或者线程正在等待I/O,也会进入该状态。注意,java中Lock对象不会使线程进入该状态。

Dead:线程执行完毕,或者抛出了未捕获的异常之后,会进入dead状态,表示该线程结束。

上图中某些状态只是为了方便说明,实际并不存在,如running/sleeping,java中明确定义的线程状态值有如下几个:

NEW、RUNNABLE、BLOCKED、WAITING、TIMED_WAITING、TERMINATED

分析jstack日志

  • 大量dubbo线程处于WAITING状态,看日志:
"DubboServerHandler-172.24.16.78:33180-thread-1220" #1700 daemon prio=5 os_prio=0 tid=0x00007f3394988800 nid=0x4aae waiting on condition [0x00007f32d75c0000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x00000000866090c0> (a java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(AbstractQueuedSynchronizer.java:2039)
	at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:1081)
	at java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(ScheduledThreadPoolExecutor.java:809)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

由日志可知道,线程“DubboServerHandler-172.24.16.78:33180-thread-1220”处于WAITING状态,主要原因是线程从线程池队列中取任务来执行,但线程池为空,最终调用了LockSupport.park使线程进入等待状态,需要等待队列非空的通知。

设想一下,什么时候会新创建新线程来处理请求?结合jdk线程池实现可知,当新请求到来时,若池中线程数量未达到corePoolSize,线程池就会直接新建线程来处理请求。

根据jstack日志,有195个dubbo线程从ScheduledThreadPoolExecutor中取任务导致处于WAITING状态,按理这些dubbo线程只负责处理客户端请求,不会处理调度任务,为什么会去调度任务线程中取任务呢?这里暂时抛出这个问题吧,我也不知道答案,希望有大神帮忙解答。

  • 还有另外一部分WAITING状态的线程,看日志:
"DubboServerHandler-172.24.16.78:33180-thread-1489" #1636 daemon prio=5 os_prio=0 tid=0x00007f33b0122800 nid=0x48ec waiting on condition [0x00007f32db600000]
   java.lang.Thread.State: WAITING (parking)
	at sun.misc.Unsafe.park(Native Method)
	- parking to wait for  <0x0000000089d717a8> (a java.util.concurrent.SynchronousQueue$TransferStack)
	at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(SynchronousQueue.java:458)
	at java.util.concurrent.SynchronousQueue$TransferStack.transfer(SynchronousQueue.java:362)
	at java.util.concurrent.SynchronousQueue.take(SynchronousQueue.java:924)
	at java.util.concurrent.ThreadPoolExecutor.getTask(ThreadPoolExecutor.java:1067)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1127)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

这部分dubbo线程主要是因为从ThreadPoolExecutor取任务来执行时被挂起(309个线程),这些线程正常处理完第一个请求后,就会回到线程池等待新的请求。由于这里使用newFixedThreadPool作为dubbo请求处理池,因此每个新请求默认都会创建新线程来处理,除非达到池的限定值。只有达到线程池最大线程数量,新的请求来临才会被加入任务队列,哪些阻塞在getTask()的线程才会得到复用。

  • 此外,还有大量dubbo线程处于BLOCKED状态,看日志:
"DubboServerHandler-172.24.16.78:33180-thread-236" #1727 daemon prio=5 os_prio=0 tid=0x00007f336403b000 nid=0x4b8b waiting for monitor entry [0x00007f32d58a4000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.checkRollover(RollingFileManager.java:149)
	- waiting to lock <0x0000000085057998> (a org.apache.logging.log4j.core.appender.rolling.RollingRandomAccessFileManager)
	at org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender.append(RollingRandomAccessFileAppender.java:88)
	at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:155)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:128)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:119)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
	at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:390)
	at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:375)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:359)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:349)
	at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:63)
	at org.apache.logging.log4j.core.Logger.logMessage(Logger.java:146)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1993)
	at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1852)
	at org.apache.logging.slf4j.Log4jLogger.info(Log4jLogger.java:179)
	at com.alibaba.dubbo.common.logger.slf4j.Slf4jLogger.info(Slf4jLogger.java:42)
	at com.alibaba.dubbo.common.logger.support.FailsafeLogger.info(FailsafeLogger.java:93)
	at com.dianwoba.universe.dubbo.filter.ResponseFilter$1.run(ResponseFilter.java:116)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
	at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

waiting for monitor entry :说明当前线程正处于EntryList队列中,等待获取监视器锁。

说明:Java中synchronized的同步语义主要基于Java对象头和monitor实现,每个monitor同一时间只能由一个线程拥有,其他想要获取该monitor只能等待,其中monitor具有两个队列:WaitSet 和 EntryList。当某个线程在拥有monitor时,调用了Object.wait(),则会释放monitor,进入WaitSet队列等待,此时线程状态为WAITING,WaitSet中的等待的状态是 “in Object.wait()”。当其他线程调用Object的notify()/notifyAll()唤醒该线程后,将会重新竞争monitor;当某个线程尝试进入synchronized代码块或方法时,获取monitor失败则会进入EntryList队列,此时线程状态为BLOCKED,EntryList中等待的状态为“waiting for monitor entry”。

根据jstack日志,有377个dubbo线程在等待锁定资源“0x0000000085057998”,从堆栈可知,这些线程都在竞争RollingRandomAccessFileManager的monitor,让我们看看那个线程拥有了该监视器,看日志:

"DubboServerHandler-172.24.16.78:33180-thread-429" #553 daemon prio=5 os_prio=0 tid=0x00007f339c09f800 nid=0x4467 waiting for monitor entry [0x00007f331f53a000]
   java.lang.Thread.State: BLOCKED (on object monitor)
	at org.apache.logging.log4j.core.appender.rolling.RollingFileManager.checkRollover(RollingFileManager.java:149)
	- locked <0x0000000085057998> (a org.apache.logging.log4j.core.appender.rolling.RollingRandomAccessFileManager)
	at org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender.append(RollingRandomAccessFileAppender.java:88)
	at org.apache.logging.log4j.core.config.AppenderControl.tryCallAppender(AppenderControl.java:155)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender0(AppenderControl.java:128)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppenderPreventRecursion(AppenderControl.java:119)
	at org.apache.logging.log4j.core.config.AppenderControl.callAppender(AppenderControl.java:84)
	at org.apache.logging.log4j.core.config.LoggerConfig.callAppenders(LoggerConfig.java:390)
	at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:375)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:359)
	at org.apache.logging.log4j.core.config.LoggerConfig.logParent(LoggerConfig.java:381)
	at org.apache.logging.log4j.core.config.LoggerConfig.processLogEvent(LoggerConfig.java:376)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:359)
	at org.apache.logging.log4j.core.config.LoggerConfig.log(LoggerConfig.java:349)
	at org.apache.logging.log4j.core.config.AwaitCompletionReliabilityStrategy.log(AwaitCompletionReliabilityStrategy.java:63)
	at org.apache.logging.log4j.core.Logger.logMessage(Logger.java:146)
	at org.apache.logging.log4j.spi.AbstractLogger.logMessage(AbstractLogger.java:1993)
	at org.apache.logging.log4j.spi.AbstractLogger.logIfEnabled(AbstractLogger.java:1852)
	at org.apache.logging.slf4j.Log4jLogger.warn(Log4jLogger.java:239)
	at com.alibaba.dubbo.common.logger.slf4j.Slf4jLogger.warn(Slf4jLogger.java:54)
	at com.alibaba.dubbo.common.logger.support.FailsafeLogger.warn(FailsafeLogger.java:107)
	at com.alibaba.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:48)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
	at com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:78)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
	at com.alibaba.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:60)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
	at com.alibaba.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:112)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
	at com.alibaba.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
	at com.alibaba.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:38)
	at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
	at com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol$1.reply(DubboProtocol.java:108)
	at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.handleRequest(HeaderExchangeHandler.java:84)
	at com.alibaba.dubbo.remoting.exchange.support.header.HeaderExchangeHandler.received(HeaderExchangeHandler.java:170)
	at com.alibaba.dubbo.remoting.transport.DecodeHandler.received(DecodeHandler.java:52)
	at com.alibaba.dubbo.remoting.transport.dispatcher.ChannelEventRunnable.run(ChannelEventRunnable.java:82)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

看到该线程的堆栈就一脸懵b了,它已经锁定了资源“0x0000000085057998”,但仍然处于BLOCKED状态,是不是有死锁的味道?但是这里不是死锁,最可能的原因是:

  • 线程没有获得运行所需的资源;
  • JVM正在进行fullGC

从这部分日志可知,大部分线程阻塞在打印监控日志的过程中,所以很多请求出现超时。主要原因可能是CPU占用率高,持有锁的线程处理过程非常慢,导致越来越多的线程在锁竞争中被阻塞,整体性能下降。

到此,仍然没有找到问题的原因,再一次观察资源占用情况,发现当出现问题时,内存占用持续增长,且无下降痕迹,然后找运维dump了一份GC日志,发现JVM一直在做fullGC,而每次GC之后内存基本没变化,说明程序中发生了内存泄漏。最后定位到发生内存泄漏的地方是一个分页查询接口,SQL语句中漏掉了limit,offset,够初心大意了。

这尼玛一次性将整张表的数据查出来(300万),还要对300万记录循环处理一遍,这内存不爆掉就怪了。正是因为该原因,导致内存长时间没有释放,JVM执行fullGC无法回收内存,导致持续做fullGC,CPU被耗尽,无法处理应用请求。

综上,罪魁祸首是发生了内存泄漏,JVM一直做fullGC,导致CPU突然飙升,Dubbo活动线程数增大,锁竞争严重,请求处理超时。根据以上分析,同时也暴露了另外一个不合理的问题:dubbo线程池数量配置过大,最大值为1500,也就是说最终线程池中会有1500个线程来处理用户请求,当并发量高时,活动线程数增加,CPU频繁进行上下文切换,系统的吞吐率并不会太高。这是一个优化点。

本文记录该过程,一方面是为了记录曾经踩过的坑,同时提高自己的故障分析和处理能力。当需要问题时,一定不要着急,学会分析问题,一步步找到问题所在。尤其是遇到线上问题时,由于无法调试,一定要在应用中做监控,当出现问题时,一定要结合日志来分析,业务中的问题结合业务日志,性能问题结合内存dump日志和线程dump日志等等。

欢迎指出本文有误的地方!

© 著作权归作者所有

AbeJeffrey
粉丝 49
博文 43
码字总数 116095
作品 0
杭州
高级程序员
私信 提问
加载中

评论(7)

给你一颗糖
给你一颗糖
博主我也遇到了大量  DubboClientHandler-10.25.159.32:20990-thread-135 这种time_waiting的情况,而且很规律,半个小时激增150个线程然后两分钟后又回收了,请问有什么排查建议吗
AbeJeffrey
AbeJeffrey 博主

引用来自“ismallboy”的评论

能分享一下这个过程么——“最后定位到发生内存泄漏的地方是一个分页查询接口,SQL语句中漏掉了limit,offset,够初心大意了”,谢谢~

引用来自“AbeJeffrey”的评论

灰度测试发现的

引用来自“ismallboy”的评论

:bowtie:还想着学习一下heapdump的分析过程咧~嘿嘿~楼主有相关的经验,可以分享一下
后续另起文章介绍下
ismallboy
ismallboy

引用来自“ismallboy”的评论

能分享一下这个过程么——“最后定位到发生内存泄漏的地方是一个分页查询接口,SQL语句中漏掉了limit,offset,够初心大意了”,谢谢~

引用来自“AbeJeffrey”的评论

灰度测试发现的
:bowtie:还想着学习一下heapdump的分析过程咧~嘿嘿~楼主有相关的经验,可以分享一下
AbeJeffrey
AbeJeffrey 博主

引用来自“ismallboy”的评论

能分享一下这个过程么——“最后定位到发生内存泄漏的地方是一个分页查询接口,SQL语句中漏掉了limit,offset,够初心大意了”,谢谢~
灰度测试发现的
ismallboy
ismallboy
能分享一下这个过程么——“最后定位到发生内存泄漏的地方是一个分页查询接口,SQL语句中漏掉了limit,offset,够初心大意了”,谢谢~
AbeJeffrey
AbeJeffrey 博主

引用来自“程序员小兵”的评论

谢谢楼主 帮了我很多
但我有个疑问啊
-----
由日志可知道,线程“DubboServerHandler-172.24.16.78:33180-thread-1220”处于WAITING状态,主要原因是线程从线程池队列中取任务来执行,但线程池为空,最终调用了LockSupport.park使线程进入等待状态,需要等待队列非空的通知。
-----

这个我看堆栈信息是 DelayedWorkQueue.take 导致的。DelayedWorkQueue 中的元素第一个元素永远是 delay 时间最小的那个元素,如果 delay 没有到期,take 的时候便会 block 住。 这里是 任务没到期 或者没有任务 阻塞的把


-----
这部分dubbo线程主要是因为从ThreadPoolExecutor取任务来执行时被挂起(309个线程),这些线程正常处理完第一个请求后,就会回到线程池等待新的请求。由于这里使用newFixedThreadPool作为dubbo请求处理池,因此每个新请求默认都会创建新线程来处理,除非达到池的限定值。只有达到线程池最大线程数量,新的请求来临才会被加入任务队列,哪些阻塞在getTask()的线程才会得到复用。
------
我看堆栈是 SynchronousQueue是应该用的这个 newCachedThreadPool 静态方法创建的线程执行者把

这个dubbo线程池 相对于 ScheduledThreadPoolExecutor 线程池 是生产者 还是 消费者啊
多谢补充说明。我们确实是按newFixedThreadPool模式来创建线程池,只不过是根据配置来选择不同的队列
程序员小兵
程序员小兵
谢谢楼主 帮了我很多
但我有个疑问啊
-----
由日志可知道,线程“DubboServerHandler-172.24.16.78:33180-thread-1220”处于WAITING状态,主要原因是线程从线程池队列中取任务来执行,但线程池为空,最终调用了LockSupport.park使线程进入等待状态,需要等待队列非空的通知。
-----

这个我看堆栈信息是 DelayedWorkQueue.take 导致的。DelayedWorkQueue 中的元素第一个元素永远是 delay 时间最小的那个元素,如果 delay 没有到期,take 的时候便会 block 住。 这里是 任务没到期 或者没有任务 阻塞的把


-----
这部分dubbo线程主要是因为从ThreadPoolExecutor取任务来执行时被挂起(309个线程),这些线程正常处理完第一个请求后,就会回到线程池等待新的请求。由于这里使用newFixedThreadPool作为dubbo请求处理池,因此每个新请求默认都会创建新线程来处理,除非达到池的限定值。只有达到线程池最大线程数量,新的请求来临才会被加入任务队列,哪些阻塞在getTask()的线程才会得到复用。
------
我看堆栈是 SynchronousQueue是应该用的这个 newCachedThreadPool 静态方法创建的线程执行者把

这个dubbo线程池 相对于 ScheduledThreadPoolExecutor 线程池 是生产者 还是 消费者啊
CPU100%问题快速定位思路

在我日常运维工作中,无论自己 或同事、朋友总会问我,服务器CPU使用率100%,卡死了,这样的话,那今天咱们就一起模拟故障,进行细致的分析,首先介绍下,CPU出现问题的几种原因: 一、CPU 1...

邱月涛
2018/06/04
0
0
一个系统,搞定闲鱼服务端复杂问题告警-定位-快速处理

引言 服务端问题排查(服务稳定性/基础设施异常/业务数据不符合预期等)对于开发而言是家常便饭,问题并不可怕,但是每天都要花大量时间去处理问题会很可怕;另一方面故障的快速解决至关重要。...

阿里云云栖社区
2019/07/25
41
0
解Bug之路-记一次中间件导致的慢SQL排查过程

解Bug之路-记一次中间件导致的慢SQL排查过程 前言 最近发现线上出现一个奇葩的问题,这问题让笔者定位了好长时间,期间排查问题的过程还是挺有意思的,正好博客也好久不更新了,就以此为素材...

无毁的湖光-Al
2018/12/27
1.8K
20
pt-online-schema-change你今天滥用了吗?

注:本文来自真实生产案例,感谢网友小豚提供,本人加以故障重现校验。 场景 因想整理一下线上的独立表空间碎片,故使用了pt-online-schema-change在slave从库上执行,目的是怕影响主库的CPU...

hcymysql
2016/12/06
0
0
线上问题处理方案

接到线上问题应该如何去做 处理线上问题第一原则:先保障线上服务可用性,第一时间降低故障影响范围。 机动人员处理问题流程: 第一时间在问题群内同步自己开始跟进问题 评估问题影响范围,确...

美团点评点餐
2017/12/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何创建spring-boot的web项目

第一步:新建一个maven项目 新建项目,选择maven 填写GroupId和ArtifactId 下一步默认即可,直接点击finish 创建完成后项目结构如下 第二步: 配置pom.xml 在pom.xml中添加如下代码: <p...

幻境fairy
6分钟前
22
0
「网易官方」极客战记(codecombat)攻略-地牢-Kithgard 斗殴-kithgard-brawl

每次你从一波波的敌人中存活下来,就会变得更难。但是你如果你输了,你必须要等一天后才能再次提交。 简介 这是一个无尽的挑战关卡,敌人会一波波地向你发起进攻,一次比一次强大,直到你坚持...

极客战记
8分钟前
46
0
基于数据回放功能开发的线性挂单流策略

前言 人们常说,交易是一门艺术,而艺术来源于灵感。所以今天想和大家分享一下,如何利用发明者量化数据回放功能,发掘自己的交易灵感。 交易的灵感和盘感 通常我们所说的灵感,是指人们在思...

发明者量化
13分钟前
20
0
技术答疑丨如何区分游戏短音乐与音效以及配音

在游戏的声音领域,一般游戏音乐、音效与配音,但是每个类别又有不同的细分,在我们奇亿音乐与游戏厂商的日常沟通中,发现这些问题一直困扰着大家,一起来看看吧。 1、如何区分游戏的音效与配...

奇亿音乐
13分钟前
66
0
如何在mac上录屏

新上手的苹果电脑,想要完成录屏操作还不知道从哪下手的小伙伴有福利了,小编今天分享如何在mac上录屏内容,需要的来一起了解吧~ 如何在mac上录屏 Aiseesoft Screen Recorder for Mac(录屏软...

麦克虾仔
26分钟前
40
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部