`
luhantu
  • 浏览: 205110 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

熔断机制的一种实-- 滑动窗口

    博客分类:
  • Java
阅读更多

 

package com.codahale.metrics;

import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 熔断机制的一种实-- 滑动窗口
 * 清除超过一个窗口的,统计窗口内的
 * 参考:https://github.com/infusionsoft/yammer-metrics/blob/master/metrics-core/src/main/java/com/codahale/metrics/SlidingTimeWindowReservoir.java
 * A {@link Reservoir} implementation backed by a sliding window that stores only the measurements made
 * in the last {@code N} seconds (or other time unit).
 */
public class SlidingTimeWindowReservoir implements Reservoir {
    //防止冲突的buffer
    // allow for this many duplicate ticks before overwriting measurements
    private static final int COLLISION_BUFFER = 256;
    //每隔多长时间进行一次蓄水池Reservoir的清除
    // only trim on updating once every N
    private static final int TRIM_THRESHOLD = 256;

    private final Clock clock;
    private final ConcurrentSkipListMap<Long, Long> measurements;
    private final long window;
    private final AtomicLong lastTick;
    private final AtomicLong count;

    /**
     * Creates a new {@link SlidingTimeWindowReservoir} with the given window of time.
     *
     * @param window     the window of time
     * @param windowUnit the unit of {@code window}
     */
    public SlidingTimeWindowReservoir(long window, TimeUnit windowUnit) {
        this(window, windowUnit, Clock.defaultClock());
    }

    /**
     * Creates a new {@link SlidingTimeWindowReservoir} with the given clock and window of time.
     *
     * @param window     the window of time
     * @param windowUnit the unit of {@code window}
     * @param clock      the {@link Clock} to use
     */
    public SlidingTimeWindowReservoir(long window, TimeUnit windowUnit, Clock clock) {
        this.clock = clock;
        this.measurements = new ConcurrentSkipListMap<Long, Long>();
        this.window = windowUnit.toNanos(window) * COLLISION_BUFFER;
        this.lastTick = new AtomicLong();
        this.count = new AtomicLong();
    }

    @Override
    public int size() {
        trim();
        return measurements.size();
    }

    @Override
    public void update(long value) {
        if (count.incrementAndGet() % TRIM_THRESHOLD == 0) {
            trim();
        }
        measurements.put(getTick(), value);
    }

    @Override
    public Snapshot getSnapshot() {
        trim();
        return new Snapshot(measurements.values());
    }

    private long getTick() {
        for (; ; ) {
            final long oldTick = lastTick.get();
            final long tick = clock.getTick() * COLLISION_BUFFER;
            // ensure the tick is strictly incrementing even if there are duplicate ticks
            System.out.println("test" +count);
            final long newTick = tick > oldTick ? tick : oldTick + 1;
            if (lastTick.compareAndSet(oldTick, newTick)) {
                return newTick;
            }
        }
    }

    private void trim() {
        measurements.headMap(getTick() - window).clear();
    }
}

 

测试类:

package com.codahale.metrics;

import org.junit.Test;

import java.util.concurrent.TimeUnit;

import static org.fest.assertions.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class SlidingTimeWindowReservoirTest {
    private final Clock clock = mock(Clock.class);
    private final SlidingTimeWindowReservoir reservoir = new SlidingTimeWindowReservoir(10, TimeUnit.NANOSECONDS, clock);

    @Test
    public void storesMeasurementsWithDuplicateTicks() throws Exception {
        when(clock.getTick()).thenReturn(20L);

        reservoir.update(1);
        reservoir.update(2);

        assertThat(reservoir.getSnapshot().getValues())
                .containsOnly(1, 2);
    }

    @Test
    public void boundsMeasurementsToATimeWindow() throws Exception {
        when(clock.getTick()).thenReturn(0L);
        reservoir.update(1);

        when(clock.getTick()).thenReturn(5L);
        reservoir.update(2);

        when(clock.getTick()).thenReturn(10L);
        reservoir.update(3);

        when(clock.getTick()).thenReturn(15L);
        reservoir.update(4);

        when(clock.getTick()).thenReturn(20L);
        reservoir.update(5);
        
        assertThat(reservoir.getSnapshot().getValues())
                .containsOnly(4, 5);
    }
}

 

 

0
0
分享到:
评论

相关推荐

    高可用:降级和熔断有什么区别?

    - 使用统计方法,如滑动窗口算法,来动态调整阈值。 - 结合异常检测算法,识别出真正的服务故障。 3. **如何测试和演练降级和熔断策略?** - 在测试环境中模拟高负载和故障场景。 - 定期进行灾难恢复演练,评估...

    Sentinel限流、熔断降级源码剖析1

    当系统资源(如CPU、内存)或服务调用响应时间超过预设阈值时,Sentinel会自动触发熔断机制,将后续请求快速失败,避免系统雪崩。同时,Sentinel还提供了降级策略,如返回默认值、快速失败或降级到备用系统,以减轻...

    sentinel-dashboard-1.7.2.zip

    - 当服务出现异常时,Sentinel 提供熔断机制,自动切换到降级模式,通常有返回默认值、快速失败和空短路三种降级策略。 - 熔断降级有助于快速恢复系统的稳定,防止故障扩散。 6. **系统保护**: - Sentinel 会...

    spring cloud流量控制 sentinel-dashboard.zip

    总的来说,Sentinel-Dashboard是Spring Cloud流量控制的重要工具,它提供了一种直观、易用的方式,帮助开发者管理和优化服务的流量,确保系统的稳定性和弹性。通过熟练掌握Sentinel和其控制台,开发者可以更好地应对...

    亿级流量下的分布式限流解决方案.rar

    - 滑动窗口算法:分为固定窗口、滑动窗口和滚动窗口,通过统计一段时间内的请求数量来判断是否超过限制。 - 令牌桶算法:系统以恒定速率向桶中添加令牌,请求需要从桶中取出令牌才能执行,当桶中无令牌时则拒绝...

    秒杀后端.zip 后端代码

    秒杀系统是电商领域常见的一种营销手段,用于在短时间内处理大量用户请求,实现商品的快速售卖。本压缩包“秒杀后端.zip”包含了构建一个高效、稳定的后端代码资源,主要关注的是如何设计和实现能够应对高并发场景的...

    0.《百图解码支付系统设计与实现》专栏大纲_V20240225.pdf

    - **资损防控**:提出一种有效的防错策略,防止支付错误的发生。 - **数据库与事务**:分析Spring事务模板及afterCommit存在的潜在问题。 - **分库分表**:探讨大规模支付系统中的数据分片策略。 - **多活**:介绍...

    sentinel-dashboard-1.7.1.jar

    描述中提到的 "网盘地址" 提供了一种便捷的方式获取 Sentinel Dashboard,对于那些遇到 GitHub 下载速度慢的用户来说,这是一个非常实用的解决方案。通常,GitHub 因为网络问题在中国访问可能不太稳定,使用国内的...

    35-流量控制:高并发系统中我们如何操纵流量?_For_group_share1

    限流是一种重要的服务保护策略,尤其在高并发的系统中,用于确保系统稳定性和可用性。在面对诸如双十一、618大促等流量高峰时,传统的熔断和降级策略可能并不适用,因为核心服务不能轻易降级。此时,限流策略就显得...

    miaosha-master_秒杀系统_面试算法_

    熔断机制可以在服务出现问题时,快速切换到降级模式,保护系统整体稳定性。 7. **算法应用**:面试中经常涉及的算法问题,如快速排序、堆排序等可以用于优化数据处理效率;一致性哈希用于分布式环境中的负载均衡;...

    基于Java开发的简单、易用、高性能的服务降级系统,支持限流、熔断和降级等功能,服务端必备!!.zip

    降级通常是在限流和熔断之后的一种补充措施,意味着在服务不可用或者性能严重下降时,返回一个预设的默认值或者错误信息,而不是让用户等待一个可能永远无法返回的结果。例如,当电商网站在促销期间访问量激增,可以...

    流控项目_流控_流控后台管理系统_源码

    3. **熔断与降级**:当服务因流量过大而无法正常响应时,系统可自动触发熔断机制,暂时停止服务,以保护整体系统的稳定性。同时,可以提供降级策略,将请求路由到备用服务或返回默认结果。 4. **黑白名单管理**:...

    sentinel.zip

    总结来说,Sentinel 是一个功能强大的服务治理工具,它的流量控制、熔断降级机制有助于提升微服务架构的稳定性和健壮性。通过合理配置和使用 Sentinel,开发者可以更好地管理和维护复杂的分布式系统。

    03-05-16-Apache Sentinel的基本应用及原理分析1

    1. **流量控制**:Sentinel 提供了多种流量控制策略,如滑动窗口、固定窗口、令牌桶、漏桶等算法,用于限制系统的输入流量,防止过载导致服务崩溃。例如,可以设定在特定时间窗口内允许的最大请求数量,超过则进行限...

    nacos-server-1.2.1-seata-server-1.1.0和1.3.0-sentinel-dashboard-1.7.1

    它支持多种流量控制策略,如固定窗口、滑动窗口、漏桶、令牌桶等,以及基于QPS、线程数等维度的控制。同时,Sentinel还提供了熔断和降级功能,当服务出现异常时,可以快速切换到备用方案,保证系统的稳定运行。 这...

    Spring Cloud Alibaba.zip

    2. **Sentinel流量控制与熔断组件**:Sentinel是Spring Cloud Alibaba中的一个关键组件,它提供了丰富的流量控制策略,如滑动窗口、令牌桶等,可以有效防止服务过载。此外,Sentinel还具备熔断机制,当服务出现异常...

    hyxtrix限流.zip

    断路器模式是一种设计模式,当服务出现故障时,断路器会打开,阻止进一步的请求,防止故障扩散,让系统有机会自我恢复。Hystrix通过监控服务调用的失败率和延迟,自动触发断路器状态的切换。 Hystrix的限流功能则...

    Laravel开发-soa-sentinel

    SOA(Service-Oriented Architecture,面向服务架构)则是一种设计模式,它提倡将业务功能分解为一系列可重用的服务,这些服务可以独立部署、独立升级,并通过网络进行通信。Laravel的灵活性使得它能够很好地适应SOA...

    阿里云 专有云企业版 V3.8.2 API 网关 开发指南 20200417.pdf

    API网关是云服务的一种核心组件,它作为对外的统一入口,负责处理来自客户端的请求,转发到后端服务,并对返回的数据进行处理。API网关可以实现服务的聚合、认证、限流、熔断、监控等功能,提高系统的稳定性和安全...

    JAVA全栈核心知识点整理-面试

    4. **Spring Cloud**:这是一个微服务框架,包括服务发现(Eureka)、配置中心(Config)、熔断机制(Hystrix)、API网关(Zuul或Gateway)、服务间调用(Feign)等组件。了解其工作原理和实践应用,能够设计和实现...

Global site tag (gtag.js) - Google Analytics