Redis部署-集群

目录

集群

数据分片算法

哈希求余

一致性哈希算法

哈希槽分区算法

redis集群搭建

1.创建目录和配置.

2.将上述redis节点.构建成集群

3.使用客户端连接集群

集群模式下的故障转移流程

1.故障判定

2.故障迁移

集群扩容


集群

广义上的集群,只要是多个机器,构成了分布式系统,都可以称为是一个"集群".前面的主从模式和哨兵模式也可以称为是广义的集群.

狭义的集群,redis提供的集群模式,在这个集群模式之下,主要是姐姐,存储空间不足的问题.

redis集群基本概念

上述的哨兵模式,虽然提高了系统的可用性,但是真正用来存储数据的还是master和slave节点,所有的数据都需要存储在单个的master和slave节点中.

如果数据量很大,超出了master/slave所在机器的物理内存,就可能出现严重问题了.

那么如何获得更大的空间,加机器即可!!!

redis集群就是在上述思路下,引入多组master/slave存储数据全集的一部分,从而构成一个更大的整体,称为是redis集群.

假定整个数据全集是1TB,此时就可以引入三组master/slave,每一组master/slave只需要存储整个数据全集的三分之一即可.

其中每一组主从节点保存的是同样的数据,占数据全集的三分之一.

每个从节点都是对应主节点的备份,当主节点挂了,对应的slave会补位成主节点.

每组主从节点都可以称为是一个分片(sharding).

如果全量数据进一步增加,只要在增加更多的分片即可.


数据分片算法

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

哈希求余

借助了哈希表的基本思想,借助hash函数,把一个key映射到整数,在针对数组的长度,求余,就可以得到一个数组的下标.

比如有三个分片,编号为0,1,2.

此时就可以针对要插入的数据key计算hash值(比如使用MD5计算hash值),在把这个hash值余上分片的个数,就得到了一个编号,此时就可以把这个数据放到对应的下标对应分片中了.

md5是一个计算hash值的算法.它能够针对一个字符串里面的内容进行一系列的数学演算,最终得到一个整数.

它是一个非常广泛使用的hash算法.特点:

  • 1.md5计算结果是定长的,无论输入的原字符串有多长,最终算出的结果就是固定长度.
  • 2.md5计算结果是分散的,两个源字符串,哪怕只有一个地方不同,算出来的md5值也会差别很大.
  • 3.md5计算结果是不可逆的.字符串->md5值是很容易得到,而根据md5值还原出原始字符串是很困难的,理论上是不可行的.

如果计算出hash(key)%3==0,此时这个key就要存储在0号分片中,后续查询key的时候,也是同样的算法.

数据搬运

一旦服务器集群需要扩容,就需要更高的成本了.分片的主要目的是为了提高存储能力,分片越多,能存的数据也就越多,但是成本也就更高.

如果随着业务的增长,原先的三个分片已经不够用了,那么此时就要"扩容",引入更多的分片.

引入新的分片的后,hash(key)%N中的N就变了,加入这里新引入一个分片,N就从3变为了4.

当hash函数和key都不变的情况下,如果N变了,整体的分片结果仍然会改变.

如果发现某个数据,在扩容之后,不应该存储在当前的分片中了,就需要重新进行分配这个数据,这个过程就叫做数据搬运.

从上图可以看出,一共20个数据,经过扩容之后,只有3个数据不需要搬运,17个数据需要搬运!!!

由此我们知道采用哈希求余算法需要搬运的数据的比例是很高的.如果在生产环境上扩容,开销是极大的.所以我们往往不能直接在生产环境上操作上述过程,只能通过替换的方式来实现扩容.但是替换也就意味着依赖的机器更多了,成本更高,操作步骤也非常复杂!!!


一致性哈希算法

在hash求余这种操作下,当前的key属于哪个分片,是交替的.

102->0,103->1,104->2,105->0......,交替出现,就导致数据搬运的成本很大.

在一致性hash算法中,把交替出现,改进成了连续出现.降低了数据搬运的开销,能够高效扩容.

一致性hash算法过程

1.把0->2^31-1这个数据空间,映射到一个圆环上,数据按照顺时针方向增长.

2.假设当前存在三个分片,就把分片放到圆环的某个位置上.

3.假定有一个key,计算得到hash值H,就从H所在位置,顺时针往下找,找到的第一个分片,即为该key所从属的分片.

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


在这种情况下,如果扩容一个分片,原有分片在环上的位置不动,只要在环上新安排一个分片位置即可.

此时,只要把0号分片上的部分数据,搬运到3号分片上即可,1号分片和2号分片管理的区间上的数据都是不变的.

虽然搬运的成本低了,但是这几个分片上的数据量,就可能步均匀了,就造成了数据倾斜的问题!!!


哈希槽分区算法

此种算法是redis真正采用的分片算法.

为了解决搬运成本高和数据分配不均匀的问题,reids cluster引入了哈希槽算法.

hash_slot = crc16(key) % 16384

其中crc也是一种hash算法.

相当于把整个哈希值,映射到16384个槽位上,也就是[0,16384].

然后把这些槽位均匀的分配给每个分片,每个分片的节点都需要记录自己持有哪些分片.

这种算法,本质就是把一致性hash和哈希求余两种方式结合一下.

假设现在有三个分片,一种可能的分配方式:

0号分片:[0,5461],共5462个槽位;

1号分片:[5462,10923],共5462个槽位.

2号分片:[10924,16383],共5460个槽位.

虽然不是严格意义的均匀,但是差异非常小,此时这三个分片上的数据就是比较均匀的了.

上述只是一种可能的分片方式,实际上分片是非常灵活的,每个分片持有的槽位号,可以是连续的,也可以是不连续的.

此处,每个分片都会使用位图这样的数据结构,来表示出当前持有的槽位.16384个bit位(2KB),用每一位的0或者1来区分这个分片是否持有这个槽位.

如果需要扩容,比如新增一个3号分片,就可以针对原有的槽位进行重新分配.

比如可以把之前每个分片持有的槽位,各拿出一点,分给新的分片.

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

注意,我们在使用redis集群分片的时候,不需要手动指定哪些槽位分配给某个分片,只需要告诉redis某个分片应该持有多少个槽位即可,redis会自动完成后续的槽位分配,以及key对应的搬运工作.

关于哈希槽分区算法的两个问题

redis集群是最多有16384个分片吗???

其实不然,如果一个分片上只有一个槽位,这对于集群的数据均匀是难以保证的.而且16384个分片这么大规模的集群,本身的可用性是一个大问题.

实际上redis的作者建议分片的数目不应该超过1000.

为什么是16384个槽位???

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

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

总结来说,就是这些个槽位基本上是够用的,同时占用的网络带宽也不是很大.


redis集群搭建

在这里由于只有一台云服务器,所以也是基于docker搭建.

实际工作中,一般是通过主机的方式,来搭建集群.

在搭建之前,一定要把之前启动的redis容器,给停止掉!!!在redis-data目录和redis-sentinel目录下分别执行docker-compose down命令.

在这里我们创建出11个redis节点,其中9个用于集群的搭建,2个用于集群的扩容.


1.创建目录和配置.

创建redis-cluster目录,内部创建两个文件.

在linux上以.sh为后缀结尾的文件,称为是shell脚本.shell脚本里可以批量化执行命令,并且还能加入条件,循环,函数等机制,来完成更加复杂的工作.

generate.sh内容

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

for port in $(seq 1 9);表明这是一个基于范围的循环.类似于java的for each.

seq也是一个命令,seq 1 9表示生成1-9闭区间内的数据.

\是续行符,把下一行的内容和当前行,合并成一行.shell默认情况下,要求把所有的代码都写到一行里,使用续行符来换行.

对于for来说,用do和done表示代码块的开始和结束,shell中{}用来表示变量了,不表示代码块.

shell中拼接字符是直接写到一起,而不需要使用+.

因此上述第一个循环就表示,创建9个目录,在这些目录下创建一个文件,将内容写到文件中去.

这些内容只有在配置集群的ip的时候是不一致的,

cluster-announce-ip 172.30.0.10${port},会生成101-109的ip.

经过上述两个循环,就会得到11个目录,每个目录里都有一个配置文件,配置文件中ip地址各不相同.

cluster-enabled yes表示开启集群
cluster-config-file nodes.conf//不需要手动写,redis自动生成,后续启动节点之后,会配置一些redis集群信息,写入到此文件中.
cluster-node-timeout 5000//多个节点保持联络的心跳包的超时时间
cluster-announce-ip 172.30.0.10${port}//该redis节点所在主机的ip,当前是使用docker容器模拟的主机,此处写的应该是docker容器的ip.
cluster-announce-port 6379//redis节点自身绑定的端口(容器内的端口),属于是业务端口.
cluster-announce-bus-port 16379//该redis节点的管理端口.

一个服务器,可以绑定多个端口号.

业务端口是用来完成业务数据通信的,响应redis客户端的请求.

管理端口:为了完成一些管理上的任务来进行通信的端口,如果某个分片的redis主节点挂了,就需要从节点成为主节点,此过程就需要管理端口来完成对应的操作.

完成上述操作之后,使用bash命令执行shell脚本.


docker-compose.yml的编写

version: '3.7'
networks:
  mynet:
    ipam:
      config:
        - subnet: 172.30.0.0/24
services:
  redis1:
    image: 'redis:5.0.9'
    container_name: redis1
    restart: always
    volumes:
      - ./redis1/:/etc/redis/
    ports:
      - 6371:6379
      - 16371:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.101
  redis2:
    image: 'redis:5.0.9'
    container_name: redis2
    restart: always
    volumes:
      - ./redis2/:/etc/redis/
    ports:
      - 6372:6379
      - 16372:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.102
  redis3:
    image: 'redis:5.0.9'
    container_name: redis3
    restart: always
    volumes:
      - ./redis3/:/etc/redis/
    ports:
      - 6373:6379
      - 16373:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.103
  redis4:
    image: 'redis:5.0.9'
    container_name: redis4
    restart: always
    volumes:
      - ./redis4/:/etc/redis/
    ports:
      - 6374:6379
      - 16374:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.104
  redis5:
    image: 'redis:5.0.9'
    container_name: redis5
    restart: always
    volumes:
      - ./redis5/:/etc/redis/
    ports:
      - 6375:6379
      - 16375:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.105
  redis6:
    image: 'redis:5.0.9'
    container_name: redis6
    restart: always
    volumes:
      - ./redis6/:/etc/redis/
    ports:
      - 6376:6379
      - 16376:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.106
  redis7:
    image: 'redis:5.0.9'
    container_name: redis7
    restart: always
    volumes:
      - ./redis7/:/etc/redis/
    ports:
      - 6377:6379
      - 16377:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.107
  redis8:
    image: 'redis:5.0.9'
    container_name: redis8
    restart: always
    volumes:
      - ./redis8/:/etc/redis/
    ports:
      - 6378:6379
      - 16378:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.108
  redis9:
    image: 'redis:5.0.9'
    container_name: redis9
    restart: always
    volumes:
      - ./redis9/:/etc/redis/
    ports:
      - 6379:6379
      - 16379:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.109
  redis10:
    image: 'redis:5.0.9'
    container_name: redis10
    restart: always
    volumes:
      - ./redis10/:/etc/redis/
    ports:
      - 6380:6379
      - 16380:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.110
  redis11
    image: 'redis:5.0.9'
    container_name: redis11
    restart: always
    volumes:
      - ./redis11:/etc/redis/
    ports:
      - 6381:6379
      - 16381:16379
    command:
      redis-server /etc/redis/redis.conf
    networks:
      mynet:
        ipv4_address: 172.30.0.111

此处为了后续创建静态ip,要先手动创建出网络,同时给这个网络也分配ip.

创建完配置文件之后,启动容器.


2.将上述redis节点.构建成集群

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

--cluster create表示建立集群,后面填写每个节点的ip和端口.

--cluster-replicas 2表示每个主节点需要2个从节点备份.

redis在构建集群的时候,谁是主节点谁是从节点,哪些节点是一个分片不是固定的.

执行命令.

输入yes.

集群构造完毕.


3.使用客户端连接集群

从101-109九个节点,现在是一个整体,使用客户都安连上任意一个节点,都是在操作整个集群,本质上都是等价的.

使用cluster nodes命令查看当前集群的信息.

使用集群来存储数据.

设置成集群模式之后,当前数据就要分片存储了,k1这个key通过hash计算之后,得到slot为12706,属于103这个分片,所以就报错了.

我们可以在启动redis客户端的时候,加上-c选项,此时客户端如果发现当前的key的操作不在当前分片上,就能够自动的重定向到对应的分片主机.

请求转发给了103这个节点,进一步完成了数据存储的操作.

使用集群之后,之前学过的操作多个key的命令有时候就不能正常使用了,此时如果key分布在多个分片上,就有可能出现问题.


如果集群中,有节点挂了怎么办?

如果挂了的是从节点,没有多大影响.

如果挂了的是主节点,因为只有主节点才能处理写操作(如果在从节点上尝试写操作,此时就会自动的被重定向到指定的主节点上),此时集群做的工作就和哨兵做的类似了,集群会自动的把该主节点旗下的从节点,选拔一个出来,晋升为主节点.

我们先使用docker stop redis1命令停掉redis1.

在连上一个客户端查看集群信息.

可以看出,106成了新的主节点,并且105成了106的从节点.

然后我们在使用docker start redis1恢复redis1节点.

再次查看集群信息.

101成了从节点,从属于106.

通过上述过程,我们可以看出,集群机制具有故障转移的机制.


集群模式下的故障转移流程

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 就彻底被判定为故障节点了.

2.故障迁移

上述例⼦中, B 故障, 并且 A 把 B FAIL 的消息告知集群中的其他节点.
如果 B 是从节点, 那么不需要进⾏故障迁移.
如果 B 是主节点, 那么就会由 B 的从节点 (⽐如 C 和 D) 触发故障迁移了.
所谓故障迁移, 就是指把从节点提拔成主节点, 继续给整个 redis 集群提供⽀持.
具体流程如下:
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 算法, 是⼀种在分布式系统中⼴泛使⽤的算法. 在随机休眠时间的加持下, 基本上就是谁先唤醒, 谁就能竞选成功.

注意和哨兵的区别,哨兵实现出leader,leader负责找一个从节点升级成主节点.而集群是直接投票选出新的主节点.


集群扩容

101-109九个主机,构成了3主6从结构的集群.

现在将110和111两个节点也加入到集群当中,以110为主节点,111为从节点,同时数据分片从3变为4.

1.新的主节点110加入到集群中

redis-cli --cluster add-node 172.30.0.110:6379 172.30.0.101:6379

add-node后的第一组地址是新节点的地址,第二组地址是集群中任意节点的地址,代表整个集群.

此时通过cluster nodes命令查看到110已经成为主节点了,但是还有槽位分配给它.

2.重新分配slots

把之前三组的master上面的槽位各自分出一些来,给到新的主节点.

redis-cli --cluster reshard 172.30.0.101:6379

reshard后的地址是集群中任意节点的地址,reshard代表重新切分的意思.

执行此命令之后,会进入交互式操作,redis会提示用户输入以下内容:

1).多少个slots要进行reshard?

此处我们填写4096.

2).哪个节点接收这些slots?

此处我们填写172.30.0.110这个节点的集群节点的id,上方会有打印,直接粘贴即可.

3).这些slots从哪些节点搬运过来?

此处我们填写all,意思是每个主节点都分一些槽位过来.

也可以手动指定,从某一个或者某几个节点来移动slots,输入以done结尾.

当输入all之后,给出的搬运计划还没有真正开始,当输入yes之后,搬运才真正开始.

此时不仅仅是slots的重新划分,也会把slots上对应的数据,也搬运到新的主机上,这是比较重量的操作!!!

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

搬运完成后,就可以看到它的槽位信息了.

3.给新的主节点添加从节点

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

redis-cli --cluster add-node 172.30.0.111:6379 172.30.0.101:6379 --cluster-slave --cluster-master-id [172.30.0.110节点的nodeid]

从节点添加完毕!!!


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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

一体化污水处理设备材质怎么选

在环保意识日益增强的今天&#xff0c;污水处理设备成为城市建设过程中的重要环节。而选择合适的一体化污水处理设备材质&#xff0c;则成为了一项重要的决策。本文将从专业的角度出发&#xff0c;为您解析一体化污水处理设备材质的选取。 首先&#xff0c;一体化污水处理设备材…

css:flex布局中子元素高度height没有达到100%

目录 问题flex布局示例解决办法方式一方式二 参考 问题 css中使用flex布局中子元素高度height没有达到100% flex布局示例 希望实现两个盒子左右分布&#xff0c;内容垂直居中对齐 <style>.box {display: flex;align-items: center;border: 1px solid #eeeeee;}.box-l…

信息系统安全运维服务资质认证申报流程详解

随着我国信息化和信息安全保障工作的不断深入&#xff0c;以应急处理、风险评估、灾难恢复、系统测评、安全运维、安全审计、安全培训和安全咨询等为主要内容的信息安全服务在信息安全保障中的作用日益突出。加强和规范信息安全服务资质管理已成为信息安全管理的重要基础性工作…

群晖Docker搭建HomeAssistant,结合内网穿透实现远程访问智能家居控制中心

使用群晖Docker搭建HomeAssistant并实现异地公网访问 文章目录 使用群晖Docker搭建HomeAssistant并实现异地公网访问一、下载HomeAssistant镜像二、内网穿透HomeAssistant&#xff0c;实现异地控制智能家居三、使用固定域名访问HomeAssistant HomeAssistant是一个可以控制 苹果…

苍穹外卖项目笔记(7)— 微信登录、商品浏览

前言 苍穹外卖项目代码&#xff1a;https://github.com/Echo0701/take-out 1 HttpClient 1.1 介绍 HttpClient 是 Apche Jakarta Common 下的子项目&#xff0c;可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包&#xff0c;并且支持 HTTP 协议最新…

[LeetCode周赛复盘] 第 374 场周赛20231203

[LeetCode周赛复盘] 第 374 场周赛20231203 一、本周周赛总结100144. 找出峰值1. 题目描述2. 思路分析3. 代码实现 100153. 需要添加的硬币的最小数量1. 题目描述2. 思路分析3. 代码实现 100145. 统计完全子字符串1. 题目描述2. 思路分析3. 代码实现 100146. 统计感冒序列的数…

LeetCode Hot100 994.腐烂的橘子

题目&#xff1a; 在给定的 m x n 网格 grid 中&#xff0c;每个单元格可以有以下三个值之一&#xff1a; 值 0 代表空单元格&#xff1b;值 1 代表新鲜橘子&#xff1b;值 2 代表腐烂的橘子。 每分钟&#xff0c;腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。 返回…

计算机速成课Crash Course - 08. 指令和程序

今天开始计算机速成课Crash Course的系列讲解。 更多技术文章&#xff0c;全网首发公众号 “摸鱼IT” 锁定 -上午11点 - &#xff0c;感谢大家关注、转发、点赞&#xff01; 计算机速成课Crash Course - 08. 指令和程序 08. 指令和程序 上集我们把 ALU, 控制单元, RAM, 时钟…

观测云实现日志存储与分析 10 倍性价比提升|SelectDB 技术团队

作者&#xff1a;观测云 CEO 蒋烁淼 & 飞轮科技技术团队 在云计算逐渐成熟的当下&#xff0c;越来越多的企业开始将业务迁移到云端&#xff0c;传统的监控和故障排查方法已经无法满足企业的需求。而观测云可提供整体数据的分析、洞察、可视化、自动化、监测告警、智能巡查…

单周爆售150w+,“不是羽绒服买不起,而是军大衣更有性价比”

拼多多收盘市值超过阿里&#xff0c;成在美中概股市值第一。 截至美股收盘&#xff08;11月30日&#xff09;&#xff0c;拼多多收盘市值超过阿里巴巴&#xff0c;成为在美中概股中的市值第一股。拼多多收涨4.03%&#xff0c;报147.44美元&#xff0c;市值1959亿美元&#xff…

Tiled Matrix Multiplication

if(true) { (function(i,s,o,g,r,a,m){i[‘GoogleAnalyticsObject’]r;i[r]i[r]||function(){ (i[r].qi[r].q||[]).push(arguments)},i[r].l1*new Date();as.createElement(o), ms.getElementsByTagName(o)[0];a.async1;a.srcg;m.parentNode.insertBefore(a,m) })(window,docum…

uniapp微信小程序分包,小程序分包

前言&#xff0c;都知道我是一个后端开发、所以今天来写一下uniapp。 起因是美工给我的切图太大&#xff0c;微信小程序不让了&#xff0c;在网上找了一大堆分包的文章&#xff0c;我心思我照着写的啊&#xff0c;怎么就一直报错呢&#xff1f; 错误原因 tabBar的页面被我放在分…

五肽-13|提亮肤色,美白肌肤

五肽-13 INCI名称&#xff1a;五肽-13 说明&#xff1a; 五肽-13是一种合成肽&#xff0c;由丙氨酸、精氨酸、赖氨酸、脯氨酸和缬氨酸组成 功能&#xff1a; 五肽-13起到增白剂的作用 应用程序&#xff1a; 提亮和美白

2023年2月8日 Go生态洞察:Profile-Guided Optimization预览

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

Streamlit框架的定制化

Streamlit框架的定制化 最近做了一个关于streamlit框架的项目&#xff0c;颇有感触&#xff0c;所以在这里记录一下。 什么是streamlit? Streamlit 是一个python的WEB UI库&#xff0c;它做了高度的封装以便于不懂后前端开发的人员也能轻松构建画面。你可以从官网进行详细的…

Linux文件结构与文件权限

基于centos了解Linux文件结构 了解一下文件类型 Linux采用的一切皆文件的思想&#xff0c;将硬件设备、软件等所有数据信息都以文件的形式呈现在用户面前&#xff0c;这就使得我们对计算机的管理更加方便。所以本篇文章会对Linux操作系统的文件结构和文件权限进行讲解。 首先…

halcon如何设置窗口背景颜色?

halcon窗口背景默认是黑色&#xff0c;有时候图片背景是黑色&#xff0c;不方便观察边缘&#xff0c;如果需要设置窗口背景颜色&#xff0c;可以使用如下算子。 设置窗口背景颜色&#xff1a;白色 set_window_param (WindowHandle, background_color, white) 设置白色后的效…

13款趣味性不错(炫酷)的前端动画特效及源码(预览获取)分享(附源码)

文字激光打印特效 基于canvas实现的动画特效&#xff0c;你既可以设置初始的打印文字也可以在下方输入文字可实现激光字体打印&#xff0c;精简易用。 预览获取 核心代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8&q…

关于 mapboxgl 的常用方法及效果

给地图标记点 实现效果 /*** 在地图上添加标记点* point: [lng, lat]* color: #83f7a0*/addMarkerOnMap(point, color #83f7a0) {const marker new mapboxgl.Marker({draggable: false,color: color,}).setLngLat(point).addTo(this.map);this.markersList.push(marker);},…

从【注意力机制】开始的,零基础【大模型】系列

注意力机制 原理&#xff1a;从关注全部到关注重点软注意力-计算方式传统注意力问题 键值注意力&#xff1a;单标签的检索系统计算方式 多头注意力&#xff1a;多标签的检索系统自注意力&#xff1a;对输入数据内部关系进行预处理计算方式 Transformer 原理&#xff1a;从关注全…