Redis之持久化、集群

1. Redis持久化

Redis为什么需要持久化?因为Redis的数据我们都知道是存放在内存中的,那么每次关闭或者机器断电,我们的数据旧丢失了。

因此,Redis如果想要被别人使用,这个问题就需要解决,怎么解决呢?就是说我们的数据要同步到磁盘,只有同步到磁盘中了,数据才不会丢失,然后我们启动的时候,内存从磁盘里再加载数据,这样就既能满足基于内存的操作,保证性能,同时也尽可能的防止了数据的丢失。

那么Redis做持久化的方式有哪些呢? RDB和AOF

1.1 RDB

RDB是Redis默认的持久化方案,当满足一定条件的时候,会把当前内存中的数据写入磁盘,生成一个快照文件dump.rdb(默认)

可配置RDB文件的文件名与路径:

# The filename where to dump the DB
dbfilename dump . rdb //dunmp.rdb 文件名
dir . / // 文件路径

那么RDB什么时候会触发呢?

  • 自动触发
    • 配置触发
save 900 1 900 s 检查一次,至少有 1 key 被修改就触发
save 300 10 300 s 检查一次,至少有 10 key 被修改就触发
save 60 10000 60 s 检查一次,至少有 10000 key 被修改
  • shutdown正常关闭;
任何组件,在正常关闭的时候,都会去完成该完成的事情,比如 Mysql中的Redolog 持久化 正常关闭的时候也会去持久化。
  •  flushall指令触发
数据清空指令会触发 RDB 操作,并且是触发一个空的 RDB 文件,所以, 如果在没有开启其他的持久化的时候,flushall 是可以删库跑路的,在 生产环境慎用。
  • 手工触发
    • save 主线程去进行备份,备份期间不会去处理其它的指令,其它指令必须等待
    • bgsave 子线程去进行备份,其它指令正常执行

操作实例演示:

a.我们首先添加一份数据并且备份到RDB

redis > set k1 1
redis > set k2 2
redis > set k3 3

 b.查看数据是否存在

redis > keys *

c.进行shutdown操作触发RDB快照

 redis> shutdown

 d.对现有RDB数据进行备份cp

redis > cp dump . rdb dump . rdb . bak

 e 启动redis

redis > src / redis - server & redis . conf

 发现数据都还在

f. 现在模拟数据丢失

redis > flushall

 g. 停服务器再启动

redis > shutdown
redis > src / redis - server & redis . conf

h. 此时发现数据已经丢失,现在就要从我们备份的数据恢复,先关闭

 redis> shutdown

 i.删除原RDB备份数据

redis > rm dump . rdb

j 将备份数据改名为bump.rdb

 mv dump.rdb.bak dump.rdb

k.  重启服务

src / redis - server & redis . conf

 我们发现数据已经恢复

思考:我们的数据是怎么备份到RDB中的呢?

1. 新起子线程,子线程会将当前 Redis 的数据写入一个临时文件
2. 当临时文件写完成后,会替换旧的 RDB 文件。
Redis 启动的时候,如果只开启了 RDB 持久化,会从 RDB 文件中加载数据。

 RDB的优势:

1. 是个非常紧凑型的文件,非常适合备份与灾难恢复。
2. 最大限度的提升了性能,会 fork 一个子进程,父进程永远不会产于磁盘IO或者类似操作。
3. 更快的重启。

简单总结一句话,RDB恢复与备份都非常的快

RDB的不足

 1.数据安全性不是很高,因为是根据配置的时间来备份,假如每5分钟备份 一次,也会有5分钟数据的丢失

2. 经常 fork 子进程,所以比较耗 CPU ,对 CPU 不是很友好。 

1.2 AOF

由于RDB的数据可靠性非常低,所以Redis又提供了另外一种持久化方案: Append Only File 简称 AOF

AOF默认是关闭的,你可以在配置文件中进行开启 (追加文件,即每次更改的命令都会附加到我的AOF文件中)

appendonly no // 默认关闭,可以进行开启
# The name of the append only file ( default : "appendonly.aof" )
appendfilename "appendonly.aof" //AOF 文件名

 1.2.1同步机制

AOF, 会记录每个写的操作,那么问题来了?我难道每次操作命令又得跟磁盘交互呢?不跟mysql 一样每次需要跟磁盘交互呢?
当然不行,所以, redis 支持几种策略,由你们自己来决定要不要每次都跟磁盘交互
# appendfsync always 表示每次写入都执行 fsync( 刷新 ) 函数 性能会非常非常慢 但是非常安全
appendfsync everysec 每秒执行一次 fsync 函数 可能丢失 1s 的数据
# appendfsync no 由操作系统保证数据同步到磁盘,速度最快 你的数据只需要交给操作系统就行
默认1s一次,最多有1s的数据丢失

1.2.2 重写机制

由于AOF是追加的形式,所以文件会越来越大,越大的话,数据加载越慢。所以我们需要对AOF文件进行重写。

那么什么是重写呢?

比如 我们的 incr 指令,假如我们 incr 100 次,现在数据是 100 ,但是我们的aof 文件中会有 100 incr 指令,但是我们发现这个 100 条指令用处不大,假如我们能把最新的内存里的数据保存下来的话。
所以,重写就是做了这么一件事情,把当前内存的数据重写下来,然后把
之前的追加的文件删除。

重写流程(Redis7之前)

1. Redis fork 一个子进程,在一个临时文件中写入新的 AOF (当前内存的数据生成的新的AOF
2. 那么在写入新的 AOF 的时候,主进程还会有指令进入,那么主进程会在内存缓存区中累计新的指令 (但是同时也会写在旧的AOF 文件中,就算重写失败,也不会导致AOF 损坏或者数据丢失)
3. 如果子进程重写完成,父进程会收到完成信号,并且把内存缓存中的指令追加到新的AOF 文件中
4. 替换旧的 AOF 文件 ,并且将新的指令附加到重写好的 AOF 文件中。

 什么时候进行重写(根据配置)

# 重写触发机制
auto - aof - rewrite - percentage 100
auto - aof - rewrite - min - size 64 mb 就算达到了第一个百分比的大小,也必须大于 64 M

 说明:在aof文件小于64mb的时候不进行重写,当到达64mb的时候,就重写一次。重写后的aof文件可能是40mb.上面配置了auto-aof-rewrite-percentage为100,即aof文件到了80mb的时候进行重写

1.2.3 AOF的优势与不足

优势

1. 安全性高,就算默认的持久化同步机制,也最多只会导致 1s 丢失。
2.AOF 由于某些原因,比如磁盘满了等导致追加失败,也能通过 redis
check-aof 工具来修复   ./redis-check-aof --fix append
3. 格式都是追加的日志,所以可读性更高

不足

1. 数据集一般比 RDB
2. 持久化跟数据加载比 RDB 更慢
3. 7.0 之前,重写的时候,因为重写的时候,新的指令会缓存在内存区,所以会导致大量的内存使用
4. 并且重写期间,会跟磁盘进行 2 IO ,一个是写入老的 AOF 文件,一个 是写入新的AOF 文件

2.Redis集群

2.1 Redis主从

为什么要有主从?

1. 故障恢复 主挂了或者数据丢失了,我从还会有数据冗余
2. 负载均衡,流量分发 我们可以主写,从库读,减少单实例的读写压力
3. 高可用 我们等下讲的集群 等等,都是基于主从去实现的

 安装教程后续会单独出文章

我们现在已经安装了一个主从,先看下基本信息

主:

127.0 . 0.1 : 6379 > info replication
# Replication
role : master // 角色
connected_slaves : 1 // 从节点数量
slave0 : ip = 192.168 . 8.127 , port = 6379 , state = online , offset = 7889
9 , lag = 1 // 从节点的信息 状态 偏移量
master_replid : 04f4969 ab63ce124e870fa1e4920942a5b3448e7
//# master 启动时生成的 40 16 进制的随机字符串,用来标识 master 节点
master_replid2 : 0000000000000000000000000000000000000000
master_repl_offset : 78899 //mater 已写入的偏移量
second_repl_offset : - 1
repl_backlog_active : 1
repl_backlog_size : 1048576 // 缓冲区大小
repl_backlog_first_byte_offset : 1
repl_backlog_histlen : 78899 // 缓冲区的数据已有大小(是个环形,跟RedoLog一样会覆盖)

从:

 127.0.0.1:6379> info replication

# Replication
role : slave // 角色
master_host : 192.168 . 8.129 // 主节点 IP
master_port : 6379 // 主节点端口
master_link_status : up // 连接状态 up 是正常同步连接状态 down
示复制端口
master_last_io_seconds_ago : 1 // 主库多少秒没有发送数据到从库 0-
10
master_sync_in_progress : 0 // 是否正在跟主服务同步
slave_repl_offset : 163 // 从节点偏移量
slave_priority : 100 // 选举时成为主节点的优先级 越大优先级越高 0不会成为主节点
slave_read_only : 1 // 是否为只读从库 如果不是只读,则能自己进行数据写入,默认是只读
connected_slaves : 0 // 连接的从库实例
master_replid : 04f4969 ab63ce124e870fa1e4920942a5b3448e7
//master 启动时生成的 40 16 进制的随机字符串,用来标识 master 节点
master_replid2 : 0000000000000000000000000000000000000000
//slave 切换 master 之后,会生成了自己的 master 标识,之前的 master 节点的标识存到了master_replid2 的位置
master_repl_offset : 163 // 已写入偏移量
second_repl_offset : - 1
repl_backlog_active : 1
repl_backlog_size : 1048576 // 复制积压的缓存区大小
repl_backlog_first_byte_offset : 1
repl_backlog_histlen : 163

 2.1.1 主从数据同步

我们发现,我们的信息中,有个slave_read_only,如果是1代表只读。也就是默认,当然也可以配置成写,但是写的数据不会同步到主库,需要自己去保证数据的一致性,可能从库写的数据会被主库的数据操作覆盖。出现从库set一个值后,获取到的是主库覆盖的数据。

举例:

127.0 . 0.1 : 6379 > set k1 2 // 从库设置 k1 2

 127.0.0.1:6379> set k1 3 //主库设置k13 并且会同步到从库

 127.0.0.1:6379> get k1

"3"     // 从库得到的是主库设置的值

 思考:  我们主库的数据是怎么同步到从库的呢?同步过程是怎么样的?或者主从数据是怎么保证一致性的。

a.建立连接

当首次成为主节点的从节点时,执行 replicaof ip port 命令的时候就会保存主服务器的IP 与端口
并且与主服务器建立连接,接收主节点返回的命令
判断主节点是否有密码 如果有 进行权限校验
保证主从之前保存了各自的信息,并正常连接。

b.slave发起同步master数据指令

在slave的serverCron方法调用replicationCron方法,里面会发起跟master的数据同步

run_with_period ( 1000 ) replicationCron ();

 b.1 全量同步

1. master 服务器收到 slave 的命令后( psync ),判断 slave 传给我的master_replid 是否跟我的 replid 一致,如果不一致或者传的是个空的,那么就需要全量同步。
2. slave 首次关联 master ,从主同步数据, slave 肯定是没有主的 replid, 所以需要进行全量同步。
3. 进行全量同步
        3.1. master开始执行 bgsave ,生成一个 RDB 文件,并且把 RDB 文件传输给我们的slave ,同时把 master replid 以及 offerset master 的数据进度,处理完命令后,都会写入自身的offerset
        3.2. slave接收到 rdb 文件后,清空 slave 自己内存中的数据,然后用 rdb来加载数据,这样保证了slave 拿到的数据是 master 生成 rdb 时候的最新数据。
        3.3. 由于 master 生成 RDB 文件是用的 bgsave 生成,所以,在生成文件的时候,是可以接收新的指令的。那么这些指令,我们需要找一个地方保存,等到slave 加载完 RDB 文件以后要同步给 slave
                3.2.1. 在master 生成 rdb 文件期间,会接收新的指令,这些新的指令会保存在一个内存区间,这个内存区间就是replication_buffer
                3.2.2. 这个空间不能太小,如果太小,为了数据安全,会关闭跟从库的网络连接。再次连接得重新全量同步,但是问题还在,会导致无限的在同步

 replication_buffer大小的设置

client - output - buffer - limit replica 256 mb 64 mb 60  256 mb 硬性限制,大于 256M 断开连接
64 mb 60 软限制 超过 64M 并且超过了 60s 还没进行同步 内存数据就会断开连接

 b.2 增量同步

为什么需要增量同步?

这是因为每个节点都会保存数据的偏移量,那么就有可能出现slave跟master网络断开一小会,然后发起数据同步的场景,如图所示:

 slave1由于网络断开了,偏移量跟master相差了3.

那么当slave1重新跟master连接后,同样的会去跟master连接触发数据同步。但是这个时候还需不需要全量同步了?我们肯定是尽可能的减少全量同步。

所以,当master收到slave的指令时:

1. 判断 slave1 传给我的 master_replid 是否跟 master replid 一致,由于之前已经连接过保过了master replid ,满足条件。
2. 所以我希望只同步断开连接后没有同步到的数据,必须,我 slave1 只差 了3 的数据。那么我需要找到这个 3 的数据。所以 master 中有个另外的积压缓(replication_backlog_buffer )。
我们也不可能无限制的往里面写数据, replication_backlog_buffer 的数据是会覆盖的。
3. 所以,我们 slave1 master 相差的 3 条数据可能会被覆盖,如果覆盖了,触发全量,如果没有覆盖,即能找到相差的3 条数据。增量即可。

 replication_backlog_buffer的配置

# The bigger the replication backlog , the longer the
time the replica can be 复制积压越大,复制副本的时间越长
# disconnected and later be able to perform a partial
resynchronization . 已断开连接,稍后可以执行部分重新同步。
#
# The backlog is only allocated once there is at least
a replica connected . 只有在至少连接了一个副本后,才会分配积压工 作。
#
# repl - backlog - size 1 mb

 b.3 指令同步

master写入的指令,异步同步给slave,如果有slave,写入replication_backlog

_buffer

整体主从数据同步流程图: Redis主从同步策略| ProcessOn免费在线作图,在线流程图,在线思维导图

2.2 Sentinel哨兵

主从,虽然解决了比如负载、数据备份等问题。但是我们发现如果master挂了,slave不会直接升级为主,必须手动把slave升级为主。这样肯定人为维护的成本比较高。所以我们希望能有一个技术帮我们实现这样的需求,于是就有了哨兵集群。

什么是哨兵集群?

Redis sentinel 在不适用 Cluster 集群的时候,为 Redis 提供了高可用性。
并且提供了监测、通知、自动故障转移、配置提供等功能。
监控 :能够监控我的 Redis 各实例是否正常工作
通知 :如果 Redis 的实例出现问题,能够通知给其他实例以及 sentinel
自动故障转移 :当我的 master 宕机, slave 可以自动升级为 master
配置提供 sentinel 可以提供 Redis master 实例地址,那么客户端只需要跟sentinel 进行连接, master 挂了后会提供新的 master

其实sentinel是独立于Redis服务的单独的服务,并且它们之间是相互通信的。

2.2.1 哨兵故障转移流程

我们的哨兵到底是怎么去发现我们的master挂了的呢?挂了后让slave变成Master的整个流程是咋样的呢?

a。发现master故障

1. 当我们某个 sentinel master 通信时(默认 1s 发送 ping ),发现我在 一定时间内(down-after-milliseconds ) 没有收到 master 的有效的回复。这个时候这个sentinel 就会人为 master 是不可用,但是有多个sentinel,它现在只有 1个人觉得宕机了,这个时候不会触发故障转移,
只会标记一个状态,这个状态就是 SDOWN Subjectively Down condition ),也就是我们讲的主观下线
2. SDOWN 时,不会触发故障转移,会去询问其他的 sentinel ,其他的sentinel是否能连上 master ,如果超过 Quorum( 法定人数 ) sentinel 都认为master 不可用,都标记 SDOWN 状态,这个时候, master 可能就真的是down 了。那么就会将 master 标为 ODOWN Objectively Down condition 客观下线)

b. 进行故障转移

1. 当状态为 ODWON 的时候,我们就需要去触发故障转移,但是有这么多 的sentinel ,我们需要选一个 sentinel 去做故障转移这件事情,并且这 个sentinel 在做故障转移的时候,其他 sentinel 不能进行故障转移
2. 所以,我们需要选举一个 sentinel 来做这件事情 : 其中这个选举过程有 2个因素。
        2.1  Quorum 如果小于等于一半,那么必须超过半数的 sentinel 授权,你才能去做故障迁移,比如5 sentinel ,你配置的 Quorum=2 ,那么选举的时候必须有3 5 台的一半以上)人同意
        2.2. Quorum如果大于一半,那么必须 Quorum sentinel 授权,故障迁移才能启动。

 c.选哪个slave来变成master

1. master 的断开连接时间
如果 slave 与主服务器断开的连接时间超过主服务器配置的超时时间 (down-after-milliseconds )的十倍,被认为不适合成为 master 。直接去除资格
2. 优先级
配置 replica-priority replica-priority 越小,优先级越高,但是配置为0的时候,永远没有资格升为 master
3. 已复制的偏移量
比较 slave 的赋值的数据偏移量,数据最新的优先升级为 master
4. Run ID (每个实例启动都会有个 Run ID
通过 info server 可以查看。

2.2.2 Sentinel导致的数据一致性问题

官方建议配置至少3个sentinel

原因如下:

1. 如果只有 1 sentinel 实例,则这个实例挂了就不能保证 sentinel 的高可用性。
2. 如果,我配置了 2 sentinel ,分别在 127 跟128.n并且我配置的quorum=1 ;就可能发生
        2.1.sentinel2检测到 master 不可用,因为 127 128 网络断开,这个时候会触发主观下线,同时,sentinel2 只能连接到 1 sentinel ,也满足半数以上原则(只有1 sentinel2
        2.2.sentinel2开启故障转移,将 128 slave 升级为 master, 就出现了 2 个master,这个情况也叫作脑裂。并且客户端会连接到 2 master 。 (客户端连的是sentinel 集群,所以 sentinel1 连到 127.sentinel2 连到 128
        2.3  2 master 都会写入数据,当网络恢复后, 127 会变成从, 127 的数据会
128 去拿取,这个时候 127 的数据就会丢失

2.2.3 脑裂问题

脑裂问题其实就是我会有2个master,client会从不同的master写数据,从而在master恢复的时候会导致数据丢失。

所以只要发生分区容错性,不管多少节点都会出现,比如3个节点。

初始 129 master, 假如 129 网络断开,跟 127.128 连接断开后, 128sentinel发起故障转移。发现 sentinel 的个数超过一半,能够发起故障 转移。将128 升级为 master ,导致 128.129 同时 2 master 并可用

解决方案:

在Redis.cfgt文件中有2个配置:

min - replicas - to - write 1 至少有 1 个从节点同步到我主节点的数据,但是由于是异步同步,所以是最终一致性 不会确保有数据写入
min - replicas - max - lag 10 判断上面 1 个的延迟时间必须小于等于 10s

 按上述场景

129由于没有slave同步,不满足我配置的要求,不能进行数据写入。尽量减少数据一致性问题。

思考,为什么部署奇数台?一因为4跟3 能容许挂掉的机器数量是一样的,都是1台

2.3 Redis Cluster

我们发现sentinel提供了比如监控、自动故障转移、客户端配置等高可用的方案,但是没有分片功能。

何为分片:就是我希望把数据分别到不同的节点。这样如果某些节点异常,其它数据能正常提供服务,跟我们微服务的思想很相似。

所以我们cluster就提供了这样的解决方案

1. 多个节点之间的数据拆分,也就是我们的数据分片
2. 当某些节点遇到故障的时候,其他的节点还能继续服务。

 2.3.1 hash slot(虚拟槽)

那么如何进行分片?分片要做的事情就是把不同的数据放到不同的实例里面去。就相当于我们分表,不同的数据放到不同的表里。

普通取模问题

取模 直接取模实例数,得到 key hash 值,取模实例数,假如实例是 3 ,那么取模后得到0-2 的值,每个值代表一个实例。
但是这种取模有一个问题,假如我做了实例的扩容与缩容,那么全部数据要进行迁移。
假如我之前是 3 台,扩容到 4 台,那么所有的数据都必须重新 rehash
所以, Redis 里面提出了一个 Hash 槽,也叫作虚拟槽的概念。什么是虚拟槽,其实就是虚拟节点。
Redis cluster 中有 16384 个虚拟槽

我们的key会跟槽对应,怎么对应?

根据key通过CRC16取模16383得到一个0到16383的值,计算公式:slot=CRC16(key)&16383,得到的值,就代表这个key在哪个虚拟槽。

举例:

假如
set k1 1 :
CRC16 ( k1 ) & 16383 = 11901
set k2 1 :
CRC16 ( k2 ) & 16383 = 10
set k3 1 :
CRC16 ( k3 ) & 16383 = 6666
那么我们 k1 对应的槽是 11901 k2 对应的槽是 10 k3 对应的槽是 6666

key跟槽的关系是根据key算出来的,后续不能变动。

如果想把相关keu放入一个虚拟槽,也就是一个实例节点,我们可以采用{},那么就只会根据{}里面的内容计算hash槽!

比如: zsc{18}跟james{18}就会在一个虚拟槽

那么key怎么去放到我们的真实节点?

假设我们现在有6台实例,三主三从。主跟槽的对应关系如下:
master1 0-5460 虚拟槽
master2 5461-10922 虚拟槽
master3 10923-16383 虚拟槽

 我们知道,k1的虚拟槽是10001,所以放到master3,依次类推,k2放到master1,k3放到mster2

从节点的数据全部来源于主,所以k1放入master3的从,以此对应。

127.0.0.1:6380> cluster nodes 查看当前节点的虚拟槽信息

这样,每次节点的扩容与缩容,只需要改变节点跟虚拟槽的关系即可,不需要全部变动。

3. 总结

        redis是内存型数据库,因此每次机器关机都会清理内存,因此,要想保证redis的可用性,就需要持久化技术,redis持久化分为RDB快照和AOF追加两种形式; 但是为了高可用,流量的分发以及为了应对redis挂了之后的可用性,引入了主从,主从之间就又设计到了数据的全量同步和增量同步;随后,为了更进一步的将主从切换智能化,提出了sentinel哨兵模式,可用监控主的状态,采用一定的策略,保证主挂了以后从可以升级为主;最后是为了更进一步提升redis的高可用,采用集群的方案,将redis数据分布到不同的节点进行管理。

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

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

相关文章

深度解析:从概念到变革——Transformer大模型的前世今生以及大模型预备知识讲解[知存科技]

深度解析:从概念到变革——Transformer大模型的前世今生 点击:知存科技相关课程推荐 知存科技是全球领先的存内计算芯片企业。针对AI应用场景,在全球率先商业化量产基于存内计算技术的神经网络芯片。凭借颠覆性的技术创新,知存科…

小米投屏怎么投?收好这3个投屏指南!(2024新)

近年来,小米凭借过硬的品质和合理的价格成为手机市场的一股强劲力量。随着其销量的上升,人们可以通过多种方式使用它来获得乐趣和便利。比如小米MIUI 11自带一个“光环”——Miracast,可以让用户在电脑上控制小米/红米/小米,获得更…

conda创建虚拟环境并激活

1 conda activate base 2 conda creat -n aaa python** 3 conda activate aaa 4 interpreter里面去选择刚搞好的编译器 ...../conda.exe

软考随记(二)

I/O系统的5种不同的工作方式: 程序控制方式: 无条件查询:I/O端口总是准备好接受主机的输出数据,或是总是准备好向主机输入数据,而CPU在需要时随时直接利用I/O指令访问相应的I/O端口,实现与外设的数据交换 …

9.Halcon3D点云力矩求解-平面拟合用法

1.实现效果 我们在使用3d相机对产品进行扫描生成点云的时候,由于安装问题,所以我们不可能保证每次产品扫描出来都在坐标系中位置和姿态非常标准。 上述算法描述的就是在某一个维度或者某几个维度上将点云数据和坐标系对齐; 至于怎么对齐,如何实现就是今天的内容。 本人能…

【UE5.1 角色练习】10-物体抬升、抛出技能 - part2

目录 前言 效果 步骤 一、让物体缓慢的飞向手掌 二、向着鼠标方向发射物体 前言 在上一篇(【UE5.1 角色练习】08-物体抬升、抛出技能 - part1)的基础上继续完成角色将物体吸向手掌,然后通过鼠标点击的方向来发射物体的功能。 效果 步骤…

华为 CANN

华为 CANN 1 介绍1.1 概述1.2 CANN 是华为昇腾计算产业的重要一环1.3 昇腾系列处理器1.4 昇腾 AI 产业1.5 从 AI 算法到产品化落地流程1.6 多样性计算架构1.7 人工智能各层级图示1.8 人工智能技术发展历史 2 CANN vs CUDA支持平台优化方向编程接口生态系统与应用性能与功能 3 C…

民国漫画杂志《时代漫画》第36期.PDF

时代漫画36.PDF: https://url03.ctfile.com/f/1779803-1248636233-8a4a9d?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了,截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

day23--单元测试-反射-注解-动态代理

day23-单元测试、反射 恭喜同学们,Java主要的知识我们其实已经学习得差不多了。今天同学们再把单元测试、反射、注解、动态代理学习完。Java的基础知识就算全齐活了。 首先,我们进入单元测试的学习。 一、单元测试 1.1 单元测试快速入门 所谓单元测…

mimkatz获取windows10明文密码

目录 mimkatz获取windows10明文密码原理 lsass.exe进程的作用 mimikatz的工作机制 Windows 10的特殊情况 实验 实验环境 实验工具 实验步骤 首先根据版本选择相应的mimikatz 使用管理员身份运行cmd 修改注册表 ​编辑 重启 重启电脑后打开mimikatz 在cmd切换到mi…

相同的树(oj题)

一、题目链接https://leetcxode-cn.com/problems/same-tree/ 二、题目思路 遍历整颗树,判断两棵树的每个位置的结点都相同。 每个结点的左右孩子结点都要综合判断 三、题解代码 bool isSameTree(struct TreeNode* p, struct TreeNode* q) {//如果两颗树的根结点…

MVC、MVP 和 MVVM 架构总结

MVC、MVP 和 MVVM 是常见的软件架构模式,主要用于组织应用程序的结构,特别是在用户界面和业务逻辑之间进行分离。以下是对它们的详细解释,包括它们的差异、优缺点。 MVC(Model-View-Controller) 结构 Model&#xf…

unicloud 云对象

背景和优势 20年前,restful接口开发开始流行,服务器编写接口,客户端调用接口,传输json。 现在,替代restful的新模式来了。 云对象,服务器编写API,客户端调用API,不再开发传输json…

万字长文详解QUIC协议,为什么有了TCP我们还需要QUIC?

本文目录 1.前言2. HTTP缺点缺点一:建立连接的握手延迟大缺点二:多路复用的队首阻塞缺点三:TCP协议的更新滞后 3.TCP缺点3.QUIC优点一:避免队首阻塞的多路复用优点二:支持连接迁移优点三:可插拔的拥塞控制优…

TiDB-从0到1-MVCC

TiDB从0到1系列 TiDB-从0到1-体系结构TiDB-从0到1-分布式存储TiDB-从0到1-分布式事务TiDB-从0到1-MVCC 一、MVCC Multi-Version Concurrency Control 多版本并发控制,其主要解决了读并发的问题。 其维持一个数据的多个版本使读写操作没有冲突。也就是说数据元素X…

多维数组操作,不要再用遍历循环foreach了!来试试数组展平的小妙招!array.flat()用法与array.flatMap() 用法及二者差异详解

目录 一、array.flat()方法 1.1、array.flat()的语法及使用 ①语法 ②返回值 ③用途 二、array.flatMap() 方法 2.1、array.flatMap()的语法及作用 ①语法 ②返回值 ③用途 三、array.flat()与a…

Android MediaCodec 简明教程(九):使用 MediaCodec 解码到纹理,使用 OpenGL ES 进行处理,并编码为 MP4 文件

系列文章目录 Android MediaCodec 简明教程(一):使用 MediaCodecList 查询 Codec 信息,并创建 MediaCodec 编解码器Android MediaCodec 简明教程(二):使用 MediaCodecInfo.CodecCapabilities 查…

接入knife4j-openapi3访问/doc.html页面空白问题

大概率拦截器拦截下来了,我们F12看网络请求进行排查 都是 /webjars/ 路径下的资源被拦截了,只需在拦截器中添加该白名单即可"/webjars/**" 具体配置如下: Configuration public class WebConfig implements WebMvcConfigurer {priv…

百度智能云与博彦科技达成战略合作 共同推动千行百业智能化升级

5月30日,百度智能云与博彦科技签署战略合作协议,双方已经基于以百度智能云千帆大模型平台为核心的产品、解决方案,在市场拓展、集成开发、实施交付、运营运维等领域开展深度合作,未来将进一步共同推动大模型技术创新和行业应用落地…

【MySQL用户管理】

文章目录 1.用户信息2.创建用户3.删除用户4.修改用户密码5.给用户设置权限展示zhangsan用户的权限 6.回收权限 1.用户信息 host: 表示这个用户可以从哪个主机登陆,如果是localhost,表示只能从本机登陆 user: 用户名 authenticatio…