【redis】集群详解

redis集群

    • 一、集群的概念
    • 二、数据分片算法
      • 2.1哈希求余算法
      • 2.2一致性哈希算法
      • 2.3哈希槽分区算法
    • 三、集群的搭建
      • 3.1配置docker-compose.yml文件
      • 3.2配置generate.sh脚本文件
      • 3.3构建redis集群
      • 3.4简单测试redis集群
    • 四、故障处理流程
      • 4.1故障判定
      • 4.2故障转移
    • 五、集群扩容

一、集群的概念

虽说哨兵模式提⾼了系统的可⽤性,但是真正⽤来存储数据的还是 master 和 slave 节点。所有的数据都需要存储在单个 master 和 slave 节点中,因此当数据量很⼤,接近超出了 master / slave 所在机器的物理内存,就可能出现严重问题了

Redis 的集群就是在上述的思路之下, 引⼊多组 Master / Slave , 每⼀组 Master / Slave 存储数据全集的⼀部分, 从⽽构成⼀个更⼤的整体, 称为 Redis 集群 (Cluster)

理解分组存储

假定整个数据全集是 1 TB, 引⼊三组 Master / Slave 来存储. 那么每⼀组机器只需要存储整个数据全集的 1/3 即可

在这里插入图片描述

在上述图中, 每组master/slave存储的数据都是不一样的,但是组内的master和slave构成主从复制结构,它们的数据是一样的,每个 slave 都是对应 master 的备份(当 master 挂了, 对应的 slave 会补位成 master)。每一组都可以称为是⼀个 分⽚ (Sharding),如果全量数据进⼀步增加,只要再增加更多的分⽚,即可解决

数据量多了,为什么不用硬盘保存下来呢?

不要忘了硬盘只是存储多了, 但是访问速度是⽐内存慢很多的. 但是事实上, 还是存在很多的应⽤场景, 既希望存储较多的数据, ⼜希望有⾮常⾼的读写速度,比如搜索引擎

二、数据分片算法

Redis cluster 的核⼼思路是⽤多组机器来存数据的每个部分. 那么接下来的核⼼问题就是, 给定⼀个数据 (⼀个具体的 key), 那么这个数据应该存储在哪个分⽚上? 读取的时候⼜应该去哪个分⽚读取? 此时业界主流的有三种算法

2.1哈希求余算法

设有 N 个分⽚, 使⽤ [0, N-1] 这样序号进⾏编号,针对某个给定的 key, 先计算 hash 值, 再把得到的结果 % N, 得到的结果即为分⽚编号

例如:N 为 3,给定 key 为 hello,对 hello 计算 hash 值(⽐如使⽤ md5 算法),得到的结果为 bc4b2a76b9719d91,再把这个结果 % 3, 结果为 0, 那么就把 hello 这个 key 放到 0 号分⽚上. 当然, 实际⼯作中涉及到的系统, 计算 hash 的⽅式不⼀定是 md5, 但是思想是⼀致的

补充:md5算法就是将不同顺序组合而成的字符串转换成唯一的整数。

在这里插入图片描述

后续如果要取某个 key 的记录, 也是针对 key 计算 hash , 再对 N 求余, 就可以找到对应的分⽚编号了

哈希求余算法的优点:简单⾼效, 数据分配均匀

哈希求余算法的缺点: ⼀旦需要进⾏扩容, N 改变了,原有的映射规则被破坏,就需要让节点之间的数据相互传输,重新排列,以满⾜新的映射规则,此时需要搬运的数据量是⽐较多的, 开销较⼤

例如:N 为 3 的时候,[100, 120] 这 21 个 hash 值的分布 (此处假定计算出的 hash 值是⼀个简单的整数,⽅便⾁眼观察)

当引⼊⼀个新的分⽚,N 从 3 => 4 时,⼤量的 key 都需要重新映射(某个key % 3 和 % 4 的结果不⼀样, 就映射到不同机器上了)

在这里插入图片描述

如上图可以看到, 整个扩容⼀共 21 个 key, 只有 3 个 key 没有经过搬运, 其他的 key 都是搬运过的

2.2一致性哈希算法

一致性哈希算法的映射策略:

为了降低上述的搬运开销,能够更⾼效扩容,业界提出了 “⼀致性哈希算法”,key 映射到分⽚序号的过程不再是简单求余了, ⽽是改成以下过程

  1. 把 0 -> 2^32-1 这个数据空间, 映射到⼀个圆环上. 数据按照顺时针⽅向增⻓
  2. 假设当前存在三个分⽚, 就把分⽚放到圆环的某个位置上
  3. 假定有⼀个 key, 计算得到 hash 值 H, 那么这个 key 映射到哪个分⽚呢? 规则很简单, 就是从 H 所在位置, 顺时针往下找, 找到的第⼀个分⽚, 即为该 key 所从属的分⽚

在这里插入图片描述

这就相当于, N 个分⽚的位置, 把整个圆环分成了 N 个管辖区间. Key 的 hash 值落在某个区间内, 就归对应区间管理

一致性哈希算法的扩容策略:

原有分⽚在环上的位置不动, 只要在环上新安排⼀个分⽚位置即可,比如:当需要新增一个分片3号,只需要把 0 号分⽚上的部分数据, 搬运给 3 号分⽚即可,1号分⽚和 2号分⽚管理的区间都是不变的

在这里插入图片描述

通过上图就可以发现,移动的数据只有全部存储数据的六分之一,可以说是非常的少了,但是也暴露了该算法数据分布不均的问题。

一致性哈希算法的优点:⼤⼤降低了扩容时数据搬运的规模, 提⾼了扩容操作的效率

一致性哈希算法的缺点:数据分配不均匀 (有的多有的少, 数据倾斜)

2.3哈希槽分区算法

为了解决上述问题 (搬运成本⾼ 和 数据分配不均匀), Redis cluster 引⼊了哈希槽 (hash slots) 算法

hash_slot = crc16(key) % 16384
  • crc16是一种哈希算法
  • 16384 = 16 * 1024 = 2^14 表示槽位数

相当于是把整个哈希值映射到 16384 个槽位上,也就是 [0, 16383],然后再把这些槽位⽐较均匀的分配给每个分⽚,每个分⽚的节点都需要记录⾃⼰持有哪些分⽚

哈希槽分区算法的槽位分配规则

假设当前有三个分⽚, ⼀种可能的分配⽅式:

  • 0号分⽚: [0, 5461], 共 5462 个槽位

  • 1号分⽚: [5462, 10923], 共 5462 个槽位

  • 2号分⽚: [10924, 16383], 共 5460 个槽位

注意:这⾥的分⽚规则是很灵活的,每个分⽚持有的槽位也不⼀定连续,每个分⽚的节点使⽤位图来表⽰⾃⼰持有哪些槽位. 对于 16384 个槽位来说, 需要 2048 个字节(2KB) ⼤⼩的内存空间表⽰

如果需要进⾏扩容, ⽐如新增⼀个 3 号分⽚, 就可以针对原有的槽位进⾏重新分配. ⽐如可以把之前每个分⽚持有的槽位, 各拿出⼀点, 分给新分⽚,⼀种可能的分配⽅式:

  • 0号分⽚:[0, 4095], 共 4096 个槽位
  • 1号分⽚:[5462, 9557], 共 4096 个槽位
  • 2号分⽚:[10924, 15019], 共 4096 个槽位
  • 3号分⽚:[4096, 5461] + [9558, 10923] + [15019, 16383], 共 4096 个槽位

我们在实际使⽤ Redis 集群分⽚的时候, 不需要⼿动指定哪些槽位分配给某个分⽚, 只需要告诉某个分⽚应该持有多少个槽位即可, Redis 会⾃动完成后续的槽位分配, 以及对应的 key 搬运的⼯作

Redis 集群是最多有 16384 个分⽚吗?

并⾮如此. 如果⼀个分⽚只有⼀个槽位, 这对于集群的数据均匀其实是难以保证的,实际上 Redis 的作者建议集群分⽚数不应该超过 1000,⽽且,16000 这么⼤规模的集群, 本⾝的可⽤性也是⼀个⼤问题. ⼀个系统越复杂, 出现故障的概率是越⾼的

为什么是 16384 个槽位?

节点之间通过⼼跳包通信. ⼼跳包中包含了该节点持有哪些 slots. 这个是使⽤位图这样的数据结构表⽰的. 表⽰ 16384 (16k) 个 slots, 需要的位图⼤⼩是 2KB. 如果给定的 slots 数更多了, ⽐如 65536 个了, 此时就需要消耗更多的空间, 8 KB 位图表⽰了8 KB, 对于内存来说不算什么,但是在频繁的⽹络⼼跳包中, 还是⼀个不⼩的开销的.

另⼀⽅⾯, Redis 集群⼀般不建议超过 1000 个分⽚. 所以 16k 对于最⼤ 1000 个分⽚来说是⾜够⽤的, 同时也会使对应的槽位配置位图体积不⾄于很⼤

三、集群的搭建

基于 docker, 搭建⼀个集群. 每个节点都是⼀个容器,在创建redis集群前需要先把正在运行的redis服务器停掉,避免不必要的麻烦

创建 redis-cluster ⽬录. 内部创建两个⽂件

redis-cluster/
├── docker-compose.yml  #docker-compose的配置文件,主要为了同时启动多个容器
└── generate.sh  #shell脚本

3.1配置docker-compose.yml文件

在配置该文件之前,需要先查看一下我们主机上现在存在的网段号:

ifconfig

在这里插入图片描述

通过上图就可以发现,我们主机上存在的网段,此时我们进行下面配置的时候,只要不和上述的网段冲突就行。

version: '3.7'
networks:mynet:ipam:config:- subnet: 172.30.0.0/24#创建的虚拟局域网,网段,不能和主机上的网段冲突
services:redis1:image: 'redis:5.0.9'container_name: redis1restart: alwaysvolumes:- ./redis1/:/etc/redis/ports:- 6371:6379- 16371:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.101redis2:image: 'redis:5.0.9'container_name: redis2restart: alwaysvolumes:- ./redis2/:/etc/redis/ports:- 6372:6379- 16372:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.102redis3:image: 'redis:5.0.9'container_name: redis3restart: alwaysvolumes:- ./redis3/:/etc/redis/ports:- 6373:6379- 16373:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.103redis4:image: 'redis:5.0.9'container_name: redis4restart: alwaysvolumes:- ./redis4/:/etc/redis/ports:- 6374:6379- 16374:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.104redis5:image: 'redis:5.0.9'container_name: redis5restart: alwaysvolumes:- ./redis5/:/etc/redis/ports:- 6375:6379- 16375:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.105redis6:image: 'redis:5.0.9'container_name: redis6restart: alwaysvolumes:- ./redis6/:/etc/redis/ports:- 6376:6379- 16376:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.106redis7:image: 'redis:5.0.9'container_name: redis7restart: alwaysvolumes:- ./redis7/:/etc/redis/ports:- 6377:6379- 16377:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.107redis8:image: 'redis:5.0.9'container_name: redis8restart: alwaysvolumes:- ./redis8/:/etc/redis/ports:- 6378:6379- 16378:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.108 redis9:image: 'redis:5.0.9'container_name: redis9restart: alwaysvolumes:- ./redis9/:/etc/redis/ports:- 6379:6379- 16379:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.109redis10:image: 'redis:5.0.9'container_name: redis10restart: alwaysvolumes:- ./redis10/:/etc/redis/ports:- 6380:6379- 16380:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.110redis11:image: 'redis:5.0.9'container_name: redis11restart: alwaysvolumes:- ./redis11/:/etc/redis/ports:- 6381:6379- 16381:16379command:redis-server /etc/redis/redis.confnetworks:mynet:ipv4_address: 172.30.0.111     

3.2配置generate.sh脚本文件

#port in $(seq 1 9) 表示获取一到九放到port中
for port in $(seq 1 9); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.10${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done
# 注意 cluster-announce-ip 的值有变化.
for port in $(seq 10 11); \
do \
mkdir -p redis${port}/
touch redis${port}/redis.conf
cat << EOF > redis${port}/redis.conf
port 6379
bind 0.0.0.0
protected-mode no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 172.30.0.1${port}
cluster-announce-port 6379
cluster-announce-bus-port 16379
EOF
done

执⾏命令:

bash generate.sh

⽣成⽬录如下:

在这里插入图片描述

启动docker容器:

docker-compose up -d

在这里插入图片描述

此时就算创建成功了

3.3构建redis集群

此处是把前 9 个主机构建成集群, 3 主 6 从. 后 2 个主机暂时不⽤

redis-cli --cluster create 172.30.0.101:6379 172.30.0.102:6379 172.30.0.103:6379 172.30.0.104:6379 172.30.0.105:6379 172.30.0.106:6379 172.30.0.107:6379 172.30.0.108:6379 172.30.0.109:6379 --cluster-replicas 2

上面的这些ip地址是redis.conf中的IP地址,也就是docker-compose.yml中对应的ip地址,根据自己的实际情况进行输入ip地址和端口号

  • –cluster create 表⽰建⽴集群. 后⾯填写每个节点的 ip 和地址
  • –cluster-replicas 2 表⽰每个主节点需要两个从节点备份

执⾏之后, 容器之间会进⾏加⼊集群操作

在这里插入图片描述

此时提示我们这些节点的分布情况和槽位的分配情况,询问我们是否同意,同意就继续,不同意就终止:

在这里插入图片描述

当出现这样的结果,就表明集群构建成功了

3.4简单测试redis集群

此时, 使⽤客⼾端连上集群中的任何⼀个节点,都相当于连上了整个集群

客⼾端后⾯要加上 -c 选项, 否则如果 key 没有落到当前节点上, 是不能操作的. -c 会⾃动把请求重定向到对应节点. 使⽤ cluster nodes 可以查看到整个集群的情况

连接集群中的一个节点

redis-cli -h 172.30.0.101 -p 6379 -c

查看集群分布情况

cluster nodes

在这里插入图片描述

插入数据的时候,如果数据对应的不是当前节点,那么集群会进行重定向

set key 1

在这里插入图片描述

通过上图可以发现,本来连接的是172.30.0.101这个节点,但是插入数据的时候连接重定向到了172.30.0.103这个节点

四、故障处理流程

主节点宕机后的情况

⼿动停⽌⼀个 master 节点, 观察效果

docker stop redis1

连上 redis2 , 观察结果

redis-cli -h 172.30.0.102 -p 6379 -c

观察集群的分布情况

cluster nodes

在这里插入图片描述

通过上图,可以发现本来172.30.0.101这个节点是master节点,但是现在它处于fail状态,而172.30.0.106这个节点以前是slave节点,现在变成了master节点

重新启动172.30.0.101这个节点

docker start redis1

启动后,观察现在的集群分布情况

cluster nodes

在这里插入图片描述

可以发现现在172.30.0.101这个节点变成了slave节点

当然也可以手动恢复集群,可以使⽤ cluster failover 进⾏集群恢复. 也就是把 101 重新设定成 master. (登录到 101 上执⾏)

cluster failover

在这里插入图片描述

此时172.30.0.101这个节点就又变成了master节点

4.1故障判定

集群中的所有节点,都会周期性的使⽤⼼跳包进⾏通信

  1. 节点 A 给 节点 B 发送 ping 包,B 就会给 A 返回⼀个 pong 包,ping 和 pong 除了 message type属性之外,其他部分都是⼀样的。 这⾥包含了集群的配置信息(该节点的id,该节点从属于哪个分⽚,是主节点还是从节点, 从属于谁, 持有哪些 slots 的位图…)
  2. 每个节点, 每秒钟, 都会给⼀些随机的节点发起 ping 包,⽽不是全发⼀遍这样设定是为了避免在节点很多的时候,⼼跳包也⾮常多(⽐如有 9 个节点,如果全发,就是 9 * 8 有 72 组⼼跳了,⽽且这是按照 N^2 这样的级别增⻓的)
  3. 当节点 A 给节点 B 发起 ping 包,B 不能如期回应的时候,此时 A 就会尝试重置和 B 的 tcp 连接,看能否连接成功如果仍然连接失败, A 就会把 B 设为 PFAIL 状态(相当于主观下线)
  4. A 判定 B 为 PFAIL 之后,会通过 redis 内置的 Gossip 协议,和其他节点进⾏沟通,向其他节点确认 B 的状态(每个节点都会维护⼀个⾃⼰的 “下线列表”,由于视⻆不同, 每个节点的下线列表也不⼀定相同)
  5. 此时A发现其他很多节点, 也认为 B 为 PFAIL,并且数⽬超过总集群个数的⼀半,那么 A 就会把 B 标记成 FAIL (相当于客观下线), 并且把这个消息同步给其他节点(其他节点收到之后,也会把 B 标记成 FAIL)

⾄此, B 就彻底被判定为故障节点了

集群宕机的三种情况

  1. 某个分⽚, 所有的主节点和从节点都挂了.

  2. 某个分⽚, 主节点挂了, 但是没有从节点.

  3. 超过半数的 master 节点都挂了

4.2故障转移

所谓故障迁移, 就是指把从节点提拔成主节点, 继续给整个 redis 集群提供⽀持。

上述例⼦中, B 故障, 并且 A 把 B FAIL 的消息告知集群中的其他节点,此时会有两种情况:

  1. 如果 B 是从节点, 那么不需要进⾏故障迁移
  2. 如果 B 是主节点, 那么就会由 B 的从节点 (⽐如 C 和 D) 触发故障迁移了

具体步骤如下:

  1. 从节点判定⾃⼰是否具有参选资格. 如果从节点和主节点已经太久没通信(此时认为从节点的数据和主节点差异太⼤了), 时间超过阈值, 就失去竞选资格

  2. 具有资格的节点, ⽐如 C 和 D, 就会先休眠⼀定时间. 休眠时间 = 500ms 基础时间 + [0, 500ms] 随机时间 + 排名 * 1000ms. offset 的值越⼤, 则排名越靠前(越⼩)

  3. ⽐如 C 的休眠时间到了, C 就会给其他所有集群中的节点, 进⾏拉票操作. 但是只有主节点才有投票资格

  4. 主节点就会把⾃⼰的票投给 C (每个主节点只有 1 票). 当 C 收到的票数超过主节点数⽬的⼀半, C 就会晋升成主节点. (C ⾃⼰负责执⾏ slaveof no one, 并且让 D 执⾏ slaveof C)

  5. 同时, C 还会把⾃⼰成为主节点的消息, 同步给其他集群的节点. ⼤家也都会更新⾃⼰保存的集群结构信息

补充:上述选举的过程, 称为 Raft 算法, 是⼀种在分布式系统中⼴泛使⽤的算法. 在随机休眠时间的加持下, 基本上就是谁先唤醒, 谁就能竞选成功

五、集群扩容

扩容是⼀个在开发中比较常遇到的场景,比如现有集群很可能⽆法容纳⽇益增⻓的数据,此时就需要给集群中加⼊更多新的机器,使存储的空间更大了

所谓分布式的本质, 就是使⽤更多的机器, 引⼊更多的硬件资源

第一步:将新的主节点加入集群中

上⾯已经把 redis1 - redis9 重新构成了集群. 接下来把 redis10 和 redis11 也加⼊集群

语法:
redis-cli --cluster add-node 第一组地址 第二组地址
#先将redis10加入集群
redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379

注意:add-node 后的第⼀组地址是新节点的地址,第⼆组地址是集群中的任意节点地址

在这里插入图片描述

查看集群分布情况

cluster nodes

在这里插入图片描述

可以发现此时的172.30.0.110这个节点成了master节点,但是此时还没有槽位

第二步:重新分配槽位

redis-cli --cluster reshard 172.30.0.101:6379

注意:reshard 后的地址是集群中的任意节点地址,另外,注意单词拼写,是 reshard (重新切分), 不是 reshared (重新分享),不要多写个 e

执⾏之后, 会进⼊交互式操作, redis 会提示用户输⼊以下内容:

  • 多少个 slots 要进行 reshard ? (此处我们填写 4096)

  • 哪个节点来接收这些 slots ? (此处我们填写 172.30.0.110 这个节点的集群节点 id)

  • 这些 slots 从哪些节点搬运过来? (此处我们填写 all, 表示从其他所有的节点都进行搬运)

How many slots do you want to move (from 1 to 16384)? 4096
What is the receiving node ID? #这个位置的id是 cluster nodes 获取到的id
Please enter all the source node IDs.
Type 'all' to use all the nodes as source nodes for the hash slots.
Type 'done' once you entered all the source nodes IDs.
Source node #1: all

注意:在搬运 key 的过程中, 对于那些不需要搬运的 key, 访问的时候是没有任何问题的. 但是对于需要搬运的 key, 进行访问可能会出现短暂的访问错误 (key 的位置出现了变化). 随着搬运完成, 这样的错误自然就恢复了

第三步:给新的主节点添加从节点

光有主节点了, 此时扩容的⽬标已经初步达成. 但是为了保证集群可⽤性,还需要给这个新的主节点添加从节点, 保证该主节点宕机之后,有从节点能够顶上

#语法
redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave --cluster-master-id [172.30.1.110 节点的 nodeId]
## 添加redis11为redis10的从节点
redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave --cluster-master-id d2ae62523e50dde1a0644dc4fe733d2357c3f0d5

在这里插入图片描述

查看集群的分布情况:

在这里插入图片描述

通过上图的id比对,可以发现redis11成为了redis10的从节点

补充:删除节点

redis-cli --cluster del-node 172.30.0.111:6379 节点id

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

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

相关文章

Linux | Linux的开机启动流程

对于linux系统的初学者来说&#xff0c;理解并掌握linux系统启动流程能够使你够深入的理解linux系统&#xff0c;还可以通过系统的启动过程来分析问题解决问题。 Linux开机启动的流程如下图 power on 开机 post自检&#xff08;检查一部分大的硬件&#xff09; BIOS&#xf…

TiDB如何保证数据一致性

1. 分布式事务协议 TiDB 采用了类似 Google Percolator 的分布式事务协议来处理分布式事务。这个协议基于两阶段提交&#xff08;2PC&#xff09;的思想&#xff0c;但进行了优化和改进&#xff0c;以适应分布式环境的特殊需求。在 TiDB 中&#xff0c;当一个事务需要跨多个节…

【Maven系列】深入解析 Maven 常用命令

前言 在当今的软件开发过程中&#xff0c;项目管理是至关重要的一环。项目管理包括了项目构建、依赖管理以及发布部署等诸多方面。而在Java生态系统中&#xff0c;Maven已经成为了最受欢迎的项目管理工具之一。Maven 是一套用于构建、依赖管理和项目管理的工具&#xff0c;主要…

DBA面试题-1

面临失业&#xff0c;整理一下面试题&#xff0c;找下家继续搬砖 主要参考&#xff1a;https://www.csdn.net/?spm1001.2101.3001.4476 略有修改 一、mysql有哪些数据类型 1&#xff0c; 整形 tinyint,smallint,medumint,int,bigint&#xff1b;分别占用1字节、2字节、3字节…

【Rust WebAssembly 入门实操遇到的问题】

Rust WebAssembly 入门实操遇到的问题 什么是WebAssembly跟着教程走wasm-pack build error总结 什么是WebAssembly WebAssembly&#xff08;简称Wasm&#xff09;是一种基于堆栈的虚拟机的二进制指令 格式。Wasm 被设计为编程语言的可移植编译目标&#xff0c;支持在 Web 上部…

数据挖掘之数据预处理

​​​​​​​ 引言 数据挖掘是从大量数据中提取有用信息和知识的过程。在这个过程中&#xff0c;数据预处理是不可或缺的关键步骤。数据预处理旨在清理和转换数据&#xff0c;以提高数据质量&#xff0c;从而为后续的数据挖掘任务奠定坚实的基础。由于现实世界中的数据通常…

21个Python脚本自动执行日常任务(1)

引言 作为编程领域摸爬滚打超过十年的老手&#xff0c;我深刻体会到&#xff0c;自动化那些重复性工作能大大节省我们的时间和精力。 Python以其简洁的语法和功能强大的库支持&#xff0c;成为了编写自动化脚本的首选语言。无论你是专业的程序员&#xff0c;还是希望简化日常工…

从 HTML 到 CSS:开启网页样式之旅(五)—— CSS盒子模型

从 HTML 到 CSS&#xff1a;开启网页样式之旅&#xff08;五&#xff09;—— CSS盒子模型 前言一、盒子模型的组成margin&#xff08;外边距&#xff09;&#xff1a;border&#xff08;边框&#xff09;&#xff1a;padding&#xff08;内边距&#xff09;&#xff1a;conten…

使用Feign远程调用丢失请求头问题

在使用Feign进行远程调用时&#xff0c;当前服务是能拿到请求头信息的&#xff0c;请求头包含有登录认证Cookie等重要信息&#xff0c;但是在调用远程服务时&#xff0c;远程服务却拿不到请求头信息&#xff0c;因为使用Feign进行远程调用实际上是发起新的Request请求了&#x…

2021数学分析【南昌大学】

2021 数学分析 求极限 lim ⁡ n → ∞ 1 n ( n + 1 ) ( n + 2 ) ⋯ ( n + n ) n \lim_{n \to \infty} \frac{1}{n} \sqrt [n]{(n+1)(n+2) \cdots (n+n)} n→∞lim​n1​n(n+1)(n+2)⋯(n+n) ​ lim ⁡ n → ∞ 1 n ( n + 1 ) ( n + 2 ) ⋯ ( n + n ) n = lim ⁡ n → ∞ ( n + …

vue+mars3d点击图层展示炫酷的popup弹窗

展示效果 目录 一&#xff1a;叠加数据图层到地图上&#xff0c;此时需要使用bindPopup绑定popup 二、封装自定义的popup&#xff0c;样式可以自行调整 一&#xff1a;叠加数据图层到地图上&#xff0c;此时需要使用bindPopup绑定popup 这里我根据数据不同&#xff0c;展示的…

【AIGC】如何使用高价值提示词Prompt提升ChatGPT响应质量

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: AIGC | 提示词Prompt应用实例 文章目录 &#x1f4af;前言&#x1f4af;提示词英文模板&#x1f4af;提示词中文解析1. 明确需求2. 建议额外角色3. 角色确认与修改4. 逐步完善提示5. 确定参考资料6. 生成和优化提示7.…

FPGA存在的意义:为什么adc连续采样需要fpga来做,而不会直接用iic来实现

FPGA存在的意义&#xff1a;为什么adc连续采样需要fpga来做&#xff0c;而不会直接用iic来实现 原因ADS111x连续采样实现连续采样功能说明iic读取adc的数据速率 VS adc连续采样的速率adc连续采样的速率iic读取adc的数据速率结论分析 FPGA读取adc数据问题一&#xff1a;读取adc数…

LobeChat-46.6k星!顶级AI工具集,一键部署,界面美观易用,ApiSmart 是你肉身体验学习LLM 最好IDEA 工具

LobeChat LobeChat的开源&#xff0c;把AI功能集合到一起&#xff0c;真的太爽了。 我第一次发现LobeChat的时候&#xff0c;就是看到那炫酷的页面&#xff0c;这么强的前端真的是在秀肌肉啊&#xff01; 看下它的官网&#xff0c;整个网站的动效简直闪瞎我&#xff01; GitH…

[报错] Error: PostCSS plugin autoprefixer requires PostCSS 8 问题解决办法

报错&#xff1a;Error: PostCSS plugin autoprefixer requires PostCSS 8 原因&#xff1a;autoprefixer版本过高 解决方案&#xff1a; 降低autoprefixer版本 执行&#xff1a;npm i postcss-loader autoprefixer8.0.0 参考&#xff1a; Error: PostCSS plugin autoprefix…

基于STM32的Wi-Fi无人机项目

引言 随着无人机技术的快速发展&#xff0c;基于微控制器的DIY无人机变得越来越流行。本项目将介绍如何使用STM32微控制器制作一架简单的Wi-Fi无人机。通过本项目&#xff0c;您将了解到无人机的基本组成部分&#xff0c;如何进行硬件连接&#xff0c;代码编写&#xff0c;以及…

IDEA注释格式、匹配补全调整

1.注释格式调整 目前重新捡起一部分Java&#xff0c;写代码时候发现注释快捷键总是放在第一列&#xff0c;看起来很难受&#xff0c;故寻找方法如下&#xff1a; 分别点击 编辑器-代码样式-Java 修改注释代码选项如下 2.大小写匹配补全问题 还发现在写代码过程中&#xff0c…

麒麟 V10(ky10.x86_64)无网环境下 openssl - 3.2.2 与 openssh - 9.8p1 升级【最全教程】

目录 背景 安装包下载 上传解压安装包 安装zlib 安装OpenSSL 安装OpenSSH 验证 背景 近期&#xff0c;项目上线已进入倒计时阶段&#xff0c;然而在至关重要的安全检查环节中&#xff0c;却惊现现有的 OpenSSH 存在一系列令人担忧的漏洞&#xff1a; OpenSSH 资源管理错…

高级架构二 Git基础到高级

一 Git仓库的基本概念和流程 什么是版本库&#xff1f;版本库又名仓库&#xff0c;英文名repository,你可以简单的理解一个目录&#xff0c;这个目录里面的所有文件都可以被Git管理起来&#xff0c;每个文件的修改&#xff0c;删除&#xff0c;Git都能跟踪&#xff0c;以便任何…

从excel数据导入到sqlsever遇到的问题

1、格式问题时间格式&#xff0c;excel中将日期列改为日期未生效&#xff0c;改完后&#xff0c;必须手动单击这个单元格才能生效&#xff0c;那不可能一个一个去双击。解决方案如下 2、导入之后表字段格式问题&#xff0c;数据类型的用navicat导入之后默认是nvarchar类型的&a…