java B2B2C Springboot多租户电子商城系统-Eureka源码解析

本文涉及的产品
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
简介: Eureka的限流算法类RateLimiter是基于令牌桶算法来实现的,下面看一看令牌桶算法的原理: 需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六 对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。

Eureka的限流算法类RateLimiter是基于令牌桶算法来实现的,下面看一看令牌桶算法的原理:
_

需要JAVA Spring Cloud大型企业分布式微服务云构建的B2B2C电子商务平台源码 一零三八七七四六二六

对于很多应用场景来说,除了要求能够限制数据的平均传输速率外,还要求允许某种程度的突发传输。这时候漏桶算法可能就不合适了,令牌桶算法更为适合。如图所示,令牌桶算法的原理是系统会以一个恒定的速度往桶里放入令牌,而如果请求需要被处理,则需要先从桶里获取一个令牌,当桶里没有令牌可取时,则拒绝服务。

源码解读:

package com.lovnx.web;

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

/**
 * @Class RateLimiter 实现基于令牌桶算法,有两个参数:
 * 
 * @para  burstSize - 允许作为突发事件进入系统的最大请求数
 * @para  averageRate - 预期的每秒请求数(新版本也支持使用分钟为单位)
 * 
 * @author lovnx
 */
public class RateLimiter {
    //限流时间单位
    private final long rateToMsConversion;
    //当前可供消费的令牌数量
    private final AtomicInteger consumedTokens = new AtomicInteger();
    //上一次填充令牌的时间戳
    private final AtomicLong lastRefillTime = new AtomicLong(0);

    //限流时间单位可设置为TimeUnit.SECONDS,已废弃
    @Deprecated
    public RateLimiter() {
        this(TimeUnit.SECONDS);
    }

    //限流时间单位可设置为TimeUnit.SECONDS或TimeUnit.MINUTES
    public RateLimiter(TimeUnit averageRateUnit) {
        switch (averageRateUnit) {
            case SECONDS:
                rateToMsConversion = 1000;
                break;
            case MINUTES:
                rateToMsConversion = 60 * 1000;
                break;
            default:
                throw new IllegalArgumentException("TimeUnit of " + averageRateUnit + " is not supported");
        }
    }

    //这个方法默认传的当前系统时间戳
    public boolean acquire(int burstSize, long averageRate) {
        return acquire(burstSize, averageRate, System.currentTimeMillis());
    }

    public boolean acquire(int burstSize, long averageRate, long currentTimeMillis) {
        //这里为了避免傻白甜将burstSize和averageRate设为负值而抛出异常
        if (burstSize <= 0 || averageRate <= 0) {
            return true;
        }
        //填充令牌
        refillToken(burstSize, averageRate, currentTimeMillis);
        //消费令牌成功与否
        return consumeToken(burstSize);
    }

    private void refillToken(int burstSize, long averageRate, long currentTimeMillis) {
        //得到上一次填充令牌的时间戳
        long refillTime = lastRefillTime.get();
        //时间间隔timeDelta = 传进来的时间戳currentTimeMillis - 上一次填充令牌的时间戳refillTime
        long timeDelta = currentTimeMillis - refillTime;
        //计算出新的令牌数量newTokens = 时间间隔 * 平均速率 / 限流时间单位
        long newTokens = timeDelta * averageRate / rateToMsConversion;
        //如果新的令牌数量大于0个
        if (newTokens > 0) {
            
            //就等于上一次填充令牌的时间戳 + 新的令牌数量 * 限流时间单位 / 平均速率
            long newRefillTime = refillTime == 0
                    ? currentTimeMillis
                    : refillTime + newTokens * rateToMsConversion / averageRate;
            //如果lastRefillTime内存偏移量值==上一次填充令牌的时间戳refillTime,则将lastRefillTime内存值设置为新的填充令牌时间戳newRefillTime
            //成功时进入条件体放令牌
            if (lastRefillTime.compareAndSet(refillTime, newRefillTime)) {
                //放令牌(核心代码)
                while (true) {
                    //得到当前已消费的令牌数量currentLevel
                    int currentLevel = consumedTokens.get();
                    //获取校正令牌数量adjustedLevel,从当前已消费的令牌数量currentLevel和允许最大请求数burstSize间取小者,以防允许最大请求数burstSize变小
                    //这一步和下一步叫做“流量削峰”
                    int adjustedLevel = Math.min(currentLevel, burstSize);
                    //获取新的令牌数量newLevel,0 与 (校正值 - 计算值)之间取大者
                    int newLevel = (int) Math.max(0, adjustedLevel - newTokens);
                    //如果当前已消费的令牌内存偏移量等于consumedTokens等于currentLevel,则将已消费的令牌量consumedTokens设置为新的令牌数量newLevel
                    //终止放令牌,在已消费偏移量不等于currentLevel时循环计算,直到它们相等
                    if (consumedTokens.compareAndSet(currentLevel, newLevel)) {
                        return;
                    }
                }
            }
        }
    }

    //消费令牌,传入突发量
    private boolean consumeToken(int burstSize) {
        //取令牌
        while (true) {
            //得到当前已消费的令牌数量currentLevel
            int currentLevel = consumedTokens.get();
            //如果已消费令牌量大于等于突发量,则不能消费令牌
            if (currentLevel >= burstSize) {
                return false;
            }
            //消费令牌,已消费令牌量+1
            if (consumedTokens.compareAndSet(currentLevel, currentLevel + 1)) {
                return true;
            }
        }
    }

    //重置令牌桶
    public void reset() {
        consumedTokens.set(0);
        lastRefillTime.set(0);
    }
}

java B2B2C Springboot多租户电子商城系统

目录
相关文章
|
5天前
|
JavaScript 安全 Java
java版药品不良反应智能监测系统源码,采用SpringBoot、Vue、MySQL技术开发
基于B/S架构,采用Java、SpringBoot、Vue、MySQL等技术自主研发的ADR智能监测系统,适用于三甲医院,支持二次开发。该系统能自动监测全院患者药物不良反应,通过移动端和PC端实时反馈,提升用药安全。系统涵盖规则管理、监测报告、系统管理三大模块,确保精准、高效地处理ADR事件。
|
1月前
|
监控 前端开发 Java
Java SpringBoot –性能分析与调优
Java SpringBoot –性能分析与调优
|
1月前
|
JavaScript Java 项目管理
Java毕设学习 基于SpringBoot + Vue 的医院管理系统 持续给大家寻找Java毕设学习项目(附源码)
基于SpringBoot + Vue的医院管理系统,涵盖医院、患者、挂号、药物、检查、病床、排班管理和数据分析等功能。开发工具为IDEA和HBuilder X,环境需配置jdk8、Node.js14、MySQL8。文末提供源码下载链接。
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
166 1
|
3月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
176 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
3月前
|
前端开发 JavaScript Java
SpringBoot项目部署打包好的React、Vue项目刷新报错404
本文讨论了在SpringBoot项目中部署React或Vue打包好的前端项目时,刷新页面导致404错误的问题,并提供了两种解决方案:一是在SpringBoot启动类中配置错误页面重定向到index.html,二是将前端路由改为hash模式以避免刷新问题。
268 1
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
108 62
|
1月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个前后端分离的应用框架,实现动态路由和菜单功能。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,帮助开发者提高开发效率和应用的可维护性。
62 2
|
3月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
230 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
3月前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
172 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统

推荐镜像

更多