手把手教你改造Sentinel Dashboard 实现配置持久化

一. 概述

Sentinel客户端默认情况下接收到 Dashboard 推送的规则配置后,可以实时生效。但是有一个致命缺陷,Dashboard和业务服务并没有持久化这些配置,当业务服务重启后,这些规则配置将全部丢失。

Sentinel 提供两种方式修改规则:

  • 通过 API 直接修改 (loadRules)
  • 通过 DataSource 适配不同数据源修改

通过 API 修改比较直观,可以通过以下几个 API 修改不同的规则:

FlowRuleManager.loadRules(List<FlowRule> rules); // 修改流控规则
DegradeRuleManager.loadRules(List<DegradeRule> rules); // 修改降级规则

手动修改规则(硬编码方式)一般仅用于测试和演示,生产上一般通过动态规则源的方式来动态管理规则。

上述 loadRules() 方法只接受内存态的规则对象,但更多时候规则存储在文件、数据库或者配置中心当中。DataSource 接口给我们提供了对接任意配置源的能力。相比直接通过 API 修改规则,实现 DataSource 接口是更加可靠的做法。

我们推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource 接口端监听规则中心实时获取变更,流程如下:

DataSource 扩展常见的实现方式有:

  • 拉模式:客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;
  • 推模式:规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

Sentinel 目前支持以下数据源扩展:

  • Pull-based: 动态文件数据源、Consul, Eureka
  • Push-based: ZooKeeper, Redis, Nacos, Apollo, etcd

Sentinel开源版在Push模式下只实现了 路径2,也就是Nacos到业务服务之间的规则同步;路径1 Dashboard配置修改写入Nacos并没有实现,在后文中我们会介绍如何修改 Dashboard 源码完成配置的写入。

二. 从 Nacos 加载规则配置

首先,我们先来看看如何使用Sentinel官方提供的 sentinel-datasource-nacos 从Nacos加载规则配置。

第一步:引入依赖

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><version>1.8.6</version>
</dependency>

第二步:配置规则自动加载

package cn.bigcoder.demo.sentinel.sentineldemo.demos.config;import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.nacos.NacosDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.nacos.api.PropertyKeyConst;
import java.util.List;
import java.util.Properties;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;@Component
public class SentinelRuleConfiguration implements ApplicationListener<ContextRefreshedEvent> {private static final String remoteAddress = "10.10.10.12:8848";// nacos groupprivate static final String groupId = "SENTINEL_GROUP";// nacos dataIdprivate static final String dataId = "sentinel-demo";private static final String NACOS_NAMESPACE_ID = "SENTINEL";@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, remoteAddress);
//        properties.put(PropertyKeyConst.NAMESPACE, NACOS_NAMESPACE_ID);ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(properties, groupId,dataId,source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {}));FlowRuleManager.register2Property(flowRuleDataSource.getProperty());}
}

第三步:往Nacos中写入配置

import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import java.util.Properties;public class NacosConfigSender {public static void main(String[] args) throws Exception {final String groupId = "SENTINEL_GROUP";final String dataId = "sentinel-demo-flow-rules";// 创建ConfigService实例Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, "10.10.10.12:8848");// 指定namespaceproperties.put(PropertyKeyConst.NAMESPACE, "SENTINEL");final String rule = "[\n"+ "  {\n"+ "    \"resource\": \"GET:/user/getById\",\n"+ "    \"controlBehavior\": 0,\n"+ "    \"count\": 1,\n"+ "    \"grade\": 1,\n"+ "    \"limitApp\": \"default\",\n"+ "    \"strategy\": 0\n"+ "  }\n"+ "]";ConfigService configService = NacosFactory.createConfigService(properties);System.out.println(configService.publishConfig(dataId, groupId, rule));}
}

执行完后,Nacos中就会出现对应的配置:

第四步:启动项目,验证规则配置是否生效

访问 http://127.0.0.1:8719/getParamRules?type=flow 即可看到业务服务内存中加载到的规则配置

并发执行 /user/getById 接口,可以发现接口被成功限流,1s内的10次请求,只有一次成功。
在这里插入图片描述

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=https%3A%2F%2Fimage.bigcoder.cn%2F20240616133032.png-large&pos_id=img-Db7YQEaO-1718516239482

三. Dashboard存在的问题

使用此方案虽然解决了配置规则配置持久化的问题,但是在Dashboard上修改配置仍然是通过业务服务暴露的接口进行的配置同步。业务服务既可以接收 Nacos 配置变更,又可以接收Dashboard的配置变更,控制台的变更的配置并没有同步到Nacos,应用重启后Sentinel控制台修改的配置仍然会全部丢失:

一个理想的情况是Sentinel控制台规则配置读取至 Nacos 而不是内存,在控制台修改/新增的配置写入Nacos,当Nacos配置发生变更时,配置进而自动同步至业务服务:
在这里插入图片描述

当然存储媒介可以根据情况选用别的组件:ZooKeeper, Redis, Apollo, etcd

很可惜的是,阿里官方开源的Sentinel控制台并没有实现将规则配置写入其他中间件的能力。它默认只支持将配置实时推送至业务服务,所以我们在生产环境中想要使用 Sentinel Dashboard 需要自行修改其源码,将其配置同步逻辑改为写入我们所需要的中间件中。

四. 修改Sentinel Dashboard源码

4.1 准备工作

首先通过git拉取下载源码,导入idea工程:

https://github.com/alibaba/Sentinel

本文源码修改基于 Sentinel 1.8.8 版本,所有修改的源码可参考:

https://github.com/bigcoder84/Sentinel

4.1.1 流控规则接口

Sentinel Dashboard的流控规则下的所有操作,都会调用Sentinel-Dashboard源码中的FlowControllerV1类,这个类中包含流控规则本地化的CRUD操作:

在com.alibaba.csp.sentinel.dashboard.controller.v2包下存在一个FlowControllerV2;类,这个类同样提供流控规则的CURD,与V1不同的是,它可以实现指定数据源的规则拉取和发布

@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);@Autowiredprivate InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;@Autowired@Qualifier("flowRuleNacosProvider")private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;@Autowired@Qualifier("flowRuleNacosPublisher")private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;//....
}

官方说明:从 Sentinel 1.4.0 开始,我们抽取出了接口用于向远程配置中心推送规则以及拉取规则。

  • DynamicRuleProvider<T>: 拉取规则
  • DynamicRulePublisher<T>: 推送规则

以 Nacos 为例,若希望使用 Nacos 作为动态规则配置中心,用户可以提取出相关的类,然后只需在 FlowControllerV2 中指定对应的 bean 即可开启 Nacos 适配

FlowControllerV2依赖两个非常重要的类

  • DynamicRuleProvider:动态规则的拉取,从指定数据源中获取控制后在Sentinel Dashboard中展示。
  • DynamicRulePublisher:动态规则发布,将在Sentinel Dashboard中修改的规则同步到指定数据源中。

只需要扩展这两个类,然后集成Nacos来实现Sentinel Dashboard规则同步

4.1.2 需要改造的页面入口

簇点链路:

由于该页面的“流控”配置是对单节点进行配置的,所以理论上该页面的URL是不用改的

流控规则:

上述位置我们都需要改造对应前端代码,使之调用的接口更改为我们新的V2接口上。

4.2 源码改造

4.2.1 在pom.xml文件中去掉test scope注释

这是因为官方提供的Nacos持久化用例都是在test目录下,所以scope需要去除test,需要sentinel-datasource-nacos包的支持。之后将修改好的源码放在源码主目录下,而不是继续在test目录下。

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><!--<scope>test</scope>-->
</dependency>
4.2.2 创建Nacos配置

我们采用官方的约束,即默认 Nacos 适配的 dataId 和 groupId 约定如下:

  • groupId: SENTINEL_GROUP
  • 流控规则 dataId: {appName}-flow-rules,比如应用名为 appA,则 dataId 为 appA-flow-rules

所以不需要修改NacosConfigUtil.java了,但这是展示是为了步骤的完整性。

package com.alibaba.csp.sentinel.dashboard.rule.nacos;import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "sentinel.nacos")
public class NacosPropertiesConfiguration {private String serverAddr;private String groupId = "SENTINEL_GROUP"; // 默认分组private String namespace;// 省略 getter/setter  
}

然后配置sentinel-dashboar/resources/application.properties中配置nacos配置,以为sentinel.nacos为前缀:

# nacos config server
sentinel.nacos.serverAddr=127.0.0.1:8848
sentinel.nacos.namespace=
sentinel.nacos.group-id=SENTINEL-GROUP
4.2.3 改造NacosConfig,创建NacosConfigService
package com.alibaba.csp.sentinel.dashboard.config;import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import java.util.List;
import java.util.Properties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@EnableConfigurationProperties(NacosPropertiesConfiguration.class)
@Configuration
public class NacosConfig {@Beanpublic Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {return s -> JSON.parseArray(s, FlowRuleEntity.class);}@Beanpublic ConfigService nacosConfigService(NacosPropertiesConfiguration nacosPropertiesConfiguration)throws Exception {Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, nacosPropertiesConfiguration.getServerAddr());properties.put(PropertyKeyConst.NAMESPACE, nacosPropertiesConfiguration.getNamespace());return ConfigFactory.createConfigService(properties);}
}

NacosConfig主要做两件事:

1) 注入Convert转换器,将 FlowRuleEntity 使用序列化为JSON字符串,以及将JSON字符串反序列化为 FlowRuleEntity

2) 注入Nacos配置服务ConfigService

4.2.4 实现 DynamicRulePublisher 和 DynamicRuleProvider 接口完成配置的持久化和远程加载

在 test 包下,已经有Sentinel官方的实现了,我们只需要将其拷贝至 src 目录下即可:

FlowRuleNacosProvider:用于从Nacos中拉取规则配置。

package com.alibaba.csp.sentinel.dashboard.rule;import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.util.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** @author Eric Zhao* @since 1.4.0*/
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<String, List<FlowRuleEntity>> converter;@Overridepublic List<FlowRuleEntity> getRules(String appName) throws Exception {String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, 3000);if (StringUtil.isEmpty(rules)) {return new ArrayList<>();}return converter.convert(rules);}
}

FlowRuleNacosPublisher:用于将配置保存至Nacos中

package com.alibaba.csp.sentinel.dashboard.rule;import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.util.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;/*** @author Eric Zhao* @since 1.4.0*/
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<List<FlowRuleEntity>, String> converter;@Overridepublic void publish(String app, List<FlowRuleEntity> rules) throws Exception {AssertUtil.notEmpty(app, "app name cannot be empty");if (rules == null) {return;}configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, converter.convert(rules));}
}
4.2.5 修改FlowControllerV2类将Nacos实现类注入进去

在这里插入图片描述

@RestController
@RequestMapping(value = "/v2/flow")
public class FlowControllerV2 {private final Logger logger = LoggerFactory.getLogger(FlowControllerV2.class);@Autowiredprivate InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;@Autowired@Qualifier("flowRuleNacosProvider")private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;@Autowired@Qualifier("flowRuleNacosPublisher")private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;// 省略      
}

到这里所有流控规则相关的后端接口都已经改造完毕,我们需要接着改造前端页面,将页面请求的接口全部换成V2新接口。

4.2.6 修改前端“流控规则”路由配置(sidebar.html)

找到 resources/app/scripts/directives/sidebar/sidebar.html 文件,该文件是用来渲染左侧路由的:

我们需要将 “流控规则” 路由跳转的页面由 app/views/flow_v1.html 更换为 app/views/flow_v2.html,因为 flow_v2.html 页面中调用的后端接口全部都是 v2接口。

修改flowV1为flow,去掉V1,这样的话会调用FlowControllerV2接口

<!--<li ui-sref-active="active" ng-if="!entry.isGateway"><a ui-sref="dashboard.flowV1({app: entry.app})"><i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则</a>
</li>-->
<!-- 修改为flow,直接调用FlowControllerV2 -->
<li ui-sref-active="active" ng-if="!entry.isGateway"><a ui-sref="dashboard.flow({app: entry.app})"><i class="glyphicon glyphicon-filter"></i>&nbsp;&nbsp;流控规则</a>
</li>

这样就可以通过js跳转至FlowControllerV2了

      .state('dashboard.flow', {templateUrl: 'app/views/flow_v2.html',url: '/v2/flow/:app',controller: 'FlowControllerV2',resolve: {loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {return $ocLazyLoad.load({name: 'sentinelDashboardApp',files: ['app/scripts/controllers/flow_v2.js',]});}]}})
4.2.7 修改前端“簇点链路”中流控配置的接口

根据 app/scripts/directives/sidebar/sidebar.html 触点链路路由调用js方法可知,最终路由转发到了 app/views/identity.html 页面:

<!-- app/scripts/directives/sidebar/sidebar.html -->
<li ui-sref-active="active" ng-if="!entry.isGateway"><a ui-sref="dashboard.identity({app: entry.app})"><i class="glyphicon glyphicon-list-alt"></i>&nbsp;&nbsp;簇点链路</a>
</li>
// app/scripts/app.js
.state('dashboard.identity', {templateUrl: 'app/views/identity.html',url: '/identity/:app',controller: 'IdentityCtl',resolve: {loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) {return $ocLazyLoad.load({name: 'sentinelDashboardApp',files: ['app/scripts/controllers/identity.js',]});}]}
})

app/views/identity.html 页面中,我们需要将“流控”弹窗的保存按钮调用的接口换成V2版本,

在这里插入图片描述

addNewFlowRule 方法在 app/scripts/controllers/identity.js 文件中:

    $scope.addNewFlowRule = function (resource) {if (!$scope.macInputModel) {return;}var mac = $scope.macInputModel.split(':');flowRuleDialogScope = $scope.$new(true);flowRuleDialogScope.currentRule = {enable: false,strategy: 0,grade: 1,controlBehavior: 0,resource: resource,limitApp: 'default',clusterMode: false,clusterConfig: {thresholdType: 0},app: $scope.app,ip: mac[0],port: mac[1]};flowRuleDialogScope.flowRuleDialog = {title: '新增流控规则',type: 'add',confirmBtnText: '新增',saveAndContinueBtnText: '新增并继续添加',showAdvanceButton: true};// $scope.flowRuleDialog = {//     showAdvanceButton : true// };flowRuleDialogScope.saveRule = saveFlowRule;flowRuleDialogScope.saveRuleAndContinue = saveFlowRuleAndContinue;flowRuleDialogScope.onOpenAdvanceClick = function () {flowRuleDialogScope.flowRuleDialog.showAdvanceButton = false;};flowRuleDialogScope.onCloseAdvanceClick = function () {flowRuleDialogScope.flowRuleDialog.showAdvanceButton = true;};flowRuleDialog = ngDialog.open({template: '/app/views/dialog/flow-rule-dialog.html',width: 680,overlay: true,scope: flowRuleDialogScope});};

在这个方法中,会调用 saveFlowRule 方法保存流控规则:

    function saveFlowRule() {if (!FlowService.checkRuleValid(flowRuleDialogScope.currentRule)) {return;}FlowService.newRule(flowRuleDialogScope.currentRule).success(function (data) {if (data.code === 0) {flowRuleDialog.close();let url = '/dashboard/flow/' + $scope.app;$location.path(url);} else {alert('失败:' + data.msg);}}).error((data, header, config, status) => {alert('未知错误');});}

在这个方法中,会调用 FlowService.newRule 方法发送HTTP请求新建规则,成功后会将页面重定向至 '/dashboard/flow/' + $scope.app,所以我们需要改两个地方:

  1. 将FlowService改成V2版本

  2. 将重定向页面跳转至 '/dashboard/v2/flow/' + $scope.app

4.3.8 重新打包项目

进入 sentinel-dashboard 目录,执行下列命令重新打包:

mvn clean package -Dmaven.test.skip

4.3 测试

可以看到修改后的Dashboard成功将配置写入Nacos中,Nacos配置发生变更,也同时通知了订阅这些配置的客户端,使得业务服务能实时更新流控配置,即使业务服务重启,之前仍能正常从Nacos中拉取配置。

五. 总结

本文详细介绍了如何利用Nacos实现Sentinel Dashboard配置的持久化,解决了业务服务重启后配置丢失的问题。通过以下几个步骤,我们成功实现了配置的动态管理和持久化存储:

  1. 引入Nacos依赖:在项目中添加了sentinel-datasource-nacos依赖,为后续集成打下基础。
  2. 配置自动加载:通过实现ReadableDataSource接口,配置了规则自动从Nacos加载到Sentinel的流程。
  3. Nacos配置写入:通过编写NacosConfigSender类,实现了向Nacos写入配置的功能。
  4. Dashboard源码改造:针对Dashboard存在的问题,通过修改前后端源码,实现了配置的持久化存储和同步更新。

通过这一系列的改造,我们不仅提高了Sentinel Dashboard的可用性和稳定性,还增强了其在生产环境中的实用性。现在,即使在业务服务重启的情况下,配置也不会丢失,确保了服务的连续性和一致性。

本文只是讲解了“流控规则”持久化的源码修改过程,如果其它模块也有持久化的需求,也可以参考此过程进行相应的源码修改。

本文参考至:

dynamic-rule-configuration | Sentinel (sentinelguard.io)

Sentinel Dashboard(基于1.8.1)流控规则持久化到Nacos——涉及部分Sentinel Dashboard源码改造 - JJian - 博客园 (cnblogs.com)

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

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

相关文章

政务云参考技术架构

行业优势 总体架构 政务云平台技术框架图&#xff0c;由机房环境、基础设施层、支撑软件层及业务应用层组成&#xff0c;在运维、安全和运营体系的保障下&#xff0c;为政务云使用单位提供统一服务支撑。 功能架构 标准双区隔离 参照国家电子政务规范&#xff0c;打造符合标准的…

B3981 [信息与未来 2024] 图灵完备

题目描述 &#xff08;你不需要看懂这张图片&#xff1b;但如果你看懂了&#xff0c;会觉得它很有趣。&#xff09; JavaScript 是一种功能强大且灵活的编程语言&#xff0c;也是现代 Web 开发的三大支柱之一 (另外两个是 HTML 和 CSS)。灵活的 JavaScript 包含“自动类型转换…

从数据库到数据仓库:数据仓库导论

导言 本文为数据仓库导论&#xff0c;旨在介绍数据仓库的基本理念和应用场景&#xff0c;帮助读者理解数据仓库的重要性及其在企业中的实际应用。 数据仓库作为重要的数据管理和分析工具&#xff0c;已经发展了30多年&#xff0c;其过程中生态和技术都发生了巨大的变化。尽管…

分布式数据库核心问题和解决方法

当下&#xff0c;由于成本压力以及数据保护的要求&#xff0c;采用国产数据库的呼声越来越高&#xff0c;但是国产数据库数量众多&#xff0c;良莠不齐&#xff0c;没有选择数据库比较靠谱的标准&#xff0c;业内真正懂得数据库的人很少&#xff0c;且为了这块大的蛋糕&#xf…

Axios进阶

目录 axios实例 axios请求配置 拦截器 请求拦截器 响应拦截器 取消请求 axios不仅仅是简单的用基础请求用法的形式向服务器请求数据&#xff0c;一旦请求的端口与次数变多之后&#xff0c;简单的请求用法会有些许麻烦。所以&#xff0c;axios允许我们进行创建axios实例、ax…

Retrofit 注解参数详解

添加依赖 implementation com.squareup.retrofit2:retrofit:2.9.0 implementation com.squareup.retrofit2:converter-gson:2.9.0 初始化Retrofit val retrofit Retrofit.Builder().baseUrl("http://api.github.com/").addConverterFactory(GsonConverterFactory…

【Kafka】Kafka提高生产者吞吐量、数据可靠性-06

【Kafka】Kafka提高生产者吞吐量-06 1. 提高生产者吞吐量2.数据可靠性2.1 回顾数据的发送流程2.2 ack应答级别2.2.1 acks:02.2.2 acks:12.2.2 acks:-1(all)2.2.2.1 数据可靠性分析2.2.2.2 数据完全可靠 2.3 可靠性总结2.4 可靠性代码配置 1. 提高生产者吞吐量 import org.apach…

科技云报道:“元年”之后,生成式AI将走向何方?

科技云报道原创。 近两年&#xff0c;以大模型为代表的生成式AI技术&#xff0c;成为引爆数字原生最重要的技术奇点&#xff0c;人们见证了各类文生应用的进展速度。Gartner预测&#xff0c;到2026年&#xff0c;超过80%的企业将使用生成式AI的API或模型&#xff0c;或在生产环…

「实战应用」如何用图表控件LightningChart JS创建SQL仪表板应用(二)

LightningChart JS是Web上性能特高的图表库&#xff0c;具有出色的执行性能 - 使用高数据速率同时监控数十个数据源。 GPU加速和WebGL渲染确保您的设备的图形处理器得到有效利用&#xff0c;从而实现高刷新率和流畅的动画&#xff0c;常用于贸易&#xff0c;工程&#xff0c;航…

OpenCore 引导完美升级

备份原有 OC (做好回滚的准备下载新版 OpenCore https://github.com/acidanthera/OpenCorePkg/releases将 1, 3, 4 里面的文件使用新版进行替换 4 里面的文件严格来说并不需要, 只是留着方便使用不追求完美到这就可以收工了将 OC 复制到 U 盘 EFI U 盘格式化可以使用: diskutil…

微服务开发与实战Day09 - Elasticsearch

一、DSL查询 Elasticsearch提供了DSL&#xff08;Domain Specific Language&#xff09;查询&#xff0c;就是以JSON格式来定义查询条件。类似这样&#xff1a; DSL查询可以分为两大类&#xff1a; 叶子查询&#xff08;Leaf query clauses&#xff09;&#xff1a;一般是在特…

Docker Jenkins(改错版本)

Devops:它强调开发(Development)和运维(Operations)团队之间的协作.实现更快,更可靠的软件交付部署. JenKins是一个开源的自动化服务器,广泛用于构建,测试和部署软件项目.它是持续集成(CI)和持续交付/部署(CD)的工具.JenKins是实现DevOps实践的重要工具. 前端项目部署一般流程:…

Matlab|基于V图的配电网电动汽车充电站选址定容-可视化

1主要内容 基于粒子群算法的电动汽车充电站和光伏最优选址和定容 关键词&#xff1a;选址定容 电动汽车 充电站位置 仿真平台&#xff1a;MATLAB 主要内容&#xff1a;代码主要做的是一个电动汽车充电站和分布式光伏的选址定容问题&#xff0c;提出了能够计及地理因素和服…

蓝队-溯源技巧

溯源技巧 大致思想 通常情况下&#xff0c;接到溯源任务时&#xff0c;获得的信息如下 攻击时间 攻击 IP 预警平台 攻击类型 恶意文件 受攻击域名/IP其中攻击 IP、攻击类型、恶意文件、攻击详情是溯源入手的点。 通过攻击类型分析攻击详情的请求包&#xff0c;看有没有攻击者…

实在智能应邀出席中国移动科技工作者论坛,分享基于大模型+Agent智能体的“企业大脑”

为大力弘扬科学家精神&#xff0c;激励广大科技工作者践行科技报国、创新为民&#xff0c;争做高水平科技自立自强排头兵&#xff0c;6月6日&#xff0c;中国移动在线营销服务中心&#xff08;以下简称“在线中心”&#xff09;“2024年科技工作者大讲堂暨青年创新创效论坛”于…

Matlab|基于手肘法的kmeans聚类数的精确识别【K-means聚类】

主要内容 在电力系统调度研究过程中&#xff0c;由于全年涉及的风、光和负荷曲线较多&#xff0c;为了分析出典型场景&#xff0c;很多时候就用到聚类算法&#xff0c;而K-means聚类就是常用到聚类算法&#xff0c;但是对于K-means聚类算法&#xff0c;需要自行指定分类数&…

C/C++:指针用法详解

C/C&#xff1a;指针 指针概念 指针变量也是一个变量 指针存放的内容是一个地址&#xff0c;该地址指向一块内存空间 指针是一种数据类型 指针变量定义 内存最小单位&#xff1a;BYTE字节&#xff08;比特&#xff09; 对于内存&#xff0c;每个BYTE都有一个唯一不同的编号…

赶紧转行大模型,预计风口就今年一年,明年市场就饱和了!不是开玩笑

恕我直言&#xff0c;就这几天&#xff0c;各大厂都在裁员&#xff0c;什么开发测试运维都裁&#xff0c;只有大模型是急招人。 你说你不知道大模型是什么&#xff1f;那可太对了&#xff0c;你不知道说明别人也不知道&#xff0c;就是要趁只有业内部分人知道的时候入局&#…

String常用方法详解

auth&#xff1a;别晃我的可乐 date&#xff1a;2024年06月16日 比较大小 equals(Object obj): 用于比较字符串内容是否相等。compareTo(String anotherString): 按字典顺序比较两个字符串。 String str1 "hello"; String str2 "world";boolean isEqual …

配置Linux DNS服务器作为自己的windows 的 DNS服务器和 配置遇到的问题

安装DNS 库 和 DNS工具&#xff1a; # bind 是用于创建 dns服务的&#xff0c; bind-utils是用于测试DNS服务的工具 yum -y install bind bind-utils配置主配置文件&#xff1a; # 下载好后就已经有DNS服务&#xff0c;但是需要你自己去配置DNS服务信息# 配置主配置文件 [rootl…