微服务前置检查框架实践

前言

微服务架构中,前置检查功能项对于服务的可靠性有重要意义,使用场景如:

1、如检查基础服务,如不正常需要熔断

2、如检查被依赖服务,不正常需要熔断

3、本服务有较长的初始化逻辑,需要完成后,才能通知提供正常REST功能

实践

import com.google.common.util.concurrent.ThreadFactoryBuilder;import lombok.extern.slf4j.Slf4j;import java.util.List;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;import java.util.function.Consumer;@Slf4jpublic class ApplicationStartupChecker { private boolean checkSwitch = true; private ScheduledExecutorService scheduledExecutorService; private Consumer passConsumer; private AdvanceCheckRegister advanceCheckRegister = new AdvanceCheckRegisterImpl(); private String threadName; private int checkCycle; private TimeUnit timeUnit; private int checkCount = 0; public ApplicationStartupChecker(String threadName, int checkCycle, TimeUnit timeUnit) { scheduledExecutorService = new ScheduledThreadPoolExecutor( 1, new ThreadFactoryBuilder().setNameFormat(threadName + “-%d”).setDaemon(true).build()); this.threadName = threadName; this.checkCycle = checkCycle; this.timeUnit = timeUnit; } public ApplicationStartupChecker(String threadName) { this(threadName, 30, TimeUnit.SECONDS); } public void bootstrap() { if (scheduledExecutorService.isShutdown() || scheduledExecutorService.isTerminated()) { scheduledExecutorService = new ScheduledThreadPoolExecutor( 1, new ThreadFactoryBuilder().setNameFormat(threadName + “-%d”).build()); } scheduledExecutorService.schedule(this::guidance, 0, TimeUnit.SECONDS); } private void guidance() { if (!checkSwitch) { scheduledExecutorService.shutdown(); log.info(“Not need check”); if (passConsumer != null) { passConsumer.accept(advanceCheckRegister.getCheckerNames()); } } checkCount++; log.info(“No.{} app startup checking”, checkCount); try { advanceCheckRegister.foreach(Checker::check); } catch (Throwable e) { log.error(“check with error.”, e); } boolean pass = advanceCheckRegister.pass(); if (pass) { scheduledExecutorService.shutdown(); log.info(“All check passed:{}”, String.join(“,”, advanceCheckRegister.getCheckerNames())); if (passConsumer != null) { passConsumer.accept(advanceCheckRegister.getCheckerNames()); } } else { scheduledExecutorService.schedule(this::guidance, this.checkCycle, this.timeUnit); } } public void setPassConsumer(Consumer passConsumer) { this.passConsumer = passConsumer; } public void addChecker(Checker kafkaHealthChecker) { advanceCheckRegister.registerEntity(kafkaHealthChecker); }}

配置用于保存检查项:

import java.util.List;import java.util.function.Consumer;public interface AdvanceCheckRegister { void registerEntity(Checker checkEntity); boolean pass(); void foreach(Consumer consumer); List getCheckerNames();}package com.zte.sdn.oscp.check;import java.util.ArrayList;import java.util.List;import java.util.Objects;import java.util.function.Consumer;import java.util.stream.Collectors;public class AdvanceCheckRegisterImpl implements AdvanceCheckRegister { private final List checkEntityList = new ArrayList(); @Override public void registerEntity(Checker entity) { Objects.requireNonNull(entity,”Register Checker can not be null.”); if ( entity.getName() == null || entity.getName().isEmpty()) { throw new IllegalArgumentException(entity.getClass().getSimpleName()+” must have valid name”); } checkEntityList.add(entity); } @Override public boolean pass() { return this.checkEntityList.stream().allMatch(Checker::isPass); } @Override public void foreach(Consumer consumer) { for (Checker checkEntity : checkEntityList) { boolean check = checkEntity.check(); checkEntity.setPass(check); if (!check) { return; } } } @Override public List getCheckerNames() { return checkEntityList.stream().map(Checker::getName).collect(Collectors.toList()); }}

检测项接口

public interface Checker { String getName(); boolean check(); boolean isPass(); void setPass(boolean pass);}package com.zte.sdn.oscp.check;public abstract class AbstractChecker implements Checker { private boolean pass; @Override public boolean isPass() { return this.pass; } @Override public void setPass(boolean pass) { this.pass = pass; }}

检查项

新增Checker项,只需要继承指定接口,实现检测逻辑,即可

public class DataBaseHealthChecker extends AbstractChecker { @Override public String getName() { return “DataBaseHealthChecker”; } @Getter @VisibleForTesting private int count; @Override public boolean check() { count++; if (count >= 3) { return true; } return false; }}

测试

循环检测直至通过,通过后回调对应方法,不过这是单独线程,不会阻塞主线

public class CheckTest { @Test public void checkTest() throws InterruptedException { ApplicationStartupChecker applicationStartupChecker = new ApplicationStartupChecker(“abc”); KafkaHealthChecker kafkaHealthChecker = new KafkaHealthChecker(); DataBaseHealthChecker dataBaseHealthChecker = new DataBaseHealthChecker(); applicationStartupChecker.addChecker(kafkaHealthChecker); applicationStartupChecker.addChecker(dataBaseHealthChecker); CountDownLatch latch = new CountDownLatch(1); applicationStartupChecker.setPassConsumer(t -> { latch.countDown(); }); applicationStartupChecker.bootstrap(); latch.await(); int kafkaCheck = kafkaHealthChecker.getCount(); int dbCheck = dataBaseHealthChecker.getCount(); Assert.assertEquals(5, kafkaCheck, 0.0); Assert.assertEquals(3, dbCheck, 0.0); } @Test public void checkTestNOChecker() throws InterruptedException { ApplicationStartupChecker applicationStartupChecker = new ApplicationStartupChecker(“abc”); CountDownLatch latch = new CountDownLatch(1); applicationStartupChecker.setPassConsumer(t -> { latch.countDown(); }); applicationStartupChecker.bootstrap(); latch.await(); } @Test public void checkTestNoConsumer() throws InterruptedException { ApplicationStartupChecker applicationStartupChecker = new ApplicationStartupChecker(“abc”); KafkaHealthChecker kafkaHealthChecker = new KafkaHealthChecker(); DataBaseHealthChecker dataBaseHealthChecker = new DataBaseHealthChecker(); applicationStartupChecker.addChecker(kafkaHealthChecker); applicationStartupChecker.addChecker(dataBaseHealthChecker); applicationStartupChecker.bootstrap(); while (dataBaseHealthChecker.getCount() < 3) { TimeUnit.SECONDS.sleep(5); } Assert.assertEquals(5, kafkaHealthChecker.getCount(), 0.0); Assert.assertEquals(3, dataBaseHealthChecker.getCount(), 0.0); } @Test public void checkTestNoConsumerTimeOut() throws InterruptedException { ApplicationStartupChecker applicationStartupChecker = new ApplicationStartupChecker("abc", 2, TimeUnit.SECONDS); KafkaHealthChecker kafkaHealthChecker = new KafkaHealthChecker(); DataBaseHealthChecker dataBaseHealthChecker = new DataBaseHealthChecker(); applicationStartupChecker.addChecker(kafkaHealthChecker); applicationStartupChecker.addChecker(dataBaseHealthChecker); applicationStartupChecker.bootstrap(); while (dataBaseHealthChecker.getCount() { latch.countDown(); }); applicationStartupChecker.bootstrap(); applicationStartupChecker.bootstrap(); applicationStartupChecker.bootstrap(); applicationStartupChecker.bootstrap(); latch.await(); int kafkaCheck = kafkaHealthChecker.getCount(); int dbCheck = dataBaseHealthChecker.getCount(); Assert.assertEquals(5, kafkaCheck, 0.0); Assert.assertEquals(3, dbCheck, 0.0); }}

其它

如果想产生检查不通过,程序不进行下一步动作的强依赖,实际上也简单,只需要在ApplicationStartupChecker中增加

>private CountDownLatch wait=new CountDownLatch(1);

检查通过后减1,主程序中await即可。

郑重声明:本文内容及图片均整理自互联网,不代表本站立场,版权归原作者所有,如有侵权请联系管理员(admin#wlmqw.com)删除。
(0)
用户投稿
上一篇 2022年6月13日
下一篇 2022年6月13日

相关推荐

  • 新手入门最简单实用机型,极空间Z2S,应该是2022年最值得入手

    距离上一次写关于NAS 的文章已经时隔快一年,这一年中NAS的发展可以说变化非常快,目前市场上的品牌也在发生着变化,现在NAS阵营从曾经威联通、群晖等涿鹿天下的时代,已经变成了多品…

    2022年6月20日
  • 全种类电风扇选购总攻略-炎炎夏日,清风徐来

    Q:在这个空调当道的日下,电风扇在家庭中还有一席之地吗? A:当然有!电风扇自1882年发明至今,100多年的时间一直没有退出历史舞台,必定有它独有的优势。电风扇是加速物体表面的空…

    2022年8月19日
  • 微信语音怎么转发给别人(微信语音转发的3种方法)

    用了微信这么多年,大家知道文字内容可以转发,视频内容可以转发,但万万没想到语音信息居然不能转发? 在这种操作下,感觉和好朋友一起快速吃瓜的快乐都少了一半,毕竟语音描述往往比文字描述…

    2022年5月6日
  • 微信又添新功能!网友:太实用了

    最新消息 微信正式推出 青少年模式支付限额功能 现在,只要将手机更新到微信安卓版本8.0.23后,父母或监护人就可在青少年模式中设置微信支付的限额,包括“每日消费限额”和“单次消费…

    2022年7月2日
  • 自由之刃魂环版本传奇新手如何快速得元宝?新手必看

    哈喽!大家好 我是小森 今天来说一下自由之刃的新手攻略 进去先跟着主线走获得元宝 击败怪物也有几率直接掉落元宝。其次可以通过回收装备,将打怪掉落的多余装备进行回收,就可以获得元宝。…

    2022年7月10日
  • 近期韭菜市场需要关注的主线

    行业跟踪 生物制品:随大盘涨跌消费医疗:较抗跌 船舶高温合金走势较强 行情没结束新冠在控制下 光伏 hjt topcon新技术环节强 板块走趋势电力:短期有催化中长逻辑较强 家电:…

    2022年8月3日
  • 坐轿子侮辱了轿夫的人格尊严吗?

    新闻说,有博主坐轿上山,被指责“花钱糟蹋他人尊严”。 指责的人显然对“尊严”有误解,他们忽略了背后的生活逻辑,不食人间烟火。 在他们眼中,坐轿子是尊贵的,抬轿子是卑微的,坐轿子的在…

    2022年8月29日
  • Controller层代码这么写,简洁又优雅

    一个优秀的Controller层逻辑 说到 Controller,相信大家都不陌生,它可以很方便地对外提供数据接口。它的定位,我认为是「不可或缺的配角」,说它不可或缺是因为无论是传…

    2022年8月4日
  • 重磅来袭!2022年红点奖部分获奖作品大赏

    红点奖,源自德国,是与IF设计奖齐名的一个工业设计大奖,是世界上知名设计竞赛中最大最有影响的竞赛。红点奖与德国“IF奖”、美国“IDEA奖”一起并称为世界三大设计奖。 REDDOT…

    2022年6月26日
  • 2022年测距仪选购攻略:迈测R2激光测距仪全功能体验

    如何选择测距仪? 一言以蔽之:精度要到位,功能要全面,做工要细致。三方面优先级顺次降低,切忌不要因为颜值养眼慌了神。测距仪是工具,不是手办,外观应该排在最次位考虑。 但是,屏幕高清…

    2022年7月26日

联系我们

联系邮箱:admin#wlmqw.com
工作时间:周一至周五,10:30-18:30,节假日休息