当前位置: 首页 > news >正文

kafka动态认证 自定义认证 安全认证-亲测成功

kafka动态认证 自定义认证 安全认证-亲测成功

背景

Kafka默认是没有安全机制的,一直在裸奔。用户认证功能,是一个成熟组件不可或缺的功能。在0.9版本以前kafka是没有用户认证模块的(或者说只有SSL),好在kafka0.9版本以后逐渐发布了多种用户认证功能,弥补了这一缺陷(这里仅介绍SASL),认证机制是SASL/PLAIN。

kafka下载安装

我这里用windows做的测试,部署到Linux上也是一样

官方下载地址:https://kafka.apache.org/downloads

我这里下载的kafka版本是:kafka_2.12-3.5.0.tgz

直接解压,如下图

在这里插入图片描述

启动zookeeper

这里的zookeeper配置其实没有做任何修改,zookeeper这里不做认证控制。

zookeeper配置文件在kafka_2.12-3.5.0\config\zookeeper.properties下,不用做任何修改

# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
# 
#    http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# the directory where the snapshot is stored.
dataDir=D:\kafka_2.12-3.5.0\zookeeper# the port at which the clients will connect
clientPort=2181
# disable the per-ip limit on the number of connections since this is a non-production config
maxClientCnxns=0
# Disable the adminserver by default to avoid port conflicts.
# Set the port to something non-conflicting if choosing to enable this
admin.enableServer=false
# admin.serverPort=8080#authProvider.1=org.apache.zookeeper.server.auth.SASLAuthenticationProvider
#requireClientAuthScheme=sasl
#jaasLoginRenew=3600000

进入kafka主目录,打开cmd

#启动zookeeper
bin\windows\zookeeper-server-start.bat  config\zookeeper.properties

在这里插入图片描述

zookeeper-server-start.bat 启动脚本

@echo off
rem Licensed to the Apache Software Foundation (ASF) under one or more
rem contributor license agreements.  See the NOTICE file distributed with
rem this work for additional information regarding copyright ownership.
rem The ASF licenses this file to You under the Apache License, Version 2.0
rem (the "License"); you may not use this file except in compliance with
rem the License.  You may obtain a copy of the License at
rem
rem     http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.IF [%1] EQU [] (echo USAGE: %0 zookeeper.propertiesEXIT /B 1
)rem set KAFKA_OPTS=-Djava.security.auth.login.config=D:\kafka_2.12-3.5.0\config\kafka_zookeeper_jaas.conf
SetLocal
IF ["%KAFKA_LOG4J_OPTS%"] EQU [""] (set KAFKA_LOG4J_OPTS=-Dlog4j.configuration=file:%~dp0../../config/log4j.properties)
IF ["%KAFKA_HEAP_OPTS%"] EQU [""] (set KAFKA_HEAP_OPTS=-Xmx512M -Xms512M
)
"%~dp0kafka-run-class.bat" org.apache.zookeeper.server.quorum.QuorumPeerMain %*
EndLocal

在这里插入图片描述

kafka自定义认证配置

kafka的用户认证,是基于java的jaas。所以我们需要先添加jaas服务端的配置文件。

在kafka_2.12-3.5.0\config目录下新建kafka_jaas.conf 配置信息如下:

KafkaServer {org.apache.kafka.common.security.plain.PlainLoginModule requiredusername="admin"password="admin-liang"user_admin="admin-123456"user_liang="liang-123456";
};

注意最后一个属性后面需要加分号!配置是不难理解的,第一行指定PlainLoginModule,算是声明这是一个SASL/PLAIN的认证类型,如果是其他的,那么就需要reqired其他的类。username和password则是用于集群内部broker的认证用的。

这里会让人疑惑的,应该是user_admin和user_liang这两个属性了。这个其实是用来定义用户名和密码的,形式是这样:user_userName=password。所以这里其实是定义了用户admin和用户liang对应的密码。

这一点可以在源码的PlainServerCallbackHandler类中找到对应的信息,kafka源码中显示,对用户认证的时候,就会到jaas配置文件中,通过user_username属性获取对应username用户的密码,再进行校验。当然这样也导致了该配置文件只有重启才会生效,即无法动态添加用户。

写完配置后,需要在kafka的配置中添加jaas文件的路径。在kafka_2.12-3.5.0/bin/kafka-run-class.sh中,找到下面的配置,修改KAFKA_OPTS到配置信息。如下:

rem Generic jvm settings you want to add
IF ["%KAFKA_OPTS%"] EQU [""] (set KAFKA_OPTS=""
)

将上述到KAFKA_OPTS修改为:

rem Generic jvm settings you want to add
IF ["%KAFKA_OPTS%"] EQU [""] (set KAFKA_OPTS="-Djava.security.auth.login.config=D:\kafka_2.12-3.5.0\config\kafka_jaas.conf"
)

修改Kafka配置文件

配置文件在kafka_2.12-3.5.0\config\server.properties 主要增加如下配置

sasl.enabled.mechanisms = PLAIN
sasl.mechanism.inter.broker.protocol = PLAIN
security.inter.broker.protocol = SASL_PLAINTEXT
listeners = SASL_PLAINTEXT://localhost:9092

其中SASL_PLAINTEXT的意思,是明文传输的意思,如果是SSL,那么应该是SASL_SSL。

这样就算是配置好kafka broker了,接下来启动kafka,观察输出日志,没有错误一般就没问题了。

进入kafka主目录,另外打开一个cmd

#启动kafka
bin\windows\kafka-server-start.bat config\server.properties

在这里插入图片描述
在这里插入图片描述

使用Kafka客户端工具Kafka Tool连接

此时就可以根据上面配置的用户admin和用户liang和相应的密码去连接了

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

其他用户或错误的密码连接就会提示没有权限,用户或密码错误
在这里插入图片描述

动态认证

以上的配置方案除了没有使用SSL加密之外,还存在一个严重的缺陷:用户信息是通过静态配置文件的方式存储的,当对用户信息进行添加、删除和修改的时候都需要重启Kafka集群,而我们知道,作为消息中间件,Kafka的上下游与众多组件相连,重启可能造成数据丢失或重复,Kafka应当尽量避免重启。

如果要动态增加一个用户,得修改kafka_jaas.conf的配置,新增加一个用户,而且还得重启Kafka,这样显然不合适。

解决方案

还好,Kafka允许用户为SASL/PLAIN认证机制提供了自定义的回调函数,如果不希望采用静态配置文件存储用户认证信息的话,只需要编写一个实现了 AuthenticateCallbackHandler 接口的类,然后在配置文件中指明这个类即可,指明的方法为在Kafka配置文件中添加如下内容

listener.name.sasl_plaintext.plain.sasl.server.callback.handler.class=com.liang.kafka.auth.handler.MyPlainServerCallbackHandler

引入相关的maven依赖包,pom添加如下依赖包

        <dependency><groupId>org.apache.kafka</groupId><artifactId>kafka_2.13</artifactId><version>2.8.1</version></dependency><dependency><groupId>cn.hutool</groupId><artifactId>hutool-cache</artifactId><version>5.7.21</version></dependency>

动态认证的完整代码如下

package com.liang.kafka.auth.handler;import com.alibaba.druid.pool.DruidDataSource;
import com.liang.kafka.auth.util.DataSourceUtil;
import com.liang.kafka.auth.util.PasswordUtil;
import org.apache.kafka.common.KafkaException;
import org.apache.kafka.common.security.JaasContext;
import org.apache.kafka.common.security.auth.AuthenticateCallbackHandler;
import org.apache.kafka.common.security.plain.PlainAuthenticateCallback;
import org.apache.kafka.common.security.plain.PlainLoginModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.AppConfigurationEntry;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;import static com.liang.kafka.auth.constants.Constants.*;/***  kafka自定义认证 sasl/plain二次开发*  liang*/
public class MyPlainServerCallbackHandler implements AuthenticateCallbackHandler  {private static final Logger logger = LoggerFactory.getLogger(MyPlainServerCallbackHandler.class);/*** 数据源*/private DruidDataSource dataSource = null;/*** 是否开启数据库验证开关*/private boolean enableDbAuth;private static final String JAAS_USER_PREFIX = "user_";private List<AppConfigurationEntry> jaasConfigEntries;@Overridepublic void configure(Map<String, ?> configs, String mechanism, List<AppConfigurationEntry> jaasConfigEntries) {//jaas配置信息,初始化一次,这就是为什么plain无法添加用户this.jaasConfigEntries = jaasConfigEntries;logger.info("==============configs:{}", JSON.toJSONString(configs));Object endbAuthObject = configs.get(ENABLE_DB_AUTH);if (Objects.isNull(endbAuthObject)) {logger.error("==============缺少开关配置 enable_db_auth!");enableDbAuth = Boolean.FALSE;return;}enableDbAuth = TRUE.equalsIgnoreCase(endbAuthObject.toString());if (!enableDbAuth) {return;}dataSource = DataSourceUtil.getInstance(configs);}//核心类,获取用户密码后,调用authenticate方法@Overridepublic void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {String username = null;for (Callback callback: callbacks) {if (callback instanceof NameCallback)username = ((NameCallback) callback).getDefaultName();else if (callback instanceof PlainAuthenticateCallback) {PlainAuthenticateCallback plainCallback = (PlainAuthenticateCallback) callback;boolean authenticated = authenticate(username, plainCallback.password());plainCallback.authenticated(authenticated);logger.info("===============认证 username:{},result:{}", username, authenticated);} elsethrow new UnsupportedCallbackException(callback);}}//用户密码是通过获取jaas文件的属性,属性名就是JAAS_USER_PREFIX变量当前缀+usernameprotected boolean authenticate(String username, char[] password) throws IOException {if (username == null || password == null) {logger.error("===========用户名或密码为空!");return false;} else {//先读取配置文件里的用户验证String expectedPassword = JaasContext.configEntryOption(jaasConfigEntries,JAAS_USER_PREFIX + username,PlainLoginModule.class.getName());logger.info("===============读取密码 username:{},pwd:{}", username, expectedPassword);boolean jaasUserBool = expectedPassword != null && Arrays.equals(password, expectedPassword.toCharArray());if (jaasUserBool) {return true;}//是否开启数据库验证if (enableDbAuth) {return dbAuthenticate(username, password);}return false;}}protected boolean dbAuthenticate(String usernameInfo, char[] passwordCharArray) throws IOException {String password = new String(passwordCharArray);logger.info("=====================begin dbAuthenticate usernameInfo:{},password:{}", usernameInfo, password);String username = usernameInfo;String userQuery = "select\n" +" u.username, u.password\n" +" from u_user u \n" +" where u.state='1' and u.username=?";Connection conn = null;try {conn = dataSource.getConnection();PreparedStatement statement = conn.prepareStatement(userQuery);statement.setString(1, username);ResultSet resultSet = statement.executeQuery();if (resultSet.next()) {String dbPassword = resultSet.getString("password");Boolean bl = PasswordUtil.matches(password, dbPassword);if (Boolean.TRUE.equals(bl)) {logger.info("=====================密码验证成功username:{}", username);} else {logger.error("=====================密码验证失败username:{}", usernameInfo);}return bl;} else {logger.error("=====================认证失败,username:{} 没有找到", usernameInfo);return false;}} catch (Exception e) {logger.error("=====================数据库查询用户异常{}", e);throw new RuntimeException(e);} finally {if (conn != null) {try {conn.close();} catch (SQLException e) {throw new RuntimeException(e);}}}}@Overridepublic void close() throws KafkaException {if (dataSource != null) {dataSource.close();}}}

获取数据源代码

package com.liang.kafka.auth.util;import com.alibaba.druid.pool.DruidDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import java.util.Map;
import java.util.Properties;/*** @author liang* @desc 获取数据源*/
public class DataSourceUtil {private static final Logger LOG = LoggerFactory.getLogger(DataSourceUtil.class);/*** 保证 instance 在所有线程中同步*/private static volatile DruidDataSource dataSource = null;public static synchronized DruidDataSource getInstance(Map<String, ?> configs) {if (dataSource == null || dataSource.isClosed()) {dataSource = initDataSource(configs);}return dataSource;}private static final DruidDataSource initDataSource(final Map<String, ?> configs) {Properties properties = new Properties();for (Map.Entry<String, ?> entry : configs.entrySet()) {if (entry.getKey().startsWith("druid.")) {String key = entry.getKey();String value = (String) entry.getValue();LOG.info("datasource connection config: {}:{}", key, value);properties.setProperty(key, value);}}dataSource = new DruidDataSource();dataSource.configFromPropety(properties);return dataSource;}}

Kafka配置文件中添加数据源的相关配置

enable_db_auth = true
listener.name.sasl_plaintext.plain.sasl.server.callback.handler.class=com.liang.kafka.auth.handler.MyPlainServerCallbackHandler
druid.name = mysql_db
druid.type = com.alibaba.druid.pool.DruidDataSource
druid.url = jdbc:mysql://127.0.0.1:3306/test?useSSL=FALSE&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=Asia/Shanghai
druid.username = root
druid.password = root
druid.filters = stat
druid.driverClassName = com.mysql.cj.jdbc.Driver
druid.initialSize = 5
druid.minIdle = 2
druid.maxActive = 50
druid.maxWait = 60000
druid.timeBetweenEvictionRunsMillis = 60000
druid.minEvictableIdleTimeMillis = 300000
druid.validationQuery = SELECT 'x'
druid.testWhileIdle = true
druid.testOnBorrow = false
druid.poolPreparedStatements = false
druid.maxPoolPreparedStatementPerConnectionSize = 20

其中:enable_db_auth来控制是否开启动态认证。

编译打成jar包后,需要放到kafka_2.12-3.5.0\libs目录,还使用了相关的依赖包也要放入
在这里插入图片描述

重启Kafka后生效,Kafka的连接认证就会从数据库去查询,想增加,修改,删除用户,直接在数据库表里操作。

参考链接:
https://www.top8488.top/kafka/458.html/
https://zhuanlan.zhihu.com/p/301343840?utm_medium=social&utm_oi=886243404000944128&utm_id=0
https://www.jianshu.com/p/e4c50e4affb8

相关文章:

kafka动态认证 自定义认证 安全认证-亲测成功

kafka动态认证 自定义认证 安全认证-亲测成功 背景 Kafka默认是没有安全机制的&#xff0c;一直在裸奔。用户认证功能&#xff0c;是一个成熟组件不可或缺的功能。在0.9版本以前kafka是没有用户认证模块的&#xff08;或者说只有SSL&#xff09;&#xff0c;好在kafka0.9版本…...

航空航司reese84逆向

reese84逆向 Reese84 是一种用于保护网站防止自动化爬虫抓取的防护机制&#xff0c;尤其是在航空公司网站等需要严格保护数据的平台上广泛使用。这种机制通过复杂的指纹识别和行为分析技术来检测和阻止非人类的互动。例如&#xff0c;Reese84 可以通过分析访问者的浏览器指纹、…...

【HTTP】请求“报头”,Referer 和 Cookie

Referer 描述了当前这个页面是从哪里来的&#xff08;从哪个页面跳转过来的&#xff09; 浏览器中&#xff0c;直接输入 URL/点击收藏夹打开的网页&#xff0c;此时是没有 referer。当你在 sogou 页面进行搜索时&#xff0c;新进入的网页就会有 referer 有一个非常典型的用…...

使用sqoop报错

报错一&#xff1a; java.io.IOException: java.lang.ClassNotFoundException: org.apache.hadoop.hive.conf.HiveConf 这个错误表示在执行与 Hive 相关的操作时&#xff0c;程序无法找 org.apache.hadoop.hive.conf.HiveConf 这个类。这个类是 Hive 的配置类&#xff0c;它用…...

一个简单的基于C语言的HTTP代理服务器的案例

一个简单的基于C语言的HTTP代理服务器的案例。这个代理服务器可以接收客户端的HTTP请求&#xff0c;并将请求转发到目标服务器&#xff0c;然后将服务器的响应返回给客户端。 1. 代理服务器的主要代码 #include <stdio.h> #include <stdlib.h> #include <stri…...

Linux学习-Ansible(二)

基本配置 #主机清单文件 [rootharbor ansible]# cat hostlist [web] 192.168.29.161 192.168.29.162 [es] 192.168.29.171 192.168.29.172 192.168.29.173 #查看所有被管理的主机 [rootharbor ansible]# ansible all --list-hostshosts (5):192.168.29.161192.168.29.162192.1…...

[SDX35]SDX35硬件使用512MB内存,实际只初始化256MB问题分析及解决方案

SDX35 SDX35介绍 SDX35设备是一种多模调制解调器芯片,支持 4G/5G sub-6 技术。它是一个4nm芯片专为实现卓越的性能和能效而设计。它包括一个 1.9 GHz Cortex-A7 应用处理器。 SDX35主要特性 ■ 3GPP Rel. 17 with 5G Reduced Capability (RedCap) support. Backward compati…...

S3C2440中断

一、中断执行的流程 soc中断的执行流程 1、中断源发生中断请求 2、CPU检查该中断是否被屏蔽&#xff0c;以及总中断是否被屏蔽 3、考察中断优先级 4、保护现场 5、执行中断服务函数 6、恢复现场 二、中断初始化 1、设置中断模式&#xff08;INTMOD&#xff09;寄存器(…...

编译成功!QT/6.7.2/Creator编译Windows64 MySQL驱动(MinGW版)

参考 GitHub - thecodemonkey86/qt_mysql_driver: Typical symptom: QMYSQL driver not loaded. Solution: get pre-built Qt SQL driver plug-in required to establish a connection to MySQL / MariaDB using Qt. Download qsqlmysql.dll binaries built from official Qt …...

SQLyou基础用法讲解

文章目录 SQLyog 基础知识讲解 1. 数据定义语言 (DDL)创建数据库创建表修改表删除表 2. 数据操作语言 (DML)插入数据批量插入数据更新数据条件更新删除数据条件删除 3. 数据查询语言 (DQL)查询数据查询所有数据使用排序使用聚合函数分组查询使用 HAVING 子句 4. 事务5. 索引创建…...

Can‘t get Kerberos realm

近期封装Ozone客户端&#xff0c;需要走kerberos登陆&#xff0c;遇到了一个问题&#xff0c;花了很长时间解决。记录一下&#xff0c;跟网上能搜到的解决方案不大一样。 先看有问题的代码 Configuration config new Configuration();ConfigurationUtils.setHadoopConfig(conf…...

[python]从零开始的PySide安装配置教程

一、PySide是什么&#xff1f; PySide 是 Qt for Python 项目的一部分&#xff0c;它提供了与 PyQt 类似的功能&#xff0c;使开发者能够使用 Python 编程语言来构建基于 Qt 的图形用户界面 (GUI) 应用程序。PySide 是由 Qt 公司官方维护的&#xff0c;而 PyQt 则是由第三方开发…...

LeetCode[中等] 74.搜索二维矩阵

给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。…...

overleaf如何下载论文的pdf

用overleaf写完英文论文后&#xff0c;要将论文保存为PDF格式 点击图片中的下载按钮 然后选择一个路径保存论文的PDF格式即可。...

Java 每日一刊(第13期):this super static

“优秀的代码不仅仅是给机器看的&#xff0c;更是给人看的。” 前言 这里是分享 Java 相关内容的专刊&#xff0c;每日一更。 本期将为大家带来以下内容&#xff1a; this 关键字super 关键字static 关键字 this 关键字 this 关键字是 Java 中最常见的关键字之一&#xf…...

关于一些Spring的配置的作用

文章目录 spring.profiles.activejmx.default-domainmain.allow-bean-definition-overridingmain.allow-circular-referencescloud.nacoscloud.nacos.configcloud.nacos.shared-configsmvc.pathmatch.matching-strategy spring:profiles:active: ${config.profile}# include…...

利用Python与Ansible实现高效网络配置管理

利用Python与Ansible实现高效网络配置管理 在当今复杂多变的网络环境中&#xff0c;自动化配置管理工具成为了IT运维团队不可或缺的工具。Python以其强大的编程能力和丰富的库支持&#xff0c;结合Ansible这一流行的自动化运维工具&#xff0c;能够极大地提升网络配置管理的效…...

JDBC技术在不同数据库系统中的兼容性及Java数据库交互技术概览

目录 1. JDBC技术在不同数据库系统中的兼容性 2. 除了JDBC&#xff0c;还有哪些技术可以实现Java与数据库的交互&#xff1f; 3. 结论 在Java应用程序中&#xff0c;数据库交互是一个核心功能。Java Database Connectivity (JDBC) 是实现这一功能的标准技术之一。然而&#…...

双击热备 Electron网页客户端

安装流程&#xff1a; 1.下载node.js安装包进行安装 2.点击Next; 3.勾选&#xff0c;点击Next; 4.选择安装目录 5.选择Online 模式 6.下一步执行安装 。 7.运行cmd,执行命令 path 和 node --version&#xff0c;查看配置路径和版本 8.Goland安装插件node.js 9.配置运行…...

数据中台系统产品原型RP原型Axure高保真交互原型 源文件分享

在数字化时代&#xff0c;数据已经成为企业最宝贵的资产之一。为了更好地管理和利用这些数据&#xff0c;这边为大家整理了一套数据中台Axure高保真原型。这套原型致力于为企业提供全方位的数据服务&#xff0c;助力企业实现数据驱动的创新发展。 下载及预览地址&#xff1a;h…...

代码随想录第43天:图论4(最小生成树、拓扑排序)

一、冗余的边II&#xff08;Kamacoder 109&#xff09; from collections import defaultdict# 并查集 - 查找根节点&#xff08;路径压缩&#xff09; def find(fa, x):if fa[x] ! x:fa[x] find(fa, fa[x])return fa[x]# 并查集 - 合并两个集合&#xff0c;返回是否合并成功 …...

尚硅谷redis7 49-51 redis管道之理论简介

前提redis事务和redis管道有点像&#xff0c;但本质上截然不同 49 redis管道之理论简介 面试题 如何优化频繁命令往返造成的性能瓶颈&#xff1f; redis每秒可以承受8万的写操作和接近10万次以上的读操作。每条命令都发送、处理、返回&#xff0c;能不能批处理一次性搞定呢…...

redis五种数据结构详解(java实现对应的案例)

一、简述 Redis是一款高性能的键值对存储数据库&#xff0c;它支持五种基本数据类型&#xff0c;分别是字符串(String)、列表(List)、哈希(Hash)、集合(Set)、有序集合(Sorted Set)。 二、五种基本数据类型 2.1 字符串(String) String是Redis最基本的类型&#xff0c;一个key对…...

AI大模型学习三十、ubuntu安装comfyui,安装插件,修改返回405 bug,值得一看喔

一、说明 ComfyUI是一个开源的、基于节点的Web应用。它允许用户根据一系列文本提示&#xff08;Prompt&#xff09;生成图像。 ComfyUI使用扩散模型作为基础模型&#xff0c;并结合 ControlNet、Lora和LCM低阶自适应等模型&#xff0c;每个工具都由程序中的一个节点表示 二、开…...

JSONP跨域原理全解析

JSONP&#xff08;JSON with Padding&#xff09;是一种绕过浏览器同源策略限制、实现跨域数据请求的“hack”式方案。其核心原理和流程如下&#xff1a; 同源策略限制 浏览器为了安全&#xff0c;只允许页面从与当前页面相同协议、域名、端口的服务器加载数据。而 <script&…...

DeepSeek智能对话助手项目

目录&#xff1a; 1、效果图2、实现代码3、温度和TopK的作用对比 1、效果图 2、实现代码 # import gradio as gr# def reverse_text(text): # return text[::-1]# demogr.Interface(fnreverse_text,inputs"text",outputs"text")# demo.launch(share&q…...

人工智能AI之机器学习基石系列 第 2 篇:数据为王——机器学习的燃料与预处理

专栏系列&#xff1a;《人工智能AI之机器学习基石》② 高质量的数据是驱动机器学习模型的强大燃料 &#x1f680; 引言&#xff1a;无米之炊与数据的重要性 在上一篇文章《什么是机器学习&#xff1f;——开启智能之门》中&#xff0c;我们一起揭开了机器学习的神秘面纱&…...

Redis分布式缓存核心架构全解析:持久化、高可用与分片实战

一、持久化机制&#xff1a;数据安全双引擎 1.1 RDB与AOF的架构设计 Redis通过RDB&#xff08;快照持久化&#xff09;和AOF&#xff08;日志持久化&#xff09;两大机制实现数据持久化。 • RDB架构&#xff1a;采用COW&#xff08;写时复制&#xff09;技术&#xff0c;主进程…...

深入解析 Flink 中的时间与窗口机制

一、时间类型详解 1. 处理时间 处理时间(Processing Time)是指执行操作算子的本地系统时间,它是 Flink 中最简单、性能最高的时间概念。在处理时间语义下,Flink 直接使用机器的本地时钟来确定时间,无需额外的时间提取与处理逻辑。 以电商订单处理为例,当订单支付成功…...

08SpringBoot高级--自动化配置

目录 Spring Boot Starter 依赖管理解释 一、核心概念 二、工作原理 依赖传递&#xff1a; 自动配置&#xff1a; 版本管理&#xff1a; 三、核心流程 四、常用 Starter 示例 五、自定义 Starter 步骤 创建配置类&#xff1a; 配置属性&#xff1a; 注册自动配置&a…...