摘要:是用于服務(wù)監(jiān)控以及服務(wù)降級(jí)基礎(chǔ)組件,主要為了解決調(diào)用外部接口的時(shí)候進(jìn)行成功率,響應(yīng)時(shí)間,指標(biāo)的監(jiān)控,同時(shí)在成功率下降到預(yù)設(shè)的閾值以下的時(shí)候自動(dòng)切斷外部接口的調(diào)用,外部接口成功率恢復(fù)后自動(dòng)恢復(fù)請(qǐng)求。
meerkat 是用于服務(wù)監(jiān)控以及服務(wù)降級(jí)基礎(chǔ)組件,主要為了解決調(diào)用外部接口的時(shí)候進(jìn)行成功率,響應(yīng)時(shí)間,QPS指標(biāo)的監(jiān)控,同時(shí)在成功率下降到預(yù)設(shè)的閾值以下的時(shí)候自動(dòng)切斷外部接口的調(diào)用,外部接口成功率恢復(fù)后自動(dòng)恢復(fù)請(qǐng)求。本文將對(duì)使用方式以及進(jìn)階特性進(jìn)行介紹。
項(xiàng)目主頁: https://github.com/ChanningBJ...
為什么要進(jìn)行監(jiān)控和熔斷在我們的Java服務(wù)中,經(jīng)常會(huì)調(diào)用外部的一些接口進(jìn)行數(shù)據(jù)的獲取操作,當(dāng)這些外部接口的成功率比較低的時(shí)候會(huì)直接影響到服務(wù)本身的成功率,因此我們添加了對(duì)外部接口調(diào)用的成功率和響應(yīng)時(shí)間監(jiān)控,這樣可以在造成大量用戶影響之前預(yù)先發(fā)現(xiàn)并解決問題。同時(shí),對(duì)于接口中的非關(guān)鍵數(shù)據(jù),我們采取了更具成功率判斷進(jìn)行觸發(fā)熔斷的方式,當(dāng)成功率下降到預(yù)定的閥值以下的時(shí)候自動(dòng)停止對(duì)這個(gè)外部接口的訪問以便保證關(guān)鍵數(shù)據(jù)能夠正常提供,當(dāng)成功率恢復(fù)以后自動(dòng)恢復(fù)請(qǐng)求。
meerkat主要功能監(jiān)控:監(jiān)控Java內(nèi)部操作的成功率以及響應(yīng)時(shí)間指標(biāo)
上報(bào):log文件和Grafhite兩種監(jiān)控指標(biāo)上報(bào)方式,支持?jǐn)U展其他的上報(bào)方式
熔斷:(可選功能)成功率下降到預(yù)設(shè)的閾值以下觸發(fā)熔斷保護(hù),暫定對(duì)外部接口的訪問,成功率恢復(fù)以后自動(dòng)恢復(fù)訪問
基本使用 maven定義受監(jiān)控的操作com.github.channingbj meerkat 1.2
假設(shè)我們的服務(wù)中需要從HTTP接口查詢一個(gè)節(jié)目的播放次數(shù),為了防止這個(gè)HTTP接口大量超時(shí)影響我們自身服務(wù)的質(zhì)量,可以定義一個(gè)查詢Command:
public class GetPlayCountCommand extends FusingCommand{ private final Long videoID; public GetPlayCountCommand(Long videoID) { this.videoID = videoID; } protected Optional run() { Long result = 0l; ? ? ? ?// 調(diào)用HTTP接口獲取視頻的播放次數(shù)信息 ? ? ? ?// 如果調(diào)用失敗,返回 null 或者拋出異常,會(huì)將這次操作記錄為失敗 ? ? ? ?// 如果ID非法,返回 Optional.absent(),會(huì)將這次操作記錄為成功 ? ? ? ?return Optional.fromNullable(result); } }
執(zhí)行查詢:
//獲取視頻ID為123的視頻的播放次數(shù) GetPlayCountCommand command = new GetPlayCountCommand(123l); Long result = command.execute(); // 執(zhí)行查詢操作,如果執(zhí)行失敗或者處于熔斷狀態(tài),返回 null配置監(jiān)控上報(bào)
在服務(wù)初始化的時(shí)候需要對(duì)監(jiān)控上報(bào)進(jìn)行設(shè)置。下面的例子中開啟了監(jiān)控?cái)?shù)據(jù)向日志文件的打印
MeterCenter.INSTANCE .enableReporter(new EnablingLogReporter("org.apache.log4j.RollingFileAppender")) .init();查看統(tǒng)計(jì)結(jié)果
統(tǒng)計(jì)結(jié)果會(huì)以熔斷命令類名為進(jìn)行分組。例如前面我們定義的 GetPlayCountCommand 類,package name 是 com.test,那么在日志中的輸出將會(huì)是這個(gè)樣子:
type=GAUGE, name=com.test.GetPlayCountCommand.normal-rate, value=0.0 type=GAUGE, name=com.test.GetPlayCountCommand.success-rate, value=61.0 type=TIMER, name=com.test.GetPlayCountCommand.time, count=25866500, min=0.0, max=0.001, mean=3.963926781047921E-5, stddev=1.951102156677818E-4, median=0.0, p75=0.0, p95=0.0, p98=0.001, p99=0.001, p999=0.001, mean_rate=649806.0831335272, m1=1665370.7316699813, m5=2315813.300713087, m15=2446572.324069477, rate_unit=events/second, duration_unit=milliseconds
監(jiān)控項(xiàng) | 含義 |
---|---|
[classname].success-rate | 成功率 |
[classname].time.m1 | QPS |
[classname].time.mean | 平均響應(yīng)時(shí)間 |
[classname].normal-rate | 過去1分鐘內(nèi)處于正常訪問(非熔斷)的時(shí)間比例 |
如果不想使用熔斷功能,只是想監(jiān)控Java方法調(diào)用的耗時(shí)和成功率,可以直接使用 OperationMeter 進(jìn)行實(shí)現(xiàn),只需要在函數(shù)調(diào)用的前后添加開始和結(jié)束的調(diào)用即可:
//創(chuàng)建一個(gè)操作的計(jì)數(shù)器 OperationMeter meter = MeterCenter.INSTANCE.getOrCreateMeter(OperationMeterTest.class, OperationMeter.class); //模擬成功率60% for(int k=0; k<100; k++){ Timer.Context context = meter.startOperation(); if(k%10<6){ meter.endOperation(context, OperationMeter.Result.SUCCESS); } else { meter.endOperation(context, OperationMeter.Result.FAILURE); } }
# 開啟熔斷并配置閥值和持續(xù)時(shí)間
首先創(chuàng)建一個(gè)接口,繼承自FusingConfig,用于指定配置文件的加載路徑,同時(shí)還可以設(shè)定配置文件的刷新時(shí)間,具體定義方法請(qǐng)參照 owner 文檔
@Config.Sources("classpath:app_config.properties") @Config.HotReload( value = 1, unit = java.util.concurrent.TimeUnit.MINUTES, type = Config.HotReloadType.ASYNC) public interface APPFusingConfig extends FusingConfig { }
創(chuàng)建查詢Command的時(shí)候在構(gòu)造函數(shù)中傳入
public class GetPlayCountCommand extends FusingCommand{ private final Long videoID; public GetPlayCountCommand(Long videoID) { super( APPFusingConfig.class); //設(shè)定配置文件 this.videoID = videoID; } protected Optional run() { Long result = 0l; ? ? ? ?// 調(diào)用HTTP接口獲取視頻的播放次數(shù)信息 ? ? ? ?// 如果調(diào)用失敗,返回 null 或者拋出異常,會(huì)將這次操作記錄為失敗 ? ? ? ?// 如果ID非法,返回 Optional.absent(),會(huì)將這次操作記錄為成功 ? ? ? ?return Optional.fromNullable(result); } }
配置文件內(nèi)容如下:
監(jiān)控項(xiàng) | 含義 | 默認(rèn)值 |
---|---|---|
fusing.[CommandClassName].mode | 熔斷模式: FORCE_NORMAL-關(guān)閉熔斷功能; AUTO_FUSING-自動(dòng)進(jìn)入熔斷模式; FORCE_NORMAL-強(qiáng)制進(jìn)行熔斷 |
FORCE_NORMAL |
fusing.[CommandClassName].duration | 觸發(fā)一次熔斷以后持續(xù)的時(shí)間,支持ms,sec,min 單位。例如 10sec | 50sec |
fusing.[CommandClassName].success_rate_threshold | 觸發(fā)熔斷的成功率閥值,降低到這個(gè)成功率以下將觸發(fā)熔斷,例如0.9表示成功率90% | 0.9 |
配置文件中的 CommandClassName 是每個(gè)操作類的名稱,可以為每個(gè)操作多帶帶設(shè)置上述參數(shù)。同時(shí),這個(gè)配置文件支持動(dòng)態(tài)加載,樂意通過修改fusing.[CommandClassName].mode 手工觸發(fā)或者關(guān)閉熔斷。
監(jiān)控指標(biāo)上報(bào)Graphite我們的服務(wù)中使用的是Metric+Graphite+Gafana進(jìn)行監(jiān)控?cái)?shù)據(jù)的采集存儲(chǔ)和展現(xiàn),下面將介紹如何配置監(jiān)控?cái)?shù)據(jù)上報(bào)Grafana,關(guān)于Graphite+Grafana的配置,可以參考文章:使用graphite和grafana進(jìn)行應(yīng)用程序監(jiān)控
定義配置文件首先定義一個(gè)接口,繼承自GraphiteReporterConfig,通過這個(gè)接口定義配置文件的加載路徑。配置文件路徑的定義方法請(qǐng)參照 owner 文檔, 下面是一個(gè)例子:
@Config.Sources("classpath:config.properties") public interface MyConfig extends GraphiteReporterConfig { }
配置文件中需要定義下列內(nèi)容:
配置項(xiàng) | 含義 |
---|---|
meter.reporter.enabled.hosts | 開啟監(jiān)控上報(bào)的服務(wù)器列表 |
meter.reporter.perfix | 上報(bào)使用的前綴 |
meter.reporter.carbon.host | grafana(carbon-cache) 的 IP 地址,用于存儲(chǔ)監(jiān)控?cái)?shù)據(jù) |
meter.reporter.carbon.port | grafana(carbon-cache) 的端口 |
下面這個(gè)例子是在192.168.0.0.1和192.168.0.0.2兩臺(tái)服務(wù)器上開啟監(jiān)控?cái)?shù)據(jù)上報(bào),上報(bào)監(jiān)控指標(biāo)的前綴是project_name.dc:
meter.reporter.enabled.hosts = 192.168.0.0.1,192.168.0.0.2 meter.reporter.perfix = project_name.dc meter.reporter.carbon.host = hostname.graphite
由于相同機(jī)房的不同服務(wù)器對(duì)外部接口的訪問情況一般比較類似,所以僅選取部分機(jī)器上報(bào),也是為了節(jié)省資源。僅選擇部分機(jī)器上報(bào)不影響熔斷效果。
初始化配置上報(bào)在服務(wù)初始化的時(shí)候需要對(duì)監(jiān)控上報(bào)進(jìn)行設(shè)置。下面的例子中開啟了監(jiān)控?cái)?shù)據(jù)向日志文件的打印,同時(shí)通過MyConfig指定的配置文件加載Graphite配置信息。
MeterCenter.INSTANCE .enableReporter(new EnablingLogReporter("org.apache.log4j.RollingFileAppender")) .enableReporter(new EnablingGraphiteReporter(MyConfig.class)) //監(jiān)控?cái)?shù)據(jù)上報(bào)Grafana .init();查看統(tǒng)計(jì)結(jié)果
統(tǒng)計(jì)結(jié)果會(huì)以熔斷命令類名為進(jìn)行分組。例如前面我們定義的 GetPlayCountCommand 類,package name 是 com.test,那么在日志中的輸出將會(huì)是這個(gè)樣子:
type=GAUGE, name=com.test.GetPlayCountCommand.normal-rate, value=0.0 type=GAUGE, name=com.test.GetPlayCountCommand.success-rate, value=61.0 type=TIMER, name=com.test.GetPlayCountCommand.time, count=25866500, min=0.0, max=0.001, mean=3.963926781047921E-5, stddev=1.951102156677818E-4, median=0.0, p75=0.0, p95=0.0, p98=0.001, p99=0.001, p999=0.001, mean_rate=649806.0831335272, m1=1665370.7316699813, m5=2315813.300713087, m15=2446572.324069477, rate_unit=events/second, duration_unit=milliseconds
監(jiān)控項(xiàng) | 含義 |
---|---|
[classname].success-rate | 成功率 |
[classname].time.m1 | QPS |
[classname].time.mean | 平均響應(yīng)時(shí)間 |
[classname].normal-rate | 過去1分鐘內(nèi)處于正常訪問(非熔斷)的時(shí)間比例 |
在Grafanna中可以看到下面的監(jiān)控圖:
自定義監(jiān)控上報(bào)meerkat使用Metrics進(jìn)行監(jiān)控?cái)?shù)據(jù)的統(tǒng)計(jì),因此可以使用Metrics支持的所有reporter進(jìn)行上報(bào)。添加一種上報(bào)的時(shí)候,只需要實(shí)現(xiàn) EnablingReporter 并在 MeterCenter 初始化之前進(jìn)行調(diào)用即可。下面是log reporter的實(shí)現(xiàn),可以作為參考
public class EnablingLogReporter implements EnablingReporter { private String loggername; public EnablingLogReporter(String loggername) { this.loggername = loggername; } @Override public void invoke(MetricRegistry metricRegistry, long period, TimeUnit timeUnit) { Slf4jReporter.forRegistry(metricRegistry) .outputTo(LoggerFactory.getLogger(loggername)) .convertRatesTo(java.util.concurrent.TimeUnit.SECONDS) .convertDurationsTo(java.util.concurrent.TimeUnit.MILLISECONDS) .build().start(period, timeUnit); } }
MeterCenter 初始化的時(shí)候開啟reporter
MeterCenter.INSTANCE .enableReporter(new EnablingLogReporter("org.apache.log4j.RollingFileAppender")) .init();多實(shí)例監(jiān)控
多實(shí)例監(jiān)控主要是為了解決一個(gè)被監(jiān)控操作的實(shí)現(xiàn)類需要根據(jù)輸入?yún)?shù)的不同分別進(jìn)行監(jiān)控和熔斷的情況,通過定義實(shí)例的名稱進(jìn)行實(shí)現(xiàn)。例如獲取視頻播放次數(shù)的例子,獲取視頻播放次數(shù)的接口對(duì)于不同的視頻類型而言請(qǐng)求邏輯是一樣的,所以使用同一個(gè)類進(jìn)行實(shí)現(xiàn);但是對(duì)于不同的視頻類型,接口實(shí)現(xiàn)的復(fù)雜程度不同導(dǎo)致成功率不同,當(dāng)用戶上傳的視頻的播次接口大量失敗的時(shí)候我們不希望同時(shí)熔斷電影電視劇這類視頻的播放次數(shù)獲取,這時(shí)就需要使用多實(shí)例這種特性進(jìn)行監(jiān)控和熔斷。
下面是一個(gè)單實(shí)例的實(shí)現(xiàn):
public class GetPlayCountCommand extends FusingCommand{ private final Long videoID; public GetPlayCountCommand(Long videoID) { super( APPFusingConfig.class); this.videoID = videoID; } protected Optional run() { Long result = 0l; // 調(diào)用HTTP接口獲取視頻的播放次數(shù)信息 // 如果調(diào)用失敗,返回 null 或者拋出異常,會(huì)將這次操作記錄為失敗 // 如果ID非法,返回 Optional.absent(),會(huì)將這次操作記錄為成功 return Optional.fromNullable(result); } }
假設(shè)業(yè)務(wù)上我們可以根據(jù)視頻ID判斷視頻類型,可以在類初始化的時(shí)候根據(jù)類型創(chuàng)建多種監(jiān)控實(shí)例,添加了多實(shí)例支持的實(shí)現(xiàn)如下:
public class GetPlayCountCommand extends FusingCommand{ private final Long videoID; public GetPlayCountCommand(Long videoID) { super( getVideoType(videoID), APPFusingConfig.class); this.videoID = videoID; } private static String getVideoType(Long videoID){ return "PGC"; //根據(jù)videoID進(jìn)行判斷,返回 "PGC" 或者 "UGC" 這兩個(gè)類別 } protected Optional run() { Long result = 0l; // 調(diào)用HTTP接口獲取視頻的播放次數(shù)信息 // 如果調(diào)用失敗,返回 null 或者拋出異常,會(huì)將這次操作記錄為失敗 // 如果ID非法,返回 Optional.absent(),會(huì)將這次操作記錄為成功 return Optional.fromNullable(result); }
由于每個(gè)實(shí)例獨(dú)享一個(gè)監(jiān)控指標(biāo),日志中的監(jiān)控個(gè)結(jié)果是這個(gè)樣子:
type=GAUGE, name=com.test.GetPlayCountCommand.PGC.normal-rate, value=100.0 type=GAUGE, name=com.test.GetPlayCountCommand.PGC.success-rate, value=100.0 type=GAUGE, name=com.test.GetPlayCountCommand.UGC.normal-rate, value=100.0 type=GAUGE, name=com.test.GetPlayCountCommand.UGC.success-rate, value=60.0 type=TIMER, name=com.test.GetPlayCountCommand.PGC.time, count=100, min=0.0, max=0.509, mean=0.00635, stddev=0.05052135687013958, median=0.001, p75=0.002, p95=0.002, p98=0.003, p99=0.003, p999=0.509, mean_rate=1.6680162586215173, m1=8.691964170141569, m5=16.929634497812284, m15=18.919189378135307, rate_unit=events/second, duration_unit=milliseconds type=TIMER, name=com.test.GetPlayCountCommand.UGC.time, count=100, min=0.0, max=0.027, mean=0.00132, stddev=0.0026939933184772376, median=0.001, p75=0.001, p95=0.002, p98=0.005, p99=0.006, p999=0.027, mean_rate=1.6715904477699361, m1=8.691964170141569, m5=16.929634497812284, m15=18.919189378135307, rate_unit=events/second, duration_unit=milliseconds
相應(yīng)的,對(duì)熔斷閥值以及持續(xù)時(shí)間的配置也需要明確指出實(shí)例的名字:
fusing.GetPlayCountCommand.UGC.mode = AUTO_FUSING fusing.GetPlayCountCommand.UGC.duration = 50sec fusing.GetPlayCountCommand.UGC.success_rate_threshold = 0.9 fusing.GetPlayCountCommand.PGC.mode = AUTO_FUSING fusing.GetPlayCountCommand.PGC.duration = 50sec fusing.GetPlayCountCommand.PGC.success_rate_threshold = 0.9
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/71138.html
摘要:有了分布式數(shù)據(jù)庫(kù)可以使數(shù)據(jù)庫(kù)的性能可以隨著節(jié)點(diǎn)增加線性地增加。分布式數(shù)據(jù)庫(kù)最最下面是,是主備的,通過的內(nèi)核開發(fā)能力,我們能夠?qū)崿F(xiàn)主備切換數(shù)據(jù)零丟失,所以數(shù)據(jù)落在這個(gè)里面,是非常放心的,哪怕是掛了一個(gè)節(jié)點(diǎn),切換完了以后,你的數(shù)據(jù)也是不會(huì)丟的。 此文已由作者劉超授權(quán)網(wǎng)易云社區(qū)發(fā)布。 歡迎訪問網(wǎng)易云社區(qū),了解更多網(wǎng)易技術(shù)產(chǎn)品運(yùn)營(yíng)經(jīng)驗(yàn) 三、微服務(wù)化的十個(gè)設(shè)計(jì)要點(diǎn) 微服務(wù)有哪些要點(diǎn)呢?第一張圖是...
時(shí)間:2017年07月06日星期四說明:本文部分內(nèi)容均來自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:無學(xué)習(xí)學(xué)習(xí)源碼:無 第一章:微服務(wù)架構(gòu)在二手交易平臺(tái)(轉(zhuǎn)轉(zhuǎn))中的實(shí)踐 1-1 微服務(wù)架構(gòu)特點(diǎn) 分享要點(diǎn)-微服務(wù)架構(gòu) 特點(diǎn) 使用原因 演進(jìn) 通信協(xié)議、服務(wù)注冊(cè)與發(fā)現(xiàn) 柔性可用實(shí)踐 服務(wù)治理 什么是微服務(wù) 微服務(wù)是一系列小服務(wù)的組合 微服務(wù)可以單獨(dú)運(yùn)行,獨(dú)立的進(jìn)程 微服務(wù)整...
摘要:系統(tǒng)需要支持命令的撤銷。第步計(jì)算斷路器的健康度會(huì)將成功失敗拒絕超時(shí)等信息報(bào)告給斷路器,斷路器會(huì)維護(hù)一組計(jì)數(shù)器來統(tǒng)計(jì)這些數(shù)據(jù)。第步,當(dāng)前命令的線程池請(qǐng)求隊(duì)列或者信號(hào)量被占滿的時(shí)候。 斷路由器模式 在分布式架構(gòu)中,當(dāng)某個(gè)服務(wù)單元發(fā)生故障之后,通過斷路由器的故障監(jiān)控(類似熔斷保險(xiǎn)絲),向調(diào)用方返回一個(gè)錯(cuò)誤響應(yīng),而不是長(zhǎng)時(shí)間的等待。這樣就不會(huì)使得線程因調(diào)用故障服務(wù)被長(zhǎng)時(shí)間占用不釋放,避免了故障...
閱讀 1256·2021-09-27 13:34
閱讀 1070·2021-09-13 10:25
閱讀 567·2019-08-30 15:52
閱讀 3510·2019-08-30 13:48
閱讀 736·2019-08-30 11:07
閱讀 2228·2019-08-29 16:23
閱讀 2054·2019-08-29 13:51
閱讀 2390·2019-08-26 17:42