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

Redis Cluster Gossip Protocol: PING, PONG, MEET

返回目录

PING / PONG / MEET 的发送

过程

  1. 计算freshNodes。freshNodes表示在消息中能携带的,在cluster节点字典中的节点总数,但需要减去myself和对端节点,因为myself的信息会存储在消息头中。实际上,并非所有在cluster节点字典中的节点都需要带出去,对于那些处于handshake,disconnected状态的节点是不用考虑的。
    freshNodes = size(cluster nodes) - 2
  2. 计算wanted。wanted表示准备在消息中携带的gossip数。个数不能少于3,不能超过freshNodes。
    wanted = floor(size(cluster nodes) / 10)
    wanted = max(wanted, 3)
    wanted = min(wanted, freshNodes)
  3. 获取pfailWanted。pfailWanted表示处于PFAIL状态的节点数。
  4. 如果当前link不是inbound,而且消息类型为PING,则更新对端实体的pingSent(发送ping的时间)为当前时间。
  5. 构建消息头部
  6. 计算maxIterations。maxIterations表示在遍历cluster节点字典时的最大遍历次数。
    maxIterations = wanted * 3
  7. 编写gossip
gossipCount = 0
while freshNodes > 0  gossipCount < wanted && maxIterations:从cluster节点字典中随机抽取一个node /* 注意:是随机地抽取 */if node是myself || 处于PFAIL状态: /* myself会在消息头,PFAIL会在最后追加 */continueif (node处于handshake或者NOADDR(地址不可知)) ||(node还没有outbound link && node没有slots):freshNodes--	/* 节省CPU */continueif node已被添加到gossip:continue把node添加到gossipfreshNodes--gossipCount++
  1. 如果pfailCount > 0,则把PFAIL节点追加到gossip
while cluster节点字典还没遍历完 and pfailWanted > 0:获取一个nodeif (node处于handshake或者NOADDR) || node并非PFAIL:	/* 只追加PFAIL的节点 */continuegossipCount++pfailWanted--
  1. 如果配置了cluster-announce-hostname,则
    • 给消息的mflags添加EXT_DATA标记,表示消息附带extension
    • 把cluster-announce-hostname写入pingExtension
    • 把pingExtension追加到消息末尾
  2. 计算消息的总长度
  3. 设置消息的count = gossipCount
  4. 设置消息的extensions = extension的个数
  5. 设置消息的totalLen = 上面计算出的总长度
  6. 发送消息
    - PING和MEET通过outbound link发送
    - PONG通过inbound link发送
gossip内容

每个要加入到gossip中的节点都会在其中生成一个对应条目,包含的信息:

  1. 节点ID
  2. 最近一次ping此节点的时间(如果已经收到此节点的PONG,会重置为0)
  3. 最近一次收到此节点PONG的时间
  4. 节点IP
  5. 节点的port,pport,cport
  6. 节点的flags

PING / PONG / MEET的接收处理

过程

第1 ~ 3步是涵盖所有类型的消息。

  1. 合法性检查
    • 消息类型(type)的检查
    • 消息长度检查。有的消息会携带gossip,有的会附带extension,所以消息的总长度是可变的,需要结合消息头部的元数据和消息的内容进行检查。
  2. 根据link和消息头,从cluster节点字典中查找实体sender
if link关联了node && node不是处于handshake:sender = node
else:sender = 根据消息头中的sender,从cluster节点字典中查找实体if sender存在 && link没有关联node:/* inbound link在创建时还不知道节点的真实ID,所以会找不到sender,因此要到达这里才能关联上sender */把link设置为sender的inbound link/* 关联后,下次就可以从link获取sender,而不需要再从cluster节点字典查找了 */把sender关联到link
  1. 通用处理,适用于所有消息类型
if sender存在:/* 更新数据接收时间,以免因为sender一直在发送数据而误认为它timeout */sender的dataReceived = 当前时间if sender没有处于handshake:/* 更新currentEpoch和configEpoch */if 消息头的currentEpoch > server的currentEpoch:server的currentEpoch = 消息头的currentEpochif 消息头的configEpoch > sender的configEpoch:sender的configEpoch = 消息头的configEpoch更新sender的复制偏移和相应时间if server正在做manual failover && myself是sender的slave &&消息头的mflags包含PAUSED && server的mf_master_offset == -1:更新server的mf_server_offset = sender的复制偏移
  1. 处理PING,MEET消息
if 消息类型是PING或者MEET:/* 获取myself的IP */if (消息类型是MEET || myself还没有IP) && 没有配置cluster-announce-ip:myself的IP = 从socket中获取自己的IP/* 在cluster节点字典中创建实体 */if sender不存在 && 消息类型为MEET:为sender创建node实体,生成随机ID/* 获取sender的IP和ports */if 消息头的myip不为全0:node的ip = myipelse:node的ip = 从socket获取对端的ip把消息头的port,pport, cport复制到node把node加入cluster节点字典/* 解析gossip */if sender不存在 && 消息类型为MEET:处理消息的gossip回复PONG消息给对端节点
  1. 处理PING,PONG,MEET消息
if 消息类型是PING或者PONG或者MEET:node = link关联的nodeif link是outbound:if node处于handshake:/* sender已经代表了对端节点,接下去node的ID也会被更新成跟sender的一样,同一个ID不能对应2个实体,所以需要把node删掉 */if sender存在: 检查ip和ports的变化,更新sender /* Point-1 */从cluster节点字典中删除node /* 会释放node的inbound和outbound link*/return更新node的ID = 消息头的sender /* 随机ID -> 真实的ID */从node中删除HANDSHAKE标记 /* 表示handshake过程结束 */根据消息头的flags,把node设置为master或slaveelse if node的ID != 消息头的sender:/* 可能对端变更了ID,也可能是由于网络的变化连错了节点 */标记node为NOADDR重置node的ip,port,pport,cport为0释放linkreturn/* 检查NOFAILOVER,更新sender */if sender存在:	/* 我们假定对端发来的信息是最新的,所以直接更新.NOFAILOVER对应的是cluster-replica-no-failover配置项 */if 消息头的flags带了NOFAILOVER:标记sender为NOFAILOVERelse:移除sender的NOFAILOVER/* 如果ip和各个端口发生了变化,则需要更新 */if sender存在 && 消息类型为PING && sender没有处于handshake:检查ip和ports的变化,更新sender/* 如果我们收到了PONG,需要清除PFAIL和FAIL状态 */if link是outbound && 消息类型为PONG:更新node的pongReceived = 当前时间重置node的pingSent = 0 if node处于PFAIL:清除PFAIL状态	/* 简单地移除PFAIL标记	*/else if node处于FAIL:清除node的FAIL状态 /* Point-2 *//* 检查是否发生了角色切换: slave -> master or master -> slave */if sender存在:if 消息头的slaveof为全0: /* 对端现在是master */把sender转换为master	 /* Point-3: 如果sender原本就是master,就无需转换 */else:	/* 对端现在是slave */if sender需要从master变为slave:把sender转换为slave	/* Point-4 */if sender的master发生了变化: 把sender从旧master迁移到新master /* Point-5 *//* 更新slots */if sender是master && sender的slots跟消息头的myslots存在不同:重新绑定消息头的myslots到sender /* Point-6 *//* 如果sender声称slot属于它,但事实并非如此,则需要通知sender */if sender存在 && sender的slots跟消息头的myslots存在不同:查找消息头的myslots中是否存在这样一个slot:1. 在myself看来,它不属于sender2. 它的configEpoch > 消息头的configEpochif 存在这样的slot:发送UPDATE消息给sender/* 解决configEpoch冲突 */		if sender是master && myself也是master &&消息头的configEpoch == myself的configEpoch:if myself的ID < sender的ID:	/* 字符串比较 */myself的configEpoch = (++server的currentEpoch)保存配置/* 处理gossip */		if sender存在:处理消息中的gossip  /* Point-7 *//* 处理消息中的pingExtension */if 消息头的extensions > 0: /* 消息带有extension *//* 当前只有一种extension: pingExtension */sender的hostname = pingExtension中的hostname 

Points 解释

Point-1:检查ip和ports的变化,更新sender
/* 检查是否使用同一条连接,若是,则不可能有变化 */
if link跟sender的link一样:	return	
/* 检查IP和ports是否有变化 */
if sender的ports跟消息头的ports相同 &&: /* port, pport, cport */sender的ip跟消息头的myip相同: /* 如果myip为全0,则使用socket上的对端IP */return
更新sender的IP和ports
if sender的link存在: /* IP和ports变更了,需要重新建立连接 */释放掉sender的link	/* 释放后会使用新的IP和port自动重连 */
if sender是myself的master:更新server复制时使用的IP和port,重新开启复制
Point-2:清除node的FAIL状态
/* 对于slave节点,只要连接上,都会认为它恢复了;对于没有slot的master节点,只要连接上,就不需要在看它是否fail了足够长的时间 */
if sender是slave || sender没有slots:清除它的FAIL标记/* 对于master节点,如果它fail的时间足够长,而且还有slots属于它,说明它没有被failover,现在连接上了,则可以认为它恢复了 */
if sender是master && sender有slots &&当前时间 - sender的failTime > 2 * cluster-node-timeout:清除它的FAIL标记
Point-3:把sender转换为master
解除sender和oldMaster之间的关联
if oldMaster没有其他slave:清除oldMaster的MIGRATE_TO标记 
if sender != myself:添加MIGRATE_TO标记到sender
设置sender为master
Point-4:把sender转换为slave
把原本属于sender的slots,全部设置为没有owner
清除sender的MIGRATE_TO标记
设置sender为slave
Point-5:把sender从原本的master迁移到新的master
解除sender和oldMaster之间的关联
if oldMaster没有其他slave:清除oldMaster的MIGRATE_TO标记
建立sender和newMaster之间的关联
添加MIGRATE_TO标记到newMaster
Point-6:重新绑定消息头的myslots到sender
if sender == myself:  /* 不需要对自己进行更新 */return
if myself是master:currentMaster = myself
elsecurrentMaster = myself的master
newMaster = null
migratedOurSlots = 0
遍历消息头中的myslots:跳过那些已经属于sender的slot跳过处于importing状态的slot/* 如果slot没有owner,或者sender声称slot属于它 */if slot没有owner || slot的configEpoch < 消息头的configEpoch:if slot的owner == myself && slot上有key: /* slot是myself的,需要标识它是dirty */记录slot到dirtySlotsif slot的owner == currentMaster:/* 存在slot从currentMaster迁移到sender */newMaster = sender++migratedOurSlots /* 记录迁移的slot数 */把slot从旧的owner删除把slot添加到senderif newMaster != null &&		/* 存在slot从currentMaster迁移到sender */currentMaster没有slot了 && (cluster-allow-replica-migration ||	/* 配置了允许副本迁移 */消息头的myslots数量 == migratedOurSlots): /* myslots全部从currentMaster迁移到sender *//* 如果myself是master,当前没有slot,说明myself被failover,它需要成为newMaster的副本;如果myself是slave,它的master没有slot,说明它当前没有slot可以复制,myself需要成为myslots的副本 *//* sender成为myself的master */if myself是master:清除它的MIGRATE_TO标记设置它为slave清除它的那些处于importing和migrating的slotselse:解除它跟oldMaster之间的关联把myself的master设置为sender更新server复制时使用的IP和port,重新开启复制重置server的manual failover状态
else if dirtySlots数量 > 0:/* 消息表明这些slots跟我们没有关系了,但是我们还有key在上面,为了维持key和slot之间的一致性,需要清除掉这些key */遍历dirtySlots,删除每个slot上所有的key
Point-7:处理消息中的gossip
遍历消息中的每个gossip:根据gossip的nodename,从cluster节点字典中查找nodeif node存在:  /* 找到关联这个gossip的node */if sender是master && node != myself:if gossip表示node处于PFAIL或FAIL: /* 对端节点连接不上node */把sender发起的failureReport添加到node /* 如果已经存在,则更新时间 *//* 检查node是否需要标记为FAIL */neededQuorum = clusterSize / 2 + 1 /* 计算仲裁所需要的票数 */if node处于PFAIL状态 && /* 我们无法连接上它 */node没有处于FAIL状态: /* 没FAIL才需要处理 */清除那些已经失效的failureReport /* 时间超过了 2 * cluster-node-timeout */failures = 有效的failureReport数if myself是master:	/* 如果我们是master,我们也需要投票 */++failuresif falures >= neededQuorum: /* 多数通过, FAIL成立 */把node从PFAIL转换成FAIL,并设置failTime为当前时间广播FAIL消息到其他节点,迫使它们标记此node已FAILelse: /* sender能连接上node */从node上删除sender发起的failureReport /* 如果有的话 */清除那些已经失效的failureReport/* 检查是否需要更新node的pongReceived */if gossip表示node没有处于PFAIL或FAIL && /* 在对端节点看来,node没有PFAIL或FAIL */node的pingSent == 0 &&	/* 我们没有处于等待回复的ping */node上没有failureReport:	 /* 在我们看来,node没有FAIL */if gossip的pongReceived > node的pongReceived &&	/* 对端节点收到node的PONG比我们更新 */gossip的pongReceived < 当前时间 + 500ms:	/* 各个节点的时钟可能不同步,500ms是容错 */		node的pongReceived = gossip的pongReceived/* 检查IP和ports是否发生了变化 */	if node原本处于PFAIL或FAIL &&	/* 我们连接不上它 */但对端节点能连接上node &&	我们和对端节点拿到的node IP,port和cport不一样:释放掉我们对node的link更新node上的IP和ports,等待下次自动重连else:	/* node在我们这还不存在 */		/* 可以通过"cluster forget"命令把node从server的cluster节点字典中删掉,为了避免node的地址和端口被重用,错误连接到别的cluster,于是需要把删掉的node加入到server的黑名单中 */if sender存在 && gossip表示node是有地址的 &&gossip的nodename不在我们的黑名单中:创建node实体填入gossip的IP和ports加入cluster节点字典

相关文章:

Redis Cluster Gossip Protocol: PING, PONG, MEET

返回目录 PING / PONG / MEET 的发送 过程 计算freshNodes。freshNodes表示在消息中能携带的&#xff0c;在cluster节点字典中的节点总数&#xff0c;但需要减去myself和对端节点&#xff0c;因为myself的信息会存储在消息头中。实际上&#xff0c;并非所有在cluster节点字典…...

httpserver 下载服务器demo 以及libevent版本的 httpserver

实现效果如下&#xff1a; 图片可以直接显示 cpp h 这些可以直接显示 其他的 则是提示是否要下载 单线程 还有bug 代码如下 先放上来 #include "httpserver.h" #include "stdio.h" #include <stdlib.h> #include <arpa/inet.h> #include…...

构建强大的RESTful API:@RestController与@Controller的对比与应用

构建强大的RESTful API&#xff1a;RestController与Controller的对比与应用 前言什么是RESTful APIRestController&#xff0c;Controller&#xff0c;ResponseBody1. Controller注解&#xff1a;2. RestController注解&#xff1a;3. ResponseBody注解&#xff1a; 示例非thy…...

【Java-LangChain:使用 ChatGPT API 搭建系统-10】评估(下)-当不存在一个简单的正确答案时

第十章&#xff0c;评估&#xff08;下&#xff09;-当不存在一个简单的正确答案时 在上一章中&#xff0c;了解了如何评估 LLM 模型在 有明确正确答案 的情况下的输出&#xff0c;我们可以编写一个函数来判断 LLM 输出是否正确地分类并列出产品。 然而&#xff0c;如果 LLM …...

【微服务的集成测试】python实现-附ChatGPT解析

1.题目 微服务的集成测试 知识点:深搜 时间限制: 1s 空间限制: 256MB 限定语言:不限 题目描述: 现在有n个容器服务,服务的启动可能有一定的依赖性 (有些服务启动没有依赖)其次服务自身启动加载会消耗一些时间。 给你一个 nxn 的二维矩阵 useTime,其中 useTime[i][i]=10 表示…...

Mesa新版来袭

Mesa 17.1.6 发布了&#xff0c;Mesa 是一个三维&#xff08;3D&#xff09;图形库的开源集合&#xff0c;其主要目标是在 Linux / UNIX 操作系统下实现各种 API&#xff08;应用程序编程接口&#xff09;和 OpenGL 规范。 它面向 3D 计算机图形&#xff0c;硬件加速 3D 渲染和…...

基于 SpringBoot 2.7.x 使用最新的 Elasticsearch Java API Client 之 ElasticsearchClient

1. 从 RestHighLevelClient 到 ElasticsearchClient 从 Java Rest Client 7.15.0 版本开始&#xff0c;Elasticsearch 官方决定将 RestHighLevelClient 标记为废弃的&#xff0c;并推荐使用新的 Java API Client&#xff0c;即 ElasticsearchClient. 为什么要将 RestHighLevelC…...

辅助驾驶功能开发-功能对标篇(15)-NOA领航辅助系统-吉利

1.横向对标参数 厂商吉利车型FX11/EX11/DCY11/G636上市时间2022Q4方案6V5R+1DMS摄像头前视摄像头1*(8M)侧视摄像头/后视摄像头1环视摄像头4DMS摄像头1雷达毫米波雷达54D毫米波雷达/超声波雷达12激光雷达/域控供应商福瑞泰克辅助驾驶软件供应商福瑞泰克高精度地图百度芯片TDA4 T…...

javascript: Sorting Algorithms

// Sorting Algorithms int JavaScript https://www.geeksforgeeks.org/sorting-algorithms/ /** * file Sort.js * 1. Bubble Sort冒泡排序法 * param arry * param nszie */ function BubbleSort(arry, nszie) {var i, j, temp;var swapped;for (i 0; i < nszie - 1; i)…...

嵌入式Linux应用开发-驱动大全-同步与互斥④

嵌入式Linux应用开发-驱动大全-同步与互斥④ 第一章 同步与互斥④1.5 自旋锁spinlock的实现1.5.1 自旋锁的内核结构体1.5.2 spinlock在UP系统中的实现1.5.3 spinlock在SMP系统中的实现 1.6 信号量semaphore的实现1.6.1 semaphore的内核结构体1.6.2 down函数的实现1.6.3 up函数的…...

2023年【高压电工】证考试及高压电工复审模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 高压电工证考试根据新高压电工考试大纲要求&#xff0c;安全生产模拟考试一点通将高压电工模拟考试试题进行汇编&#xff0c;组成一套高压电工全真模拟考试试题&#xff0c;学员可通过高压电工复审模拟考试全真模拟&a…...

C/C++学习 -- 分组密算法(3DES算法)

1. 3DES算法概述 3DES&#xff08;Triple Data Encryption Standard&#xff09;&#xff0c;又称为TDEA&#xff08;Triple Data Encryption Algorithm&#xff09;&#xff0c;是一种对称加密算法&#xff0c;是DES&#xff08;Data Encryption Standard&#xff09;的加强版…...

C/C++面试题总结

1.new与malloc的区别 new操作符从自由存储区上为对象动态分配内存空间&#xff0c;而malloc函数从堆上动态分配内存。 使用new操作符申请内存分配时无须指定内存块的大小&#xff0c;而malloc则需要显式地指出所需内存的尺寸。 int *p new int; delete p;//一定要配对使用n…...

Java下正面解除警告Unchecked cast: ‘java.lang.Object‘ to ‘java.util.ArrayList‘

就是我在反序列化时&#xff0c;遇到这样一个警告&#xff1a; Unchecked cast: java.lang.Object to java.util.ArrayList<com.work1.Student>然后我去网上查&#xff0c;有些人说用SuppressWarnings(“unchecked”)去忽略警告&#xff0c;但是我觉得作为一名合格的程序…...

图像处理与计算机视觉--第四章-图像滤波与增强-第二部分

目录 1.图像噪声化处理与卷积平滑 2.图像傅里叶快速变换处理 3.图像腐蚀和膨胀处理 4 图像灰度调整处理 5.图像抖动处理算法 学习计算机视觉方向的几条经验: 1.学习计算机视觉一定不能操之过急&#xff0c;不然往往事倍功半&#xff01; 2.静下心来&#xff0c;理解每一个…...

[前端基础]typescript安装以及类型拓展

&#xff08;0&#xff09;写在前面&#xff1a; 作者之前都是在写js&#xff0c;所以这里介绍ts肯定是不能从头开始介绍了&#xff0c;主要在js的基础上介绍ts关于类型的几个特性&#xff0c;以及ts的安装还有配置问题 &#xff08;1&#xff09;ts和js是什么关系 通俗点来…...

网络参考资料汇总(1)

将这段时间参考的各路大佬的资料加以汇总分类&#xff1a; &#xff08;1&#xff09;FFmpeg: 基于FFmpeg进行rtsp推流及拉流&#xff08;详细教程&#xff09; Linux 编译安装 FFmpeg 步骤&#xff08;带ffplay&#xff09; Jetson 环境安装(三):jetson nano配置ffmpeg和ngin…...

Remove和RemoveLast用法

LeetCode 46 全排列 先贴代码 class Solution {List<List<Integer>> result new ArrayList<>();List<Integer> temp new ArrayList<>();public List<List<Integer>> permute(int[] nums) {dfs(nums, 0);return result;}public v…...

(一) 使用 Hugo 搭建个人博客保姆级教程(上篇)

手把手教你如何从0开始构建一个静态网站&#xff0c;这不需要有太多的编程和开发经验和时间投入&#xff0c;也基本不需要多少成本&#xff08;除了个性化域名&#xff09;&#xff0c;使用GitHub和Hugo模板即可快速构建和上线一个网站。 目标读者 本文档适用于以下用户&…...

数据结构之栈

栈的模拟实现 1.栈的概念2.栈的方法3.栈的模拟实现(代码)3.1 接口My_Stack3.2 StackList3.3 异常类StackException3.4 测试类Test 1.栈的概念 2.栈的方法 3.栈的模拟实现(代码) 3.1 接口My_Stack 3.2 StackList 3.3 异常类StackException 3.4 测试类Test...

通过Wrangler CLI在worker中创建数据库和表

官方使用文档&#xff1a;Getting started Cloudflare D1 docs 创建数据库 在命令行中执行完成之后&#xff0c;会在本地和远程创建数据库&#xff1a; npx wranglerlatest d1 create prod-d1-tutorial 在cf中就可以看到数据库&#xff1a; 现在&#xff0c;您的Cloudfla…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

实现弹窗随键盘上移居中

实现弹窗随键盘上移的核心思路 在Android中&#xff0c;可以通过监听键盘的显示和隐藏事件&#xff0c;动态调整弹窗的位置。关键点在于获取键盘高度&#xff0c;并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Xcode 16 集成 cocoapods 报错

基于 Xcode 16 新建工程项目&#xff0c;集成 cocoapods 执行 pod init 报错 ### Error RuntimeError - PBXGroup attempted to initialize an object with unknown ISA PBXFileSystemSynchronizedRootGroup from attributes: {"isa">"PBXFileSystemSynchro…...

ArcGIS Pro+ArcGIS给你的地图加上北回归线!

今天来看ArcGIS Pro和ArcGIS中如何给制作的中国地图或者其他大范围地图加上北回归线。 我们将在ArcGIS Pro和ArcGIS中一同介绍。 1 ArcGIS Pro中设置北回归线 1、在ArcGIS Pro中初步设置好经纬格网等&#xff0c;设置经线、纬线都以10间隔显示。 2、需要插入背会归线&#xf…...

【技巧】dify前端源代码修改第一弹-增加tab页

回到目录 【技巧】dify前端源代码修改第一弹-增加tab页 尝试修改dify的前端源代码&#xff0c;在知识库增加一个tab页"HELLO WORLD"&#xff0c;完成后的效果如下 [gif01] 1. 前端代码进入调试模式 参考 【部署】win10的wsl环境下启动dify的web前端服务 启动调试…...

TI德州仪器TPS3103K33DBVR低功耗电压监控器IC电源管理芯片详细解析

1. 基本介绍 TPS3103K33DBVR 是 德州仪器&#xff08;Texas Instruments, TI&#xff09; 推出的一款 低功耗电压监控器&#xff08;Supervisor IC&#xff09;&#xff0c;属于 电源管理芯片&#xff08;PMIC&#xff09; 类别&#xff0c;主要用于 系统复位和电压监测。 2. …...