[toc]
为啥
最近搞了一下优雅启停,作为一个项目,在部署后,如果遇到了升级,回退,容灾倒换,蓝绿切换,扩容,节点异常停止,节点重构啥的,该如何尽可能的保证无损,
当然无损肯定要和你项目的作用与定位相关,
场景
项目入口来分场景
- nginx转发: 如果是项目入口是处理nginx转发,在服务滚动升级的情况下,把当前的升级的节点,知会nginx,不让其转发请求即可,比如一个服务有a,b俩节点,a节点先升级,知会nginx将其加入黑名单,取消路由等,nginx自然将业务转发到b节点,适用于api调用
- kafka消费:如果项目作为下游,只是处理消费kafka消息,就尽快通知kafka此节点不消费此topic,注销消费者即可
- rpc调用: 这个最简单,就通知服务中心,该节点下线了,让服务中心不暴露此节点,
项目使用其他外部接口
- redis: 在服务主备倒换期间,对于redis的内存型数据肯定是不保证持续的,数据不可信,所以在异常时,一定要进行redis数据的及时清理, 项目减少对redis的强依赖,redis底层异常重试应该根据
- mongodb: mongodb作为持久性数据,还可以主备复制,在容灾场景下,数据是可信的,但是要设置好同步数据的时间,
- mongodb要保证容灾倒换时,存储的一些节点及路由信息,能恢复或者不依赖mongodb的存储信息,一般的主备就是主节点有mongodb的读写权限,备节点只有读权限,倒换时,添加写权限给备站点,当然还是蓝绿思想好(两套站点平时都能使用,升级时导流到一个站点,另一个做升级,验证完成后,再升级另一个站点,无损升级目前较好的方式。)
如何触发优雅操作
这个其实就要和jvm交互了,因为项目本身感知到外界信号的能力是没有的,只能通过jvm添加事件来处理外部信号
例如: kill -3 -9 -15
kill -3 终端的退出信号。缺省情况下,这将触发 Javadump。看线程当前情况,贼好用
jvm 的signal的处理
这个就要用到jvm的钩子了(shutdown hooks)
你正常运行结束,或者kill -9,-15 就可以的,
import java.util.concurrent.CountDownLatch;
public class Kill15 {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread(()-> {
System.out.println("优雅");
}));
CountDownLatch countDownLatch=new CountDownLatch(1);
try {
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
上面的addShutdownHook的方式不好
建议用Sign注册的方式进行
public class SignHand implements SignalHandler {
public void regisetSignal(String name){
Signal signal=new Signal(name);
Signal.handle(signal,this);
}
@Override
public void handle(Signal signal) {
System.out.println("00000000000000");
}
}
public static void main(String[] args) {
SignHand signalHand=new SignHand();
signalHand.regisetSignal("TERM");
}
shutdownhook与sign对比
shutdownhook如果注册了多个,不保证执行顺序,多线程还有问题,
sign 参考:JVM安全退出
发表回复