redis深入理解之实战

1、SpringBoot整合redis

1.1 导入相关依赖

<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

1.2 创建Jedis对象,调用API

直接使用

@Test
public void redisTestDemo() throws InterruptedException{String host = "127.0.0.1";int port = 6379;Jedis jedis = new Jedis(host, port);jedis.set("name", "hua");System.out.println("执行setAPI后,redis中的name对应的值是:"+jedis.get("name"));jedis.setex("name",20,"32");System.out.println("执行setex后,redis中的name对应的值是:"+jedis.get("name"));Thread.sleep(1000);System.out.println("线程睡一会后检查name生存时间为:");System.out.println(jedis.persist("name"));Thread.sleep(1002);System.out.println("再次线程休眠检查name是否存在");System.out.println(jedis.exists("name"));jedis.flushAll();System.out.println("执行flushAllAPI后,检查name Key是否存在");System.out.println(jedis.exists("name"));
}

使用配置文件的方式实现

redisConfig.properties

jedis.host=127.0.0.1
jedis.port=6379
#jedis.password=yourpassword
#jedis.timeout=5000

RedisConfig配置类

@Configuration
@PropertySource("classpath:redisConfig.properties")
public class JedisConfig {@Value("${jedis.host}")private String jdsHost;@Value("${jedis.port}")private Integer jdsPort;@Bean("jds")public Jedis getJedis(){return new Jedis(jdsHost,jdsPort);}

测试类

@Autowired
@Qualifier("jds")
private Jedis jedis;@Test
public void redisTestDemo() throws InterruptedException{jedis.set("name", "hua");System.out.println("执行setAPI后,redis中的name对应的值是:"+jedis.get("name"));jedis.setex("name",20,"32");System.out.println("执行setex后,redis中的name对应的值是:"+jedis.get("name"));Thread.sleep(1000);System.out.println("线程睡一会后检查name生存时间为:");System.out.println(jedis.persist("name"));Thread.sleep(1002);System.out.println("再次线程休眠检查name是否存在");System.out.println(jedis.exists("name"));jedis.flushAll();System.out.println("执行flushAllAPI后,检查name Key是否存在");System.out.println(jedis.exists("name"));
}

结果

2、redis分片机制

2.1 redis分片机制概述

1.业务需要:

由于单台redis内存容量是有限的,无法实现海量的数据实现缓存存储。

2.分片机制概述:

概念:由多个redis节点协助工作的机制就是redis的分片机制。

作用:是为了实现redis扩容。

特点:分片机制把该机制中包含的多台redis缓存服务器当做一个整体,即看做一台redis服务器使用。

缺点:当redis分片中一个节点宕机,则可能会影响整个服务的运行,redis分片没有实现高可用。

2.2 分片机制的实现

①文件配置

1.配制规划:准备3台redis

方式:一台redis启动需要一个redis配置文件。因此实现三台redis,只需三个redis.conf文件即可。

2.修改配置文件:使3台redis的端口各不相同,如果相同则必定不能同时启动三台redis。

修改内容示例:

port 6379

port 7640

port 7639

3. 启动每个redis端口

进入redis安装目录

redis-server.exe redis.windows7640.conf
redis-server.exe redis.windows7639.conf
redis-server.exe redis.windows.conf

②SpringBoot项目使用redis分片机制

  1. 直接使用
//redis分片机制的实现
@Test
public void redisShards(){List<JedisShardInfo> shards = new ArrayList<>();shards.add(new JedisShardInfo("localhost",6379));shards.add(new JedisShardInfo("localhost",7639));shards.add(new JedisShardInfo("localhost",7640));ShardedJedis sjedis = new ShardedJedis(shards);sjedis.setnx("z7", "redis分片操作7");sjedis.setnx("z8", "redis分片操作8");sjedis.setnx("z9", "redis分片操作9");System.out.println("z7:"+sjedis.get("z7"));System.out.println("z8:"+sjedis.get("z8"));System.out.println("z9:"+sjedis.get("z9"));
}
  1. 配置文件方式实现

redisConfig.properties配置文件

#配置redis分片中各节点信息
jedis.info=127.0.0.1:6379,127.0.0.1:7639,127.0.0.1:7640

RedisConfig配置类

@Value("${jedis.info}")
private String jdsInfo;@Bean
public ShardedJedis shardedJedis(){//第一步,获取分片机制整合的每台redis的信息,并封装成一个JedisSharedInfo对象List<JedisShardInfo> shards = new ArrayList<>();String[] jedisInfo = jdsInfo.split(",");for(String s: jedisInfo){String[] allSubStr = s.split(":");shards.add(new JedisShardInfo(allSubStr[0], Integer.parseInt(allSubStr[1])));}return new ShardedJedis(shards);
}

测试类

@Autowired
private ShardedJedis sjedis;//redis分片机制的实现@Testpublic void redisShards(){sjedis.setnx("z7", "redis分片操作7");sjedis.setnx("z8", "redis分片操作8");sjedis.setnx("z9", "redis分片操作9");System.out.println("z7:"+sjedis.get("z7"));System.out.println("z8:"+sjedis.get("z8"));System.out.println("z9:"+sjedis.get("z9"));}

结果

2.3 分片机制原理

  1. 一致性哈希算法:Redis的分片机制通常使用一致性哈希算法(Consistent Hashing)来实现。一致性哈希算法将所有的key映射到一个固定的区间上(通常是一个哈希环),然后将这个区间划分为多个片段(shard),每个片段对应一个Redis节点。当客户端请求一个key时,根据一致性哈希算法计算出该key应该属于哪个片段,并将请求发送到对应的节点上进行处理。
  2. 哈希分片:Redis的哈希分片是将键值对通过哈希函数映射到不同的Redis实例中。常用的哈希函数有CRC16和CRC32等。当客户端想要访问某个key时,它会先计算出这个key的哈希值,然后根据哈希值和哈希环的映射关系找到对应的节点进行操作。
  3. 哈希槽(Hash Slots):在Redis的Cluster集群模式中,使用哈希槽的方式来进行数据分片。整个数据集被划分为多个哈希槽,每个哈希槽分配给一个节点。客户端通过计算key的哈希值并取模哈希槽的总数,来确定key所属的哈希槽,进而找到对应的节点进行操作。
  4. 自动故障转移和数据迁移:Redis的分片机制还提供了自动的故障转移和数据迁移机制。当某个节点出现故障或需要扩容时,Redis可以自动地将数据从故障节点迁移到其他节点,以保证系统的可用性和可扩展性。

分片机制存储数据使用的机制:一致性hash算法。

应用场景

场景

N 个 cache 服务器(后面简称 cache ),将一个对象 object 映射到 N 个 cache 上,计算 出object 的 hash 值,均匀的映射到到 N 个 cache ,如key%N,key是object 的hash值,N是服务器节点数

出现的问题

如果有一个服务器加入或退出这个集群,则所有的数据映射都无效了,如果是持久化存储则要做数据迁移,如果是分布式缓存,则其他缓存就失效了

一个服务器宕机退出集群

所有映射到服务器节点的对象都会失效,服务器节点从集群中移除,这时候 集群 是 N-1 台,映射公式变成了 hash(object)%(N-1)

一个服务器加入集群

集群新加服务器节点,这时候 集群 是 N+1 台,映射公式变成了 hash(object)%(N+1) ,所有映射到服务器节点的对象都会失效

解决方案

一致性Hash算法

1.一致性hash算法概述

  • 目的:解决分布式缓存的问题。即解决了简单hash算法在分布式hash表中存在的动态伸缩等问题。
  • 作用:在移除或添加一个服务器时,能够尽可能小地改变已存在的服务语法与处理请求服务器之间的映射关系。

一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响

如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器)之间数据,其它数据也不会受到影响

2.redis分片机制的一致性hash算法的使用

  • 常规hash运算
    • 结果是由一个8位16进制数构成,共能表示2^32个可能性,根据计算机存储特性(即超出范围即从别一台开始),最后形成一个hash圆。
    • 核心:参与运算的内容,只要运算内容相同,所得的hash运算结果一定相同。
  • 常规hash运算
    • 结果是由一个8位16进制数构成,共能表示2^32个可能性,根据计算机存储特性(即超出范围即从别一台开始),最后形成一个hash圆。
    • 核心:参与运算的内容,只要运算内容相同,所得的hash运算结果一定相同。
  • redis分片机制中的一致性hash算法的使用:只负责数据数据如何管理,不负责存储,存储操作由选取的redis节点负责。
    • 通过分片中的每台redis的信息(ip地址+端口号)进行hash运算来计算出每台redis的节点信息(或者是节点位于2^32具体位置)。
    • redis通过采取k-v结构存储数据。此时在程序中,redis利用传的实参key计算出该条数据位于2^32中的具体位置。
    • redis利用此两类位置信息,按照自定议的方法找到该key距离最近的redis结点,将数据存储在该节点上。
    • 当从redis取出数据时,还是通过key进行hash计算出具体位置,找个具体存储数据的redis节点,取出数据。
    • 具体实现方法如下图所示:

3. 一致性hash的特性

1.平衡性

  • 概念:指hash的结果应该平均分配到各个节点。
  • 作用:从算法上解决负载均衡问题
  • 作用对象:redis节点
  • 实现方式:
    • 当有两个以上redis节点时,两两节点经过hash运算后,位置之间的距离过大时。会在位置过大的两个节点之间生成前一个节点的虚拟节点,该虚拟节点的位置大致会位于两个真实节点位置中点的左侧靠近中点的位置。
    • 一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。例如系统中只有两台服务器,此时必然造成大量数据集中到Node A上,而只有极少量会定位到Node B上。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟节点
    • 当保存数据的对应的key经过计算后,位于真实节点与该真实节点的虚拟节点之间是时,该数据将存储到该真实节点中去。
    • 示例:

2.单调性

  • 概念:指新增或删除节点时,不影响系统正常运行。如果已经有一些内容通过哈希分派到了相应的缓冲中,又有新的缓冲区加入到系统中,那么哈希的结果应能够保证原有已分配的内容可以被映射到新的缓冲区中去,而不会被映射到旧的缓冲集合中的其他缓冲区
  • 特点:在进行数据迁移时,要求尽可能小的改变数据。

3.分散性

  • 概念:指数据应该分散的存在在分布式集群中的各个节点,不必每个节点都存储所有的数据。

3、redis哨兵机制

3.1 redis哨兵机制的概述

1.哨兵机制作用

  • 通过哨兵机制实现redis分片的高可用,即在redis的分片中当有一台节点宕机时,不会对整个redis分片的造成影响,从而实现分片的机制的高可用。

2.哨兵机制的实现原理

  • 将多台实现主从结构的redis当做整体。
    • 主机即可读又可写同时会将数据同步到从机中;
    • 而从机平时当作用备用机使用,只接收主机同步的数据,而不接受其它的写操作,但可以接受客户端的读操作;
  • 当主机宕机时,哨兵机制会从从机中选取一台当做主机使用,从而保证整个系统不会因主机宕机而造成访问失败,实现redis高可用。

哨兵通过发送命令(ping命令),等待Redis服务器响应,如果在指定时间内,主机Redis无响应,从机则判断主机宕机,选举从机上位,从而监控运行的多个Redis实例。

第一步:心跳机制

每个 Sentinel 会每秒钟 一次的频率向它所知的 主服务器、从服务器以及其他 Sentinel 实例 发送一个 PING 命令,获取其拓扑结构和状态信息。

第二步:判断master节点是否下线

每个 sentinel 哨兵节点每隔1s向所有的节点发送一个PING命令,作用是通过心跳检测,检测主从服务器的网络连接状态。

如果 master 节点回复 PING 命令的时间超过down-after-milliseconds 设定的阈值(默认30s),则这个 master 会被 sentinel 标记为主观下线。

第三步:基于Raft算法选举领头sentinel

master客观下线,那就需要一个sentinel来负责故障转移,所以需要通过选举一个sentinel的领头羊来解决。

第四步:故障转移

故障转移的一个主要问题和选择领头sentinel问题差不多,就是要选择一个slaver节点来作为master。

选择主Maseter过程大致如下:

①选择优先级最高的节点,通过sentinel配置文件中的replica-priority配置项,这个参数越小,表示优先级越高;

②如果第一步中的优先级相同,选择offset最大的,offset表示主节点向从节点同步数据的偏移量,越大表示同步的数据越多;

③ 如果第二步offset也相同,选择run id较小的;

这样通过以上四大步骤,实现由RedisSentinel自动完成故障发现和转移,实现自动高可用。

第五步:通知

通知所有子节点新的master,后边从新的master上边同步数据;广播通知所有客户端新的master。

3.适用时机

  • 主要针对多台redis构成的实现主从配置或集群里使用。

3.2 哨兵机制的实现

1.准备工作

复制三份redis.conf文件,端口分别为6379,6380,6381

修改如下配置,并启动

bind 127.0.0.1    #主从机设定为统一的端口号绑定
port 6380    #修改成不同的端口号
protected-mode no   #关闭保护模式
daemonize yes   #设置成后台启动
masterauth <master-password>  #如果主机设置了密码,从机中需要添加这个,修改为主机的密码
#启动命令,进入到redis安装目录下
redis-server redis6379.conf
redis-server redis6380.conf
redis-server redis6381.conf

2.主从搭建

  • 节点信息检查命令:
    • 命令格式:info replication
    • 作用:检查redis节点的状态信息
  • 节点划分策略:根据业务需要要求。
    • 示例:以6379为主机、6380、6381为从机
  • 实现主从挂载
    • 方法通过主从挂载命令完成。
    • 主从挂载命令:slaveof host port
    • 实现过程:
      • 第一步:进入从机客户端,执行主从挂载命令

                执行主从挂载后从机信息:

 

                执行主从挂载后主机信息:

3.哨兵机制

  • 原理:
    • 当哨兵工作时会连接redis主机,并通过主机,获取所有从机的信息。
    • 监控主机运行状况
      • 通过心跳检测(pingpong)机制,定时向主机发ping命令,当达到规定次数仍然没有得到主机的pong结果,认定主机宕机。
    • 通过随机算法将从所有从机选举出新主机。
    • 负责剩下的从机重新挂载到新主机上。
    • 当主机恢复后,会做为从机挂载到当前主机上。
  • 哨兵机制的实现
    • 编辑redis.conf文件
    • 编辑sentinel.conf文件
      • 位置:

基础配置方法 

protected-mode no  #关闭保护模式,默认为启动
port 26379   #哨兵工作时的端口,默认为26379
sentinel monitor mymaster 127.0.0.1 6379 1   #哨兵监控的主机信息以及投票次数
#投票次数一般设置为哨兵次数的一半加1即可
#sentinel down-after-milliseconds <master-name> <milliseconds>
#设置主机宕机后到哨兵开始投票之间的时间
#sentinel failover-timeout <master-name> <milliseconds>
#设置投票结果到新主机开始工作之间的时间,如果超过该时间,哨兵视作新主机也宕机,则重新开始投票
  • 哨兵启动与停止
    • 哨兵的启动
      • 前置条件:sentinel.conf
      • 启动命令:redis-sentinel sentinel.conf

进入哨兵客户端及查看相关信息

redis-cli -p 26379
info sentinel

哨兵的停止

redis-cli -p 26379 shutdown

3.3 java整合redis哨兵

- 实现要求:redis哨兵是从哨兵池中获取的。
- 实现步骤:
- 第一步:实现redis池信息配置
- 创建redis池信息配置类JedisPoolConfig的对象。
- 通过setter方法对JedisPoolConfig对象属性赋值完成对redis池配置
- 第二步:指定哨兵主机信息
- 使用Set集合来保存哨兵的主机信息,由此可知哨兵同样可以实现集群。实现方式:
- 第三步:通过redis配置类对象和保存哨兵主机信息的Set对象构建哨兵池:即JedisSentinelPool对象。
- 第四步:从哨兵池(JedisSentinelPool)中获取哨兵,并当做单台Jedis使用。
- 第五步:通过获取的Jedis的对象,操作redis。
- 第六步:使用完毕必须关闭获取的jedis对象。
- 方法:jedis.close();
- 实现示例:

    @Testpublic void testSentinel(){// Redis哨兵的master名称String masterName = "mymaster";// Redis哨兵的hosts列表Set<String> sentinels = new HashSet<String>();sentinels.add("127.0.0.1:26379");
//        sentinels.add("sentinel2-host:port");
//        sentinels.add("sentinel3-host:port");// 创建Jedis哨兵连接池JedisSentinelPool sentinelPool = new JedisSentinelPool(masterName, sentinels);// 从连接池获取Jedis实例Jedis jedis = sentinelPool.getResource();try {// 使用Jedis实例进行操作,例如设置键值对jedis.set("key", "value");// 获取并打印键对应的值System.out.println(jedis.get("key"));} finally {// 释放Jedis实例到连接池jedis.close();}// 关闭哨兵连接池sentinelPool.close();}

2.springBoot项目整合redis哨兵。

  • 第一步:完成redis哨兵池对象构建并交由spring框架管理。

  • 第二步:完成redis哨兵的DI注入

  • 第三步:获取Jedis对象并通过该对象操作redis
    • 参照单台redis在SpringBoot项目中的应用
  • 第四步:关闭Jedis:jedis.close();

4、redis集群搭建

4.1 redis集群的概述

① 为什么要用集群

通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取。

Redis是一个很好的Cache工具。大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿。

由于内存大小的限制,使用一台Redis 实例显然无法满足需求,这时就需要使用多台 Redis作为缓存数据库。但是如何保证数据存储的一致性呢,这时就需要搭建redis集群.采用合理的机制,保证用户的正常的访问需求.

采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.并且在内部实现高可用的机制.实现了服务故障的自动迁移.

② 集群概念

  • 通过集群机制将哨兵机制的高可用和分片机制的高容量整合到一起,来实现redis的高性能和高可用。

③ 集群优势

  • 采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性。并且在内部实现高可用机制。实现了服务故障的自动迁移。

4.2 redis集群的实现

1.实现需求:准备6台redis,完成3主3从集群搭建,端口号从7000-7005

2.实现步骤:

  • 第一步:复制原始redis.conf文件到指定目录,创建了一个cluster文件夹,文件夹里分别创建7000-7005文件夹,将redis.conf文件分别放到里面

  • 第二步:修改redis.conf
# bind 127.0.0.1  #解除本地ip绑定
protected-mode no   #关闭保护模式
port 7000   #修改端口号为对应端口号,分别是:7000 7001 7002 7003 7004
daemonize yes    #开启后台运行模式
pidfile /usr/local/src/cluster/7000/redis_7000.pid   #是设置pid文件夹,通常和reids.conf位于同一文件夹
dir /usr/local/src/cluster/7000   #设置持久化文件目录,与pid同一目录
maxmemory-policy volatile-lru    #设置内存优化算法
appendonly no    #关闭appendonly持久化策略
cluster-enabled yes   #支持redis集群,必须设置
cluster-config-file nodes-7000.conf    #设置集群配置文件
cluster-node-timeout 15000     #设置集群超时时间,单位毫秒
  • 第三步:开启所有redis
    • 可以通过脚本文件启动所有redis
      • 创建并编辑start.sh
#!/bin/sh
redis-server /usr/local/src/cluster/7000/redis.conf &
redis-server /usr/local/src/cluster/7001/redis.conf &
redis-server /usr/local/src/cluster/7002/redis.conf &
redis-server /usr/local/src/cluster/7003/redis.conf &
redis-server /usr/local/src/cluster/7004/redis.conf &
redis-server /usr/local/src/cluster/7005/redis.conf 

- 通过脚本启动多台redis:

sh start.sh

- 可以通过脚本关闭多台redis:
- 创建stop.sh脚本

#!/bin/sh
redis-cli -p 7000 shutdown &
redis-cli -p 7001 shutdown &
redis-cli -p 7002 shutdown &
redis-cli -p 7003 shutdown &
redis-cli -p 7004 shutdown &
redis-cli -p 7005 shutdown 

- 通过脚本关闭所有redis

sh stop.sh

- 第四步:执行创建集群命令
- 命令自动运行阶段一:收集信息,提出集群创建策略。

redis-cli --cluster create --cluster-replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005

- 命令自动运行阶段二:加载节点到集群中

命令自动运行阶段三:完成主从搭建,计算hash槽道,并完成槽道分配

  • 第五步:测试集群

当角色是从机时,仅是备份作用,当其它主机宕机后成为主机,才能按槽道读写;当角色是主机,能读能写,还能向所属从机写入主机数据

集群是根据槽道向主机写入数据,当主机写入数据时,集群会首先计算槽道,按槽道选择所属主机,如果当前主机不是所选主机,则会提示前往对应主机写入数据

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

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

相关文章

JavaEE之线程(4)——线程安全、线程安全的原因,synchronized关键字

前言 在本栏的前面的内容中&#xff0c;我们介绍了线程的创建、Thread 类及常见方法、线程的状态&#xff0c;今天我们来介绍一下关于线程的另一个重点知识——线程安全。 一、线程安全 基本概念&#xff1a; 线程安全的确切定义是复杂的&#xff0c;但我们可以这样认为&…

vue3 antd-vue 超简单方式实现a-table跨页勾选

效果如下&#xff1a; 一、第一种方法 定义一个变量 selectKeysBack 用于维护所有勾选的数据value, 然后用 onSelect 拿到当前操作的数据&#xff0c;以及时候勾选。 这个方法便于拿到后端的数据之后用于回显 1、template <a-tableclass"custom-table-data":da…

类与对象(二)

封装 封装作为面向对象三大特性&#xff08;封装&#xff0c;继承&#xff0c;多态&#xff09;之一&#xff0c;那如何实现封装性的呢&#xff1f;就又得拿出上面的访问修饰限定符的图 public: 就是在任何地方都可以访问 protected: 涉及子类在介绍继承时详细介绍 default: …

STK12 RPO模块学习 (1)

一、背景介绍 在STK12中&#xff0c;在Astrogator的模块上开发了新的模块&#xff08;Rendezvous and proximity operations)。轨道交会接近通常来说是一个很复杂的过程。RPO实现需要对轨道动力学有一个清晰的理解&#xff0c;并且对于Astrogator模块具备很强的背景和经验&…

【教学类-55-02】20240512图层顺序挑战(四格长条纸加黑色边框、4*4、7张 、43200张去掉非7色有23040张,去掉重复样式有几种?)

作品展示 背景需求&#xff1a; 之前的代码吗存在几个问题&#xff0c;最大的问题是不能生成“”长条黑边框”” 【教学类-55-01】20240511图层顺序挑战&#xff08;四格长条纸&#xff09;&#xff08;4*4&#xff09;和“手工纸自制参考图”-CSDN博客文章浏览阅读485次&…

第十篇:数字堡垒:操作系统安全深度解析与实战指南

数字堡垒&#xff1a;操作系统安全深度解析与实战指南 1 *引言 1.1 数字世界的守护者 在遥远的比特海中&#xff0c;有一座名为“操作系统”的数字堡垒&#xff0c;它守护着我们的数据宝藏&#xff0c;确保每一次计算的航行都能安全抵达彼岸。然而&#xff0c;这片海域并非风…

记录:robot_localization传感器数据融合学习

一、参考资料 官方&#xff1a; http://wiki.ros.org/robot_localizationhttp://docs.ros.org/en/noetic/api/robot_localization/html/index.html2015 ROSCon 演讲官方网址&#xff08;youyube上也有这个视频&#xff09; 实践教程 https://kapernikov.com/the-ros-robot_…

深入理解Python的类,实例和type函数

问题起源&#xff1a; class t():pass s1 t() s2 type("Student2",(),{}) isinstance(s1, type), isinstance(s2, type)为什么第一个是false&#xff0c;第二个是true呢 根因定位&#xff1a; 在Python中&#xff0c;一切皆对象&#xff0c;类是对象&#xff0c…

Linux字符设备驱动设计

Linux字符设备驱动设计 概述 驱动的定义与功能 计算机系统中存在着大量的设备&#xff0c; 操作系统要求能够控制和管理这些硬件&#xff0c; 而驱动就是帮助操作系统完成这个任务。 驱动相当于硬件的接口&#xff0c; 它直接操作、 控制着我们的硬件&#xff0c; 操作系统通…

升级Microsoft 365后,SAP GUI中无法打开Excel的解决方案

最近&#xff0c;我们遇到了一个棘手的问题&#xff0c;一位客户在升级到Microsoft 365后&#xff0c;无法在SAP GUI中打开Excel。这个问题不仅影响了工作效率&#xff0c;也给用户的日常操作带来了不便。在本文中&#xff0c;我们将探讨问题的成因&#xff0c;并提供一种解决方…

gin自定义验证器+中文翻译

gin自定义验证器中文翻译 1、说明2、global.go3、validator.go4、eg&#xff1a;main.go5、调用接口测试 1、说明 gin官网自定义验证器给的例子相对比较简单&#xff0c;主要是语法级别&#xff0c;便于入门学习&#xff0c;并且没有给出翻译相关的处理&#xff0c;因此在这里记…

PaddleOCR_PP-Structure

静态IP设置 # 修改网卡配置文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33# 修改文件内容 TYPEEthernet PROXY_METHODnone BROWSER_ONLYno BOOTPROTOstatic IPADDR192.168.15.132 NETMASK255.255.255.0 GATEWAY192.168.15.2 DEFROUTEyes IPV4_FAILURE_FATALno IPV6INIT…

YOLOv8小白中的小白安装环境教程!没一个字废话,看一遍不踩坑!

文章目录 去哪里下代码?怎么下代码?怎么装环境?命令行界面(CLI)指令和Python脚本区别?附录1 conda常用指令附录2 git常用指令附录3 项目代码文件作用去哪里下代码? 下载代码请大家直接去 YOLOv8的官方仓库下载,名字叫 ultralytics,有些镜像网站和个人发的等来历不明的代…

CMakeLists.txt语法规则:foreach 循环基本用法

一. 简介 cmake 中除了 if 条件判断之外&#xff0c;还支持循环语句&#xff0c;包括 foreach()循环、while()循环。 本文学习 CMakeLists.txt语法中的循环语句。 CMakeLists.txt语法中 有两种 循环实现方式&#xff1a;foreach循环与 while循环。 二. CMakeLists.txt语法规则…

解决 SyntaxError: Unexpected token ‘.‘ 报错问题

这个报错一般是编译问题&#xff0c;浏览器的版本过低没通过代码 解决办法&#xff1a; 在package.json文件中加上这个 "browserslist": ["> 1%","last 2 versions","not dead","not ie < 6","Android > 4&…

AI算法工程师课程学习-数学基础-高数1-微积分

基础数学学习目的&#xff1a;为机器学习(尤其是算法)和深度学习打基础。 学习路线&#xff1a;1.高中数学-->大学2.微积分-->3.线性代数-->4.概率论-->5.优化理论。&#xff08;因为自己40多岁年龄了&#xff0c;做了7年的.net开发&#xff0c;后面都一直在做软件…

工器具管理(基于若依)

文章目录 前言一、工器具管理项目总览 二、入库功能1. 前端1.1 界面展示1.2 具体操作实现1.3 js文件 2. 后端2.1 工器具信息回显2.2 工器具入库 三、领用功能1. 前端1.1 界面展示1.2 具体实现操作1.3 js文件 2. 后端2.1 工器具信息回显2.2 工器具领用 遇到的问题1. 同一页面展示…

2024 年中国大学生程序设计竞赛全国邀请赛(郑州)暨第六届CCPC河南省大学生程序 设计竞赛Problem L. Toxel 与 PCPC II

//sort bug下标 遍历dp. //没修负的bug肯定连续 #include<bits/stdc.h> using namespace std; #define int long long const int n1e611; int a,b,c[n],dp[n]; signed main() {ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);cin>>a>>b;for(int i1;…

【JVM】从可达性分析,到JVM垃圾回收算法,再到垃圾收集器

《深入理解Java虚拟机》[1]中&#xff0c;有下面这么一段话&#xff1a; 在JVM的各个区域中&#xff0c;如虚拟机栈中&#xff0c;栈帧随着方法的进入和退出而有条不紊的执行者出栈和入栈操作。每一个栈帧中分配多少内存基本上是在类结构确定下来时就已知的&#xff08;尽管在…

抖音上有可以长久赚钱的副业吗?当然有,只有它最稳定长久!

大家好&#xff0c;我是电商糖果 现在有很多年轻人在大城市上班&#xff0c;发现辛辛苦苦一年也赚不到多少钱。 如果说自己有了房贷&#xff0c;车贷&#xff0c;那更是一点儿不敢歇。 为了可以有更多的收入&#xff0c;年轻人都希望可以靠着下班时间&#xff0c;找一个可以…