日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
快放開那些搗亂的猴子!

粗看標(biāo)題你可能感覺莫名其妙,什么「搗亂的猴子」,還要放開。不急,且聽我說說為什么不光要放開這些搗亂的猴子,還要?dú)g迎他們。

靈山ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場景,ssl證書未來市場廣闊!成為創(chuàng)新互聯(lián)建站的ssl證書銷售渠道,可以享受市場價格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:028-86922220(備注:SSL證書合作)期待與您的合作!

0.背景信息

在構(gòu)建高可用性軟件架構(gòu)領(lǐng)域,有個詞叫「混沌工程」,對應(yīng)的英文是Chaos Engineering,通過 Chaos 的測試,可以發(fā)現(xiàn)系統(tǒng)的潛在風(fēng)險,特別對于分布式系統(tǒng),找出脆弱的地方進(jìn)行增強(qiáng),提升可用性,避免系統(tǒng)間級聯(lián)影響。

混沌工程是在分布式系統(tǒng)上進(jìn)行實驗的學(xué)科, 目的是建立對系統(tǒng)抵御生產(chǎn)環(huán)境中失控條件的能力以及信心。

大規(guī)模分布式軟件系統(tǒng)的發(fā)展正在改變軟件工程。作為一個行業(yè),我們很快采用了提高開發(fā)靈活性和部署速度的實踐。緊隨著這些優(yōu)點(diǎn)的一個迫切問題是:我們對投入生產(chǎn)的復(fù)雜系統(tǒng)有多少信心?

即使分布式系統(tǒng)中的所有單個服務(wù)都正常運(yùn)行, 這些服務(wù)之間的交互也會導(dǎo)致不可預(yù)知的結(jié)果。 這些不可預(yù)知的結(jié)果, 由影響生產(chǎn)環(huán)境的罕見且破壞性的事件復(fù)合而成,令這些分布式系統(tǒng)存在內(nèi)在的混沌。

https://principlesofchaos.org/zh/

后來Netflix 開源了其關(guān)于混沌工程的實現(xiàn) ChaosMonkey,以猴子的形象來代表在系統(tǒng)里出其不意的破壞者。

比如

  • 機(jī)器或者一個機(jī)房掛了
  • 一部分網(wǎng)絡(luò)延遲嚴(yán)重
  • CPU、內(nèi)存占用嚴(yán)重
  • 隨機(jī)讓某些服務(wù)異?;蛘唔憫?yīng)延遲

再看Chaos 原則里提到的這些:

  • 當(dāng)服務(wù)不可用時的不正確回滾設(shè)置;
  • 不當(dāng)?shù)某瑫r設(shè)置導(dǎo)致的重試風(fēng)暴;
  • 由于下游依賴的流量過載導(dǎo)致的服務(wù)中斷;
  • 單點(diǎn)故障時的級聯(lián)失敗等。

我們自己在代碼層面,在部署層面僅能關(guān)注應(yīng)用的功能正常,但上述這些意想不到的出錯,是我們在代碼層面不太容易控制,也不易去測試的。

而ChaosMonkey 就是用來做這個的。所以,對于這些搗亂的猴子,我們是應(yīng)該歡迎的,是不是像犀牛鳥之于犀牛?

關(guān)于ChaosMonkey,各個語言,各個公司也都有一些實現(xiàn),其中Netflix的最出名。是go語言實現(xiàn)的。

在 Java Spring Boot 技術(shù)棧中,我發(fā)現(xiàn)一個容易理解和上手的實現(xiàn)。

https://github.com/codecentric/chaos-monkey-spring-boot

我們一起來看下如何上手以及它是怎樣實現(xiàn)的。

1. 上手

添加maven 依賴

 
 
 
 
  1.   de.codecentric
  2.   chaos-monkey-spring-boot
  3.   2.3.0-SNAPSHOT

application.yml 中增加關(guān)于chaosmonkey的配置:

 
 
 
 
  1. chaos:
  2.   monkey:
  3.     enabled: true
  4.     assaults:
  5.       level: 1
  6.       latencyRangeStart: 1000
  7.       latencyRangeEnd: 10000
  8.       exceptionsActive: true
  9.       killApplicationActive: true
  10.     watcher:
  11.       repository: true
  12.       controller: true
  13. #      restController: true
  14. #      service: true

應(yīng)用啟動時,記得激活chaosmonkey的配置:

 
 
 
 
  1. java -jar your-app.jar --spring.profiles.active=chaos-monkey

再去請求你應(yīng)用的controller,是不是發(fā)現(xiàn)異常產(chǎn)生了?這就是猴子在努力的搗亂中...

關(guān)于上面這些配置,再簡單解釋下:

你會發(fā)現(xiàn)chaos - monkey 配置下,除了 enabled,還有兩項比較大的配置項,一個是Assault,一個是Watcher。

其中Assault代表是搞什么破壞,比如破壞類型有超時、內(nèi)存占用、殺死進(jìn)程、拋出異常等等

  • Latency Assault
  • Exception Assault
  • AppKiller Assault
  • Memory Assault

而Watcher 表示都要在哪些地方搞破壞。一個是What,一個是Where。

Watcher支持多種類型,比如Spring 常用的組件:

  • @Controller
  • @RestController
  • @Service
  • @Repository
  • @Component

那你說都 What 和 Where 了,怎么沒有When?還真有Level就是。

chaos.monkey.enabled 用來打開和關(guān)閉ChaosMonkey。對應(yīng)的配置中,除了設(shè)置Assault之外,不同的Assault也可以設(shè)置攻擊的頻率,配置項是chaos.monkey.assaults.level比如1代表每次請求都攻擊,10代表每十次請求攻擊一次。

chaos.monkey.assaults.latencyRangeStart 和chaos.monkey.assaults.latencyRangeEnd 這兩個配置項用來配置LatencyAssault這個攻擊的延遲時間值范圍。

如下圖所示,實際部署之后,每個ChaosMonkey會藏身于各個服務(wù)中,出其不意進(jìn)行攻擊。

這下子配置和使用就明白了。我們再來看看實現(xiàn)。

2.實現(xiàn)原理

aaa實際我們想一下,前面配置Watcher,后面決定進(jìn)行攻擊,那必須得是Watcher把它攔下來再攻擊,所以在Spring 里攔截常用的,就是它:AOP。

原理如圖所示:

以Controller 的攔截為例

 
 
 
 
  1. /** @author Benjamin Wilms */
  2. @Aspect
  3. @AllArgsConstructor
  4. @Slf4j
  5. public class SpringControllerAspect extends ChaosMonkeyBaseAspect {
  6.   private final ChaosMonkeyRequestScope chaosMonkeyRequestScope;
  7.   private MetricEventPublisher metricEventPublisher;
  8.   private WatcherProperties watcherProperties;
  9.   @Pointcut("within(@org.springframework.stereotype.Controller *)")
  10.   public void classAnnotatedWithControllerPointcut() {}
  11.   @Around(
  12.       "classAnnotatedWithControllerPointcut() && allPublicMethodPointcut() && !classInChaosMonkeyPackage()")
  13.   public Object intercept(ProceedingJoinPoint pjp) throws Throwable {
  14.     if (watcherProperties.isController()) {
  15.       log.debug("Watching public method on controller class: {}", pjp.getSignature());
  16.       if (metricEventPublisher != null) {
  17.         metricEventPublisher.publishMetricEvent(
  18.             calculatePointcut(pjp.toShortString()), MetricType.CONTROLLER);
  19.       }
  20.       MethodSignature signature = (MethodSignature) pjp.getSignature();
  21.       chaosMonkeyRequestScope.callChaosMonkey(createSignature(signature));
  22.     }
  23.     return pjp.proceed();
  24.   }
 
 
 
 
  1. public void callChaosMonkey(String simpleName) {
  2.     if (isEnabled() && isTrouble()) {
  3.       if (metricEventPublisher != null) {
  4.         metricEventPublisher.publishMetricEvent(MetricType.APPLICATION_REQ_COUNT, "type", "total");
  5.       }
  6.       // Custom watched services can be defined at runtime, if there are any, only
  7.       // these will be attacked!
  8.       if (chaosMonkeySettings.getAssaultProperties().isWatchedCustomServicesActive()) {
  9.         if (chaosMonkeySettings
  10.             .getAssaultProperties()
  11.             .getWatchedCustomServices()
  12.             .contains(simpleName)) {
  13.           // only all listed custom methods will be attacked
  14.           chooseAndRunAttack();
  15.         }
  16.       } else {
  17.         // default attack if no custom watched service is defined
  18.         chooseAndRunAttack();
  19.       }
  20.     }
  21.   }

這里是 Controller AOP的代碼,基本沒門檻。先判斷 Controller 的開關(guān)是否打開,然后再看是否需要事件通知,緊接著,就是重頭戲,召喚 Chaos Monkey 來搞破壞了。

注意這里,從激活的幾種攻擊方式里,選擇一種去調(diào)用。

 
 
 
 
  1. private void chooseAndRunAttack() {
  2.     List activeAssaults =
  3.         assaults.stream().filter(ChaosMonkeyAssault::isActive).collect(Collectors.toList());
  4.     if (isEmpty(activeAssaults)) {
  5.       return;
  6.     }
  7.     getRandomFrom(activeAssaults).attack();  // 注意這里,從激活的幾種攻擊方式里,選擇一種去調(diào)用。
  8.     if (metricEventPublisher != null) {
  9.       metricEventPublisher.publishMetricEvent(
  10.           MetricType.APPLICATION_REQ_COUNT, "type", "assaulted");
  11.     }
  12.   }

延遲攻擊

比如LatencyAssault,就是要執(zhí)行延遲攻擊,此時,會生成一個隨機(jī)的延遲時間

 
 
 
 
  1. public void attack() {
  2.     Logger.debug("Chaos Monkey - timeout");
  3.     atomicTimeoutGauge.set(determineLatency());
  4.     // metrics
  5.     if (metricEventPublisher != null) {
  6.       metricEventPublisher.publishMetricEvent(MetricType.LATENCY_ASSAULT);
  7.       metricEventPublisher.publishMetricEvent(MetricType.LATENCY_ASSAULT, atomicTimeoutGauge);
  8.     }
  9.     assaultExecutor.execute(atomicTimeoutGauge.get());
  10.   }

然后把這個值傳在線程池中進(jìn)行這個時間的

sleep。 assaultExecutor.execute(atomicTimeoutGauge.get());

 
 
 
 
  1. public class LatencyAssaultExecutor implements ChaosMonkeyLatencyAssaultExecutor {
  2.  public void execute(long durationInMillis) {
  3.    try {
  4.      Thread.sleep(durationInMillis);
  5.   } catch (InterruptedException e) {
  6.   }
  7. }
  8. }

Exception攻擊

再來看Exception 攻擊,攻擊的時候,則是構(gòu)造一個Exception 直接拋出

 
 
 
 
  1. @Override
  2.   public void attack() {
  3.     Logger.info("Chaos Monkey - exception");
  4.     AssaultException assaultException = this.settings.getAssaultProperties().getException();
  5.     assaultException.throwExceptionInstance();
  6.   }
 
 
 
 
  1. @SneakyThrows
  2.   public void throwExceptionInstance() {
  3.     Exception instance;
  4.     try {
  5.       Class exceptionClass = getExceptionClass();
  6.       if (arguments == null) {
  7.         Constructor constructor = exceptionClass.getConstructor();
  8.         instance = constructor.newInstance();
  9.       } else {
  10.         Constructor constructor =
  11.             exceptionClass.getConstructor(this.getExceptionArgumentTypes().toArray(new Class[0]));
  12.         instance =
  13.             constructor.newInstance(this.getExceptionArgumentValues().toArray(new Object[0]));
  14.       }
  15.     } catch (ReflectiveOperationException e) {
  16.       Logger.warn(
  17.           "Cannot instantiate the class for provided type: {}. Fallback: Throw RuntimeException",
  18.           type);
  19.       instance = new RuntimeException("Chaos Monkey - RuntimeException");
  20.     }
  21.     throw instance;  // 哈哈,直接拋出
  22.   }

KillApp 就直接執(zhí)行應(yīng)用的退出操作,System.exit.

本文轉(zhuǎn)載自微信公眾號「 Tomcat那些事兒」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系 Tomcat那些事兒公眾號。


分享題目:快放開那些搗亂的猴子!
文章起源:http://www.dlmjj.cn/article/dpjgdjp.html