Spring Cloud Alibaba Sentinel 集成与限流实战(6)

news2024/11/24 20:41:00

项目的源码地址
Spring Cloud Alibaba 工程搭建(1)
Spring Cloud Alibaba 工程搭建连接数据库(2)
Spring Cloud Alibaba 集成 nacos 以及整合 Ribbon 与 Feign 实现负载调用(3)
Spring Cloud Alibaba Ribbon 负载调用说明(4)
Spring Cloud Alibaba 核心理论 CAP与BASE理论简单理解(5)
Spring Cloud Alibaba Sentinel 集成与限流实战(6)
Spring Cloud Alibaba 网关 Gateway 集成(7)

目录

什么是Sentinel?

  • 阿里巴巴开源的分布式系统流控工具
  • 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性
  • 丰富的应用场景:消息削峰填谷、集群流量控制、实时熔断下游不可用应用等
  • 完备的实时监控:Sentinel 同时提供实时的监控功能
  • 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合
  • 官网:home | Sentinel (sentinelguard.io)

核心概念:

  • 资源:是 Sentinel 中的核心概念之一,可以是java程序中任何内容,可以是服务或者方法甚至代码,总结起来就是我们要保护的东西
  • 规则:定义怎样的方式保护资源,主要包括流控规则、熔断降级规则等
    官方详细介绍 introduction | Sentinel (sentinelguard.io)

Sentinel 服务

  • Sentinel 分为两个部分
    • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo、Spring Cloud 等框架也有较好的支持。
    • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

Sentinel 控制台搭建

官方文档:https://github.com/alibaba/Sentinel/wiki/控制台
控制台包含如下功能:

  • 查看机器列表以及健康情况:收集 Sentinel 客户端发送的心跳包,用于判断机器是否在线。
  • 监控 (单机和集群聚合)通过 Sentinel 客户端暴露的监控 API,定期拉取并且聚合应用监控信息,最终可以实现秒级的实时监控。
  • 规则管理和推送:统一管理推送规则。
  • 鉴权:生产环境中鉴权非常重要。这里每个开发者需要根据自己的实际情况进行定制。
//启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本,
//-Dserver.port=8858 用于指定 Sentinel 控制台端口为 8858 
//默认用户名和密码都是 sentinel
​
java -Dserver.port=8858 -Dcsp.sentinel.dashboard.server=localhost:8858 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard-1.8.0.jar

注意:

  • 如果是在 linux 系统上面,需要记得打开对应的端口防火墙
  • 如果是在 windows 上面,就要注意使用管理员模式运行命令行(另外需要使用 jdk 11),我本地是使用 jdk 17 的时候,启动报错

登录的用户名和密码:默认用户名和密码都是 sentinel
sentinel 控制台

程序集成 Sentinel

在 demo-order、demo-video 的 pom 文件中增加依赖

<!--添加sentinel客户端-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

修改对应的配置文件

#dashboard: 8080 控制台端口
#port: 9999 本地启的端口,随机选个不能被占用的,与dashboard进行数据交互,会在应用对应的机器上启动一个 Http Server,
# 该 Server 会与 Sentinel 控制台做交互, 若被占用,则开始+1一次扫描

spring:
  cloud:
    sentinel:
      transport:
        dashboard: 127.0.0.1:8858 
        port: 9999

微服务注册上去后,由于Sentinel是懒加载模式,所以需要访问微服务后才会在控制台出现
我们访问下: localhost:9000/api/v1/video_order/findById?videoId=30
访问请求

然后就可以看到 sentinel 的控制台上面增加了对应的模块信息了,我们多请求几次,可以看到 实时监控下面是有对应的数据收集
数据收集

基于QPS限流配置实战

我们是初步了解下怎么设置,先找到对应的模块的资源,然后设置流控规则,从这里可以看到,我们可以对指定的接口去设置流控,这个设置的颗粒度还是比较细的
找到资源路径

新增流控规则,这里我们为了方便于查看效果,就给一个单击阈值为:2新增流控规则

新增完了之后,可以在流控规则这里找到
流控规则

再次访问 localhost:9000/api/v1/video_order/findById?videoId=30,这次我们点击刷新的时候点击快一点:
流控报错

Sentinel流量控制功能

有了初步的操作之后,我们来简单的了解下 sentinel 的流控功能,首先我们先了解下什么是流量控制(flow control)?

原理是监控应用流量的 QPS 或并发线程数等指标,当达到指定的阈值时对流量进行控制,以避免被瞬时的流量高峰冲垮,从而保障应用的高可用性。

面板参数

面板参数
参数说明

  • 针对来源:Sentinel 可以针对调用者进行限流,填写具体微服务名时,指定对此微服务进行限流 (就是可以指定是哪个来源的进行限流,不是这个来源的不限流),默认值为 default(不区分来源,全部限制)。
  • 阈值类型/单机阈值:用于限制和控制流量的一种度量标准的类型,可以为 QPS(Queries Per Second,每秒请求数)也可以为“并发线程数”。
    • QPS:每秒请求达到此值开始限流。
    • 并发线程数:请求此资源的线程达到某个值时限流。每个请求分配一个线程,当请求执行时间长时,很快就会触发限流,相反如果线程执行速度快,那么限流触发就会概率就会比较小。
  • 流控模式:流量控制模式。
    • 直接:接口达到限流条件时,直接限流。
    • 关联:当关联的资源达到阈值时,就限流自己。
    • 链路:指定资源从入口资源进来的流量,如果达到阈值,就进行限流。
  • 流控效果:流量控制效果。
    • 快速失败:该方式是默认的流量控制方式,比如 QPS 超过任意规则的阈值后,新的请求就会被立即拒绝,拒绝方式为抛出 FlowException。这种方式适用于对系统处理能力确切已知的情况下,比如通过压测确定了系统的准确水位时。
    • 排队等待(也叫匀速通过):排队等待会严格控制请求通过的间隔时间,让请求稳定且匀速的通过,可以用来处理间隔性突发的高流量。例如抢票软件,在某一秒或者一分钟内有大量的请求到来,而接下来的一段时间里处于空闲状态,我们希望系统能够在接下来的空余时间里也能出去这些请求,而不是直接拒绝。在设置排队等待时,需要填写超时时间。
    • Warm Up:此项叫做预热或者冷启动方式,此模式主要是防止流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮,通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。当使用 Warm Up 模式时,我们还需要指定启动时开放的 QPS 比例(DEFAULT_COLD_FACTOR,默认值为 3,代表 30%),以及系统预热所需时长(warmUpPeriodSec,默认值是 10 秒)。

限流页面当“是否集群”选中之后,就会是这样的界面:
集群勾选
其中最后一项“失败退化”中的 Token Server 含义如下:Token Server 是 Sentinel 用于集群流量控制的关键组件,它负责分发令牌并进行流量控制。当 Sentinel 的应用程序配置为集群限流模式时,它会向 Token Server 请求令牌,然后根据令牌情况来进行流量控制。 如果 Token Server 不可用,可能是由于网络故障、Token Server 实例崩溃等原因,这时候无法从 Token Server 获取令牌。Token Server 配置的含义如下:

  • 当配置选项为"是"时:表示当 Token Server 不可用时,Sentinel 会自动切换为单机限流模式。在单机限流模式中,Sentine 会从本地的限流规则进行流量控制,不再依赖 Token Server。这样可以保证即使 Token Server 不可用,也能够继续对流量进行限制。
  • 当配置选项为"否"时:表示当 Token Server 不可用时,Sentinel 不会自动切换为单机限流模式,流量控制会被暂停,即无法进行限流,可能会导致服务负载过高。

基于并发线程数限流

首先,在 OrderController 增加测试代码

@RequestMapping("list")
public Map list() throws InterruptedException {
    TimeUnit.SECONDS.sleep(5);
    return Map.of("title", "互联网架构之JAVA虚拟机JVM零基础到高级实战", "price", 199.00, "createTime", new Date());
}

然后测试访问下:http://localhost:9000/api/v1/video_order/list
测试访问
接着,配置对应的流控规则:
找到对应的资源
这里我们选择线程数,单机阈值为 1
设置阈值
重新请求 http://localhost:9000/api/v1/video_order/list,浏览器刷新两次
线程流控

流控效果-Warm Up 与 排队等待

Warm Up:冷启动/预热,如果系统在此之前⻓期处于空闲的状态,我们希望处理请求的数量是缓步的增多,经过预期的时间以后,到达系统处理请求个数的最⼤值。比如说,我们设置下面的值:就表示经过10s 达到最大阈值 90
流控规则
结合一个图再理解下
warm up

匀速排队
严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法,主要用于处理间隔性突发的流量,如消息队列,想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求
时间轴

注意:

  • 匀速排队等待策略是 Leaky Bucket 算法结合虚拟队列等待机制实现的。
  • 匀速排队模式暂时不支持 QPS > 1000 的场景
    官方文档: 流量控制 · alibaba/Sentinel Wiki (github.com)

熔断与降级

上面我们说了下流控相关的,这里我们开始讲讲面试经常问到的熔断与降级,熔断降级(虽然是两个概念,基本都是互相配合):

  • 对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一
  • 对不稳定的弱依赖服务调用进行熔断降级,暂时切断不稳定调用,避免局部不稳定因素导致整体的雪崩
  • 熔断降级作为保护自身的手段,通常在客户端(调用端)进行配置、

什么是 Sentinel 降级规则 ? 官方文档,点击这里查看 ,总的来说:就是配置一定规则,然后满足之后就对服务进行熔断降级

熔断策略

慢调用比例(响应时间)

选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。
- 比例阈值:
- 熔断时长:超过时间后会尝试恢复
- 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
降级规则
这里对上面的规则进行说明,熔断触发的最小请求数为 5:

  • 请求数 < 5,即使异常比率超出阈值也不会熔断
  • 请求数 >= 5,就是表示只要有一个请求(比例阈值设置为 0.1 体现)的最大相应时间为 100毫秒(最大 RT 设置100体现),就熔断10s(熔断时长体现)

异常比例
当单位统计时长内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断

  • 比例阈值
  • 熔断时长:超过时间后会尝试恢复。
  • 最小请求数:熔断触发的最小请求数,请求数小于该值时,即使异常比率超出阈值也不会熔断。
    异常比例

异常数
当单位统计时长内的异常数目超过阈值之后会自动进行熔断

  • 异常数:
  • 熔断时长:超过时间后会尝试恢复
  • 最小请求数:熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断
    异常数

熔断的状态

服务熔断一般有三种状态

  • 熔断关闭(Closed):服务没有故障时,熔断器所处的状态,对调用方的调用不做任何限制
  • 熔断开启(Open):后续对该服务接口的调用不再经过网络,直接执行本地的fallback方法
  • 半熔断(Half-Open):所谓半熔断就是尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率
    熔断的状态

熔断的恢复:

  • 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态)尝试恢复服务调用,允许有限的流量调用该服务,并监控调用成功率。
  • 如果成功率达到预期,则说明服务已恢复,进入熔断关闭状态;如果成功率仍旧很低,则重新进入熔断状态

熔断降级的测试

第一步:增加测试源码
这里我们先修改下源码 OrderController,将 list 接口修改下:

int temp = 0;

/**
 * 用于测试熔断、降级
 *
 * @return map
 */
@RequestMapping("list")
private Map list(HttpServletRequest httpRequest) {

    temp++;

    if (temp % 3 == 0) {
        throw new RuntimeException("服务异常");
    }

    String serverInfo = httpRequest.getServerName() + ":"+ httpRequest.getServerPort();
    return Map.of("title", "测试返回数据", "name", "返回名称", "serverInfo", serverInfo);
}

代码比较简单,这样子就可以模拟出报错的情况,这里我就不贴报错的图片了
修改之后请求
第二步:增加降级规则
增加降级规则
这里我们为了测试方便,就选择异常比例的策略,阈值就选择0.1,点击新增,然后我们开始测试
新增规则

第三步:测试
访问:http://localhost:9000/api/v1/video_order/list ,然后快速刷新,就可以看到发生报错
发生熔断
报错之后,继续刷新的话还是报错,因为我们设置的是 10s 左右,我们等一会,再来请求:
再次请求

自定义流控异常

从上面的图,我们可以知道发生流控报错之后,就在页面上面显示了一个文字信息,但是我们实际生产中,更多的是使用 JSON 格式来传输数据,所以我们需要改造下。

具体的实现方式:

// 需要实现 BlockExceptionHandler 接口,然后在 handle 中写对应的业务逻辑
public class MyUrlBlockHandler implements BlockExceptionHandler {
   
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
    //降级业务处理
    }
}

sentinel 异常的种类

  • FlowException 限流异常
  • DegradeException 降级异常
  • ParamFlowException 参数限流异常
  • SystemBlockException 系统负载异常
  • AuthorityException 授权异常

增加对应的源码

@Component
public class MyUrlBlockHandler implements BlockExceptionHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        Map<String,Object> backMap=new HashMap<>();
        if (e instanceof FlowException){
            backMap.put("code",-1);
            backMap.put("msg","限流-异常啦");
        }else if (e instanceof DegradeException){
            backMap.put("code",-2);
            backMap.put("msg","降级-异常啦");
        }else if (e instanceof ParamFlowException){
            backMap.put("code",-3);
            backMap.put("msg","热点-异常啦");
        }else if (e instanceof SystemBlockException){
            backMap.put("code",-4);
            backMap.put("msg","系统规则-异常啦");
        }else if (e instanceof AuthorityException){
            backMap.put("code",-5);
            backMap.put("msg","认证-异常啦");
        }

        // 设置返回json数据
        httpServletResponse.setStatus(200);
        httpServletResponse.setHeader("content-Type","application/json;charset=UTF-8");
        httpServletResponse.getWriter().write(JSON.toJSONString(backMap));
    }
}

源码结构
这里需要重新配置下限流或者降级的规则,不然是看不到效果的,这里我就随便配置一个降级策略,
新增的降级策略
多刷新几次就可以看到对应的效果了
在这里插入图片描述

Sentinel整合OpenFeign配置

我们这里调用是通过 order 服务 调用 video 服务 如果是说,在我们调用 video 服务的时候报错,或者说 video 服务现在不可用,我们让程序返回固定默认的数据,而不是直接报错返回。

整合的步骤

加入依赖

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

开启Feign对Sentinel的支持

feign:
  sentinel:
    enabled: true

开始Fegin 对 sentinel 的支持

创建容错类,实现对应的服务接口,记得加注解 @Service

@Service
public class VideoServiceFallback implements VideoService {
    @Override
    public Video findById(int videoId) {
        Video video = new Video();
        video.setTitle("熔断降级数据");
        return video;
    }@Override
    public Video saveVideo(Video video) {
        return null;
    }
}

增加 fallback

配置feign容错类,准备兜底数据

@FeignClient(value = "xdclass-video-service", fallback = VideoServiceFallback.class)

配置 fallBack
这个时候,我们只启动一个服务,就是 Order 服务,然后访问下: http://localhost:9000/api/v1/video_order/findById?videoId=30,好了现在就可以看到效果了
兜底数据

到此,我们就搞完了 sentinel 的基础入门了,我暂时也只学到了这些。 狗头.png,其实整个搭建都不算特别难,因为我们没有说去读源码那些(面试太卷了点),如果是学习使用的,这些应该可以应对很多场景了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1669827.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL————创建存储过程函数

存储过程使用大纲 有参数传递 delimiter $$ 声明一个名称为get_student_introduce create procedure add_student_infor( in p_userName VARCHAR(20),in p_phone VARCHAR(11),in p_sex char(2),in p_introduce VARCHAR(255)) 开始操作 BEGIN 撰写真正在操作DMLDQL都行 INSE…

Transformer模型详解04-Encoder 结构

文章目录 简介基础知识归一化作用常用归一化 残差连接 Add & NormFeed Forward代码实现 简介 Transformer 模型中的 Encoder 层主要负责将输入序列进行编码&#xff0c;将输入序列中的每个词或标记转换为其对应的向量表示&#xff0c;并且捕获输入序列中的语义和关系。 具…

(超详细讲解)实现将idea的java程序打包成exe (新版,可以在没有java的电脑下运行,即可以发给好朋友一起玩)

目录 实现打包到exe大概步骤 工具准备 1.将java程序文件打包成jar文件 2.准备好jre文件 3.使用exe4j软件打包好 4.最终打包 实现打包到exe大概步骤 1.打包需要满足的条件&#xff1a;将java文件转成jar文件的工具exe4j、 以及需要满足jdk1.8以上&#xff08;因安装exe4…

Android面试题之Kotlin和Java之间互操作

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 互操作性和可空性 要注意Java中所有类型都是可空的String!表示平台数据类型 public class JavaTest {public String generateName() {return …

2024中国(重庆)无人机展览会8月在重庆举办

2024中国(重庆)无人机展览会8月在重庆举办 邀请函 主办单位&#xff1a; 中国航空学会 重庆市南岸区人民政府 招商执行单位&#xff1a; 重庆港华展览有限公司 报名&#xff1a;【交易会I 59交易会2351交易会9466】 展会背景&#xff1a; 为更好的培养航空航天产业和无人…

Python 数据处理 合并二维数组和 DataFrame 中特定列的值

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 示例代码如下&#xff1a; import numpy as np import pandas as pddata {label: [1, 2, 3, 4]} df pd.DataFrame(data)values_array df[["label"]].values random_array np.random.ran…

CSDN使用

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

Python-VBA函数之旅-sum函数

目录 一、sum函数的常见应用场景 二、sum函数使用注意事项 三、如何用好sum函数&#xff1f; 1、sum函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、sum函数的常…

AI绘画神级Stable Diffusion入门教程|快速入门SD绘画原理与安装

什么是Stable Diffusion&#xff0c;什么是炼丹师&#xff1f;根据市场研究机构预测&#xff0c;到2025年全球AI绘画市场规模将达到100亿美元&#xff0c;其中Stable Diffusion&#xff08;简称SD&#xff09;作为一种先进的图像生成技术之一&#xff0c;市场份额也在不断增长&…

Llama3-Tutorial(Llama 3 超级课堂)-- 笔记

第1节—Llama 3 本地 Web Demo 部署 端口转发 vscode里面设置端口转发 https://a-aide-20240416-b4c2755-160476.intern-ai.org.cn/proxy/8501/ ssh -CNg -L 8501:127.0.0.1:8501 rootssh.intern-ai.org.cn -p 43681参考 https://github.com/SmartFlowAI/Llama3-Tutorial/b…

每日一练2024.5.9

题目&#xff1a; 给定一个非负整数数组 nums&#xff0c; nums 中一半整数是 奇数 &#xff0c;一半整数是 偶数 。 对数组进行排序&#xff0c;以便当 nums[i] 为奇数时&#xff0c;i 也是 奇数 &#xff1b;当 nums[i] 为偶数时&#xff0c; i 也是 偶数 。 你可以返回 …

防伪溯源一体化管理系统基于FastAdmin+ThinkPHP和Uniapp(源码搭建/上线/运营/售后/维护更新)

一款基于FastAdminThinkPHP和Uniapp进行开发的多平台&#xff08;微信小程序、H5网页&#xff09;溯源、防伪、管理一体化独立系统&#xff0c;拥有强大的防伪码和溯源码双码生成功能&#xff08;内置多种生成规则&#xff09;、批量大量导出防伪和溯源码码数据、支持代理商管理…

活动预告|“AI+Security”系列第1期:大模型网络空间安全前沿探索活动火热报名中

由Wisemodel社区、安全极客主办的 “AISecurity”系列第1期&#xff1a; 大模型网络空间安全前沿探索 线下活动 将于2024年5月18日下午14:00 在苏州街16号神州数码大厦5层举行 本活动旨在汇聚业界专家和实践者共同探讨和推进AI自身安全、AI赋能安全与AI给安全带来的挑战等关…

产品设计中的“注册”说明

​在使用网站或应用的时候必不可少的就是账号系统&#xff0c;账号系统有些人可能觉得简单&#xff0c;无非就是账号密码。真的是这样吗&#xff1f; 一个完整的账号系统通常大家会分成四部分&#xff1a; 1.注册&#xff08;手机号、邮箱、用户名/密码限制/验证码&#xff09;…

项目8-头像的上传

js实现头像上传并且预览图片功能以及提交 - 掘金 (juejin.cn) 我们简单建立一个表 1.前端知识储备 1.1 addClass的使用 1.基本语法 addClass() 方法向被选元素添加一个或多个类。 该方法不会移除已存在的 class 属性&#xff0c;仅仅添加一个或多个 class 属性。 提示&…

隧道建设的数字眼睛:盾构机实时可视化技术

盾构机可视化技术可以展现盾构机在隧道掘进过程中的各项工作状态。这种技术能够将复杂的数据和参数转化为直观的图像和动画&#xff0c;包括盾构机的推进速度、土压力、刀盘转速和位置信息等关键性能指标。 通过 HT 可视化&#xff0c;工程师可以实时监控盾构机的运行状况&…

网站域名SSL证书怎么获取和安装

一、获取SSL证书 1、选择证书颁发机构&#xff08;CA&#xff09;&#xff1a; 选择一个受信任的SSL证书颁发机构&#xff0c;如JoySSL、Comodo、DigiCert、GlobalSign等。 2、生成证书签名请求&#xff08;CSR&#xff09;&#xff1a; 在您的服务商的网站上生成CSR。CSR中…

云相册APP

简介 一款用于云存照片的app&#xff0c;支持批量上传和下载照片。 平台技术 Android客户端&#xff1a;Kotlin 协程 Retrofit Server服务后端&#xff1a;Java SpringBoot 部署云服务器&#xff1a;华为云耀云服务器L实例 下载网址 小鲸鱼相册 Ps: 由于网站域名备案审核…

学校能源消耗监测管理系统,打造智能监测系统

学校能源消耗监测管理系统是一款针对&#xff0c;水、电、煤、气、热等能源的在线监测、分析与处理的系统&#xff0c;为学校管理者提供全面的能源使用情况&#xff0c;为学校管理工作提供了有力的支持。 为什么要建设能源管理系统&#xff1f; 用能需求增加 随着学校的快速…

星戈瑞SH-PEG3-OH一种多功能生物相容性PEG小分子

SH-PEG3-OH是一种含有硫基&#xff08;-SH&#xff09;、三个乙二醇单元和羟基&#xff08;-OH&#xff09;的小分子化合物。其分子结构中的硫基赋予了其独特的化学反应性&#xff0c;能够与其他含有不饱和键的化合物发生点击化学反应&#xff0c;如迈克尔加成反应等。同时&…