meerkat 是爱奇艺移动服务端团队开发的服务监控以及服务降级基础组件,主要为了解决调用外部接口的时候进行成功率,响应时间,QPS指标的监控,同时在成功率下降到预设的阈值以下的时候自动切断外部接口的调用,外部接口成功率恢复后自动恢复请求。
监控操作的成功率以及响应时间指标
log文件和Grafhite两种监控指标上报方式,支持扩展其他的上报方式
(可选功能)成功率下降到预设的阈值以下触发熔断保护,暂定对外部接口的访问,成功率恢复以后自动恢复访问
更详细的文档说明请参见 Wiki
通过日志的方式查看监控结果
type=GAUGE, name=com.qiyi.mbd.test.GetPlayCountCommand.normal-rate, value=0.0 type=GAUGE, name=com.qiyi.mbd.test.GetPlayCountCommand.success-rate, value=61.0 type=TIMER, name=com.qiyi.mbd.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
通过上报Grafana查看监控结果
<dependency> <groupId>com.github.qiyimbd</groupId> <artifactId>meerkat</artifactId> <version>1.0</version> </dependency>
假设我们的服务中需要从HTTP接口查询一个节目的播放次数,为了防止这个HTTP接口大量超时影响我们自身服务的质量,可以定义一个查询Command:
public class GetPlayCountCommand extends FusingCommand<Long> { private final Long videoID; public GetPlayCountCommand(Long videoID) { this.videoID = videoID; } protected Optional<Long> run() { Long result = 0l; // 调用HTTP接口获取视频的播放次数信息 // 如果调用失败,返回 null 或者抛出异常,会将这次操作记录为失败 // 如果ID非法,返回 Optional.absent(),会将这次操作记录为成功 return Optional.fromNullable(result); } }
执行查询:
//获取视频ID为123的视频的播放次数GetPlayCountCommand command = new GetPlayCountCommand(123l);Long result = command.execute(); // 执行查询操作,如果执行失败或者处于熔断状态,返回 null
默认情况下,操作成功率每10秒更新一次,开启通断以后当成功率小于90%的时候进入熔断状态,熔断状态下调用execute()函数会返回null,熔断状态持续50秒,终端终止以后恢复正常访问。
当处于熔断或者命令执行失败的时候execute()函数会返回null,可以通过Override getFallback这个函数对失败/熔断情况下的返回值进行修改。例如我们希望在播放次数请求失败的情况下默认播放次数是47,可以这样实现:
public class GetPlayCountCommand extends FusingCommand<Long> { private final Long videoID; public GetPlayCountCommand(Long videoID) { this.videoID = videoID; } protected Optional<Long> run() { Long result = 0l; // 调用HTTP接口获取视频的播放次数信息 // 如果调用失败,返回 null 或者抛出异常,会将这次操作记录为失败 // 如果ID非法,返回 Optional.absent(),会将这次操作记录为成功 return Optional.fromNullable(result); } /** * * @param isFusing 当前是否处于熔断状态 * @param e run函数抛出的异常 * @return 熔断或者请求出现错误的时候execute()函数的返回值 */ @Override protected Long getFallback(boolean isFusing, Exception e) { return 47l; } }
首先定义一个接口,继承自GraphiteReporterConfig,通过这个接口定义配置文件的加载路径。配置文件路径的定义方法请参照 owner 文档, 下面是一个例子:
@Config.Sources("classpath:config.properties")public interface MyConfig extends GraphiteReporterConfig { }
配置文件中需要定义下列内容:
下面这个例子是在192.168.0.0.1和192.168.0.0.2两台服务器上开启监控数据上报,上报监控指标的前缀是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
由于相同机房的不同服务器对外部接口的访问情况一般比较类似,所以仅选取部分机器上报,也是为了节省资源。仅选择部分机器上报不影响熔断效果。
在服务初始化的时候需要对监控上报进行设置。下面的例子中开启了监控数据向日志文件的打印,同时通过MyConfig指定的配置文件加载Graphite配置信息。
MeterCenter.INSTANCE .enableReporter(new EnablingLogReporter("org.apache.log4j.RollingFileAppender")) .enableReporter(new EnablingGraphiteReporter(MyConfig.class)) .init();
统计结果会以熔断命令类名为进行分组。例如前面我们定义的 GetPlayCountCommand 类,package name 是 com.qiyi.mbd.test,那么在日志中的输出将会是这个样子:
type=GAUGE, name=com.qiyi.mbd.test.GetPlayCountCommand.normal-rate, value=0.0 type=GAUGE, name=com.qiyi.mbd.test.GetPlayCountCommand.success-rate, value=61.0 type=TIMER, name=com.qiyi.mbd.test.GetPlayCountCommand.time, count=25866500, min=0.0, max=0.001, mean=3.963926781047921E-5, stddev=1.951
如果配置了Graphite上报,可以看到下面的监控图
关于Graphite+Grafana的配置,可以参考文章:使用graphite和grafana进行应用程序监控
首先创建一个接口,继承自FusingConfig,用于指定配置文件的加载路径,同时还可以设定配置文件的刷新时间,具体定义方法请参照 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 { }
创建查询Command的时候在构造函数中传入
public class GetPlayCountCommand extends FusingCommand<Long> { private final Long videoID; public GetPlayCountCommand(Long videoID) { super( APPFusingConfig.class); this.videoID = videoID; } protected Optional<Long> run() { Long result = 0l; // 调用HTTP接口获取视频的播放次数信息 // 如果调用失败,返回 null 或者抛出异常,会将这次操作记录为失败 // 如果ID非法,返回 Optional.absent(),会将这次操作记录为成功 return Optional.fromNullable(result); } }
配置文件定义:
配置文件中的 CommandClassName 是每个操作类的名称,可以为每个操作单独设置上述参数。同时,这个配置文件支持动态加载,乐意通过修改fusing.[CommandClassName].mode 手工触发或者关闭熔断。
import java.util.*; import javax.mail.*; import javax.mail.internet.*; /** Mailer. Sends an email message. * Sender class, recast as a Bean for use in JSP's & elsewhere. * Example usage: * <pre>
Java Metrics Java Metrics是一个功能比较强大的java统计库,它的输出组件也很强大,帮我们做好了: 输出到Ganglia 输出到控制台 输出到JMX 输出Json 详细见:dropwizard.github.io/metrics/ 依赖 添加依赖,如gradle: compile "io.dropwizard.metrics:metrics-core:3.1.0"
.KJava简介 Java语言最初是为嵌入式系统设计的一项产品,在Java 2中为了区分各种不同的应用,又细分成了Java 2 Enterprise Edition(J2EE)、Java 2 Standard Edition(J2SE)和Java 2 Micro Edition(J2ME)三种版本,其中J2ME又称作KJava。 在J2SE中,它定义了Java规范的核心类函数库(即Java.*)和
Java是一门面向对象的高级编程语言。为什么说它是高级语言呢,我们身为程序员,不管是前端还是后端,肯定有初级、中级、高级、资深等区分。那高级程序员为什么称之为高级呢?首先初级程序员会的技术点,高级程序员基本都会,而且高级程序员还能在这些知识点中过滤出有用的、合适的,摒弃一些过时的、存在风险的、难用的技术。 比如初级程序员掌握的技术:jsp、jquery、vue、springMVC 、Mybatis
51nod的大数题(部分)之Java Java! 1028 import java.io.*; import java.math.*; import java.text.*; import java.util.*; public class Main { public static void main(String arg[]){ Scanner cin = new Scanner(new B
需要引入je-analysis-1.4.0.jar包 package com.test; import java.io.IOException; import java.io.StringReader; import jeasy.analysis.MMAnalyzer; public class testJE { public static void main(String[] arg
Java Basis+Praktikum Tag- 05.10.2015 一,Klasse und Objekt 1,构造器: Ein Konstruktor ist eine spezielle Form einer Methode und erzeugt ein Objekt der Klasse. 构造器是为了创建一个类的实例,这个过程也可以在创建
关于JavaEE的版本 JavaEE目前最高版本是JavaEE JavaEE被Oracle捐献了,Oracle将JavaEE规范捐献给apache了 Apache把java改名了,以后不叫JavaEE了,以后叫做jakarta EE。 以后没有JavaEE了,以后都叫做Jakarta EE。 JavaEE8版本升级之后的“JavaEE 9”,不再是“JavaEE9”这个名字了,叫做JakartaE
安装 composer require hyperf/circuit-breaker 为什么要熔断? 分布式系统中经常会出现由于某个基础服务不可用造成整个系统不可用的情况,这种现象被称为服务雪崩效应。为了应对服务雪崩,一种常见的做法是服务降级。而 hyperf/circuit-breaker 组件,就是为了来解决这个问题的。 使用熔断器 熔断器的使用十分简单,只需要加入 Hyperf\Circu
Listener 原型 <?php namespace Group\Listeners; abstract class Listener { abstract function setMethod(); public function getMethod() { return $this->setMethod(); } } 实现一个监听类 <?php
可以通过服务降级功能 1 临时屏蔽某个出错的非关键服务,并定义降级后的返回策略。 向注册中心写入动态配置覆盖规则: RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getAdaptiveExtension(); Registry registry = regist
微服务治理的一个核心需求便是服务可观察性。作为微服务的牧羊人,要做到时刻掌握各项服务的健康状态,并非易事。云原生时代这一领域内涌现出了诸多解决方案。本组件对可观察性当中的重要支柱遥测与监控进行了抽象,方便使用者与既有基础设施快速结合,同时避免供应商锁定。 安装 通过 Composer 安装组件 composer require hyperf/metric hyperf/metric 组件默认安装
1.1、什么是监控服务 监控服务(Monitor Service),是指对直播视频流的实时监控。目睹云提供的监控服务能够支持对rtmp、flv、hls等大多数直播流进行即时监控,并且渲染成图表。监控服务主要监控的是直播视频的帧率和码率信息,这样能够及时的反映出来视频流的卡顿流畅情况。 1.2、监控服务功能介绍 支持多种流监控:支持rtmp、flv、hls等多种直播视频协议流监控 历史监控数据:支持
Config配置类 StaticCache静态缓存类 Route路由类 Controller控制器类 View视图类 Request请求类 Response响应类 Event事件类 Listener监听类 Subscriber多事件监听 EventDispatcher事件调度
Subscriber多事件监听 <?php namespace Group\Events\Tests; use Group\Events\EventSubscriberInterface; class TestSubscriber implements EventSubscriberInterface { public function getSubscribedEvents()
服务调用监控 KernalEvent::SERVICE_CALL事件 在框架层,调用servcie时,会抛出KernalEvent::SERVICE_CALL事件,你可以监听该事件,做数据上报处理,请以异步方式上报 <?php namespace src\Web\Listeners; use Listener; use Event; class Servic