首页 > 数据库 >模拟一个微服务架构项目来学习包括Nacos、EMQX、GateWay、RabbitMQ、Canal、Mybatis-Plus、Redis

模拟一个微服务架构项目来学习包括Nacos、EMQX、GateWay、RabbitMQ、Canal、Mybatis-Plus、Redis

时间:2024-10-11 09:18:35浏览次数:12  
标签:Canal 调用 服务 -- Redis Nacos 接口 订单 充电

前言

介绍下最近做的项目:

为什么做这个项目?

项目的核心用户目标是谁? 面向新能源电车用户

给目标用户提供了什么价值? 方便快捷充电服务

团队的作用 ? 需求分析,概要设计,详细设计,开发,测试,部署,上线

我的作用? 1-2两个核心业务 详细设计(业务流程,接口入参,接口出参,表结构),开发(代码实现),测试(单元测试)

梳理业务

1.搜索附近的充电站

2.导航过去

3.充电

4.设备上扫码 开始充电

5.下单

  1. 生成订单号

  2. 获取场站信息和设备信息 (服务之间调用 订单服务调用设备服务)

  3. 获取用户车辆信息 (服务之间调用 订单服务调用用户服务)

  4. 修改充电桩的状态 为 使用中 (服务之间调用 订单服务调用设备服务)

  5. 创建自检定时任务

  6. 给设备发送开始充电指令 (物联网 订单服务调用设备)

  7. 给RabbitMQ发送延迟消息,处理故障导致的超时订单

业务--用户服务

通过用户id获取车辆信息接口

坐标-由以下nacos和feign来创建了userFeign接口

芝士--服务之间的通信(RestTemplate)

RestTemplate(展开详情)

spring提供的通用的HTTP调用客户端

  1. 检查依赖

    <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
  2. 测试类的编写

编写测试类RestTemplateTests 学习RestTemplate的用法,和单元测试的用法

   增加单元测试的依赖

<!--单元测试依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>

增加配置类

最早接触到 容器外不能引用容器内的对象

通过配置类 @Bean 创建 RestTemplate

  @Bean 通过配置的方式创建bean,并且把bean放入spring的ioc容器,方便后续代码通过注入的方式使用

  通过订单服务调用外部接口 www.baidu.com 通过日志观察返回结果

@Test public void testRestTemplate(){ ResponseEntity<String> forEntity = restTemplate.getForEntity("https://www.baidu.com", String.class); System.out.println(forEntity.getStatusCode()); System.out.println(forEntity.getBody()); }

订单服务调用 用户服务接口 http://localhost:8080/user/info/{userId}

参数少 可以直接把入参 userId 1 拼接在URL后面

String url = "http://localhost:8083/user/info/1";

参数多 直接拼接容易出错

可以使用占位符,把 userId 1 作为getForEntity 方法的入参传入

String url = "http://localhost:8083/user/info/{1}"; //占位符号 ResponseEntity<JsonResult> entity = restTemplate.getForEntity(url, JsonResult.class,1);

为什么最后不使用RestTemplate?

我们要使用post请求时,RestTemplate太过于麻烦 因为不光要设置地址,还要进行参数的序列化和反序列化

从而引出Open-Feign--服务之间通信的组件

在部署时,我们不可避免的要使用集群,比如用户服务过多时,要部署多台用户服务,那么订单服务调用用户服务时,应该用哪一台呢? 如果使用RestTemplate,简单的通过Random来实现随机调用不同端口号的用户服务。但是这是一种硬编码,写死在订单服务中,更重要的是我们无法获得用户服务的状态,如果有用户服务宕机,我们不得而知。

从而引出Nacos注册中心--用来同步服务的状态

芝士--Nacos注册中心(8848)

主要作用

  • 服务提供者(用户服务)

    • 服务注册- 把自身信息上线(服务名,URL,端口号) 调用注册接口 告知注册中心

    • 状态同步- 把实时的状态信息告诉注册中心

    • 服务下线- 把下线信息 通过调用下线接口 告知注册中心

  • 服务消费者(订单服务)

    • 服务发现 -通过注册中心的查询接口,获取用户服务的信息(服务数量,服务状态)

Nacos的下载注册

在注册完之后,要修改配置文件

--跟数据库相关的配置

  • 建表来存储

  • 配置相关信息来连接到该表

Nacos的使用

添加依赖

<!--统一定义版本号,方便我们后续统一修改,方便管理 类似我们代码里的常量--> <properties> <nacos-version>2021.0.4.0</nacos-version> </properties> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>${nacos-version}</version> </dependency>

Open-Feign服务通信工具

  1. 增加依赖(和RestTemplate一样 Http调用客户端)

<!--统一定义版本号,方便我们后续统一修改,方便管理 类似我们代码里的常量--> <properties> <nacos-version>2021.0.4.0</nacos-version> </properties> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>${nacos-version}</version> </dependency>
  1. 创建FeignClient

想要和别的服务通信,需要创捷接口

  • 创建UserClient接口

  • 使用@FeignClient("userService") 注解 服务名(userService)和要nacos服务列表里的服务名一样

  • @EnableFeignClients 在启动类让spring-boot启动的时候帮忙开启feignClients

  • 在创建了单元测试进行测试之后,报错需要添加loadbalancer 负载均衡的依赖

<properties> <loadbalancer.version>3.1.5</loadbalancer.version> </properties> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-loadbalancer</artifactId> <version>${loadbalancer.version}</version> </dependency>

业务--订单调用设备服务

  • 创建 charging-device 设备服务 子项目

  • 实现两个接口 获取场站信息接口,更新枪状态接口

  • 把设备服务注册到注册中心

  • 创建DeviceClient 在此Client中定义两个接口 分别用来调用场站信息更新枪状态

  • 在订单服务中 集成设备服务 注入deviceClient 这样就可以调用设备服务

业务--集成用户服务

在此之前我们已经在订单服务中创建好了调用用户服务接口以及在用户服务中创建好了用户服务中获取用户车辆信息的接口

  • 在OrderServiceImpl中修改获取用户的代码

  • 在订单服务中注入UserClient

芝士--微服务&网关&Feign

https://rcnp6z3mgqkn.feishu.cn/wiki/TxTRwyq4eiPKHrkN32EcMrKcneg?from=from_copylin

芝士--IOT物联网(EMQX 1883-管理EMQX的端口号)

  • emqx消息中间件--基于MQTT消息中间件

      MQTT 是一种协议 应用在物联网 服务(订单服务)和设备 (充电桩) 通信

  • RabbitMQ

      基于AMQP消息中间件

       AMQP 高级消息队列协议 应用在 服务(订单服务)和服务(设备服务) 通信

  • mqttfx 模拟软件--mqtt的客户端模拟软件 模拟 设备 充电桩

业务--订单服务和设备通信

之前我们用订单服务和设备服务通信

现在我们要通过EMQX消息中间件 让订单服务和设备之间通信

  1. 订单服务连接EMQX 在父项目添加依赖

<properties> <mqtt-version>1.2.5</mqtt-version> </properties> <!--mqtt依赖--> <dependency> <groupId>org.eclipse.paho</groupId> <artifactId>org.eclipse.paho.client.mqttv3</artifactId> <version>${mqtt-version}</version> </dependency>
  1. 在订单服务中同样特添加依赖

  2. 与Nacos不同的,在使用Nacos时在下载时已经配好了mysql,使用EMQX时我们需要通过代码连接

  3. 订单服务连接EMQX --增加MqttConfiguration 生成了MqttClient(用来实现MQTT协议客户端功能的软件库) 模板代码

  4. 订单服务给设备发消息

    1. 创建MqttProducer

    2. 在此类中 注入MqttClient

  5. EMQX连接设备--通过mqttfx客户端接收消息 在客户端subscribepublish消息

芝士--JsonUtils

我们服务之间需要传输对象时,我们需要将Java对象转换成Json格式

在charging-common 项目中定义 定义JsonUtils 工具类把业务和json转换工具具体实现隔离

业务--订单服务发送指令到充电桩

  1. 修改 OrderServiceImpl#startCharging

  2. 定义Topic 建立一个MqttConstant 里面包含了我们需要的所有需要的topic eg:MqttConstant.TOPIC_START_CHARGING_PREFIX + pileId; --piled是我们传递的参数

  3. 服务之间传输对象 定义Dto 用JsonUtils来转换

  4. 在订单服务中注入mqttProducer 给设备发送开始充电 定义该方法中包含了我们设备要subscribe的topic

  5. 设备接受消息 topic=前缀+桩id 也就是定义的主题加发送的桩id

  6. 设备接受消息

业务--充电桩发送指令到订单服务

  1. 创建MqttConsumer--消费者从emqx subscribe(订阅)指定的topic 实现MqttCallbackExtended 从而重写以下四种方法

  2. 消费时有不同的事件

    1. 连接成功 connectComplete

    2. 连接丢失 connectionLost

    3. 消息到达 messageArrived

    4. 消息处理完成 deliveryComplete

解惑--为什么我们使用mqtt生产者时 直接将mqttproducer直接实例化到了spring容器中,也就导致在生产者中可以直接使用mqttclient(使用mqttclient中的publish方法).但是在使用mqtt消费者时不可以将对象注册到spring容器中.因为消费者涉及到异步监听 需要设置一个回调来监听并处理mqtt服务器的消息,而在容器中设置回调容易出问题--spring容器无法处理回调函数 而且 容器对bean对象生命周期的管理可能中断监听

  1. 设置回调 在我们创建mqttClient时 带来的问题就是我们消费者无法调用在容器中的mqttClient 所以我们在创建mqttClient时,通过构造将mqttClient装入消费者

  2. 我们在消费者中 还需要使用其它容器内对象 所以新增MqttContext ,将使用的其它对象装入其中,封装的好处

  3. 通过mqttfx发送消息 publish 到 topic 需要正确的json格式验证地址

业务--操作数据库

新的一种对象 PO Persist Object

Mybatis-Plus

通过mybatis能完成对数据库的CRUD

简单的CRUD懒得写,可以使用mybaits-plus 帮我们实现,

我们更加关注业务

  • 加依赖 三个依赖 因为有mysql mybatis 和mybatis-plus

  • 要使用mybatis-plus的只需要 extends BaseMapper<绑定的pojo类> pojo类用 TableName("要操作的数据库表")接口 但使用了之后 我们需要更改配置,否则找不到mapper文件mybatis-plus.mapper-locations=classpath:mappers/**/*.xml 添加了 -plus

业务 集成 将订单插入数据库

  • 设备返回响应

  • 返回开始充电成功 插入成功订单数据 新增OrderSuccessMapper

  • 返回开始充电失败 插入失败订单数据 新增OrderFailMapper

  • 将 新增的Mapper注入MqttContext 修改MqttConfiguration 在消费者中 建立属性和构造方法接受 容器中的对象

  • 之前整理业务时,我们得知只有在设备返回消息以后我们才能在数据库中插入记录,所以在consumer中的 messageArrived进行业务逻辑 --判断返回的结果 设备返回的结果也要定义为常量或者枚举 通过判断分别在成功和

  • topic有常量 订单也有常量 新增OrderStatusConstant 订单状态 充电中 正常结束 异常结束

业务 --解决设备故障问题

场景

  • 充电过程中,设备出现了故障,订单状态一直是充电中

  • 订单服务给充电桩发送充电指令

为了解决订单状态一直是充电中,我们要使用rabbitMQ中的死信队列来实现延迟处理 也就是超时任务

  • 配置配置Exchange和Queue 通过 RabbitConfiguration

  • 定义消费生产者 通过rabbitmqTemplate 把订单消息发送到 订单正常队列

  • 定义死信队列的消费者 定义死信队列的消费者

  • 在订单服务中注入RabbitMQOrderProducer 定义发送消息的方法

芝士--RabbitMQ(15672)

加依赖

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-amqp</artifactId> </dependency>
  • Virtual host 虚拟主机 隔离 分组 ,不同的业务隔离

  • Connections 和RabbitMQ的连接

  • Channel 通道 发消息 (channel.basicPublish)和收消息(channel.basicConsume)都是通过通道进行的

    • 发消息

      • 从连接获取Channel

      • Channel定义Queue 队列-存储消息

      • Channel 绑定 通过Routingkey把Exchange和Queue进行绑定

      • Channel 发送消息 channel.basicPublish

    • 收消息

      • 从连接获取Channel

      • Channel收消息channel.basicConsume 注意 callback 回调

  • 消息持久化

在生产者,消息中间件,消费者都已做了操作,但是还有可能丢失 单机产生单点故障,所以还可以集群操作

  • 普通集群 消息不实时同步,消费的时候同步

  • 镜像集群 实时同步, 消费者从哪消费都能消费到消息, 耗性能

具体操作流程

  1. 现在配置文件中配置好rabbitMQ,为了防止消息不丢失,确认和反馈都默认手动

listener: simple: #默认是自动ack,为了保证消费者消息不丢,配置为手动ack manual  acknowledge-mode: manual #开启确认模式,为了保证生产者发送消息不丢,用来确认RabbitMQ成功收到消息 publisher-confirm-type: correlated
  1. 有了依赖自动装配后(可以用DirectExchange/Queue方法),先在配置类中建立exchange和queue 已经绑定好

在队列中设置好 设置消息的TTL 设置死信的Exchange 设置死信的RoutineKey

  1. 生产者:在生产者中可以用rabbitTemplate来发送消息,当然我们还要设置confirm和ack的回调来保证发送消息不丢失

  2. 消费者:监听死信队列,当超时任务时间到达后,转给死信时消费,在其中编写业务逻辑

芝士--幂等性

幂等性:外界通过接口对系统内部的影响,只要一次或多次调用对某一个资源应该具有相同的副作用

业务 -- 幂等性错误

场景

设备模拟器 mqtt.fx 重复发送同一个订单编号的开始充电指令

订单服务 MqttConsumer#messageArrived 会收到重复的指令

成功订单表 charging_bill_success 重复保存订单数据

解决方案

  • 数据库实现

订单成功表增加 唯一索引

唯一索引,是对数据库表中的一种约束 ,唯一约束 限制

  • Redis布隆过滤器 把能区分唯一性的数据(订单号),发到过滤器里,每次处理之前,判断,存在,说明处理过,不存在,说明没处理过,继续处理

  • 程序实现 先通过订单编号,查询成功订单表 判断是否有数据 有 不保存 没有 保存

    • 用程序实现时 还需要考虑原子性

      /private synchronized void saveSuccessOrder(ChargingResultDto chargingResultDto) { 
      • 本地锁

      • 乐观锁

      • 悲观锁

      • 分布式锁

幂等性一般时消息的消费者 接口的被调用方 处理

订单服务调用优惠券 , 优惠券服务处理幂等

设备发送消息给订单服务,订单服务处理幂等

业务--设备无响应

  • 正常情况 设备收到指令,会给订单服务返回响应 分为两种 开始充电成功/失败

    • 开始充电成功

      • 直接充满

      • 同步几次后 设备故障 超时订单 RabbitMQ死信队列延迟服务

    • 开始充电失败 失败订单数据库插入一条消息

  • 异常情况 无响应

解决方案

定时任务 --设备自检一分钟

  • RabbitMQ 基于死信队列实现延迟消息

    • 在订单服务给设备发送开始充电指令后 给RabbitMQ发消息 在RabbitMQConfiguration中设置正常交换机 正常队列--(队列中设置TTL 死信交换机 死信RoutingKey) 正常绑定 设置死信交换机 私信队列 死信绑定

    • 过期 转发死信 消费者收到消息

    • 判断是否有订单记录

    • 成功订单有 成功充电不用管

    • 失败订单有 失败充电不用管

    • 都没有 说明无响应 插入失败订单记录 故障原因 无响应(需要new一个对象 设定好属性值之后 调用dao)

延迟处理 定时任务 按照固定时间 触发一次 多次 皆可

触发多次 也就是心跳 实时同步

服务提供者和nacos心跳已经通过nacos中的实时同步接口实现

设备和订单服务同步数据 //todo

  • Quartz 定时任务的框架

    • 由于 这个定时任务框架DeviceCheckJob是new出来的 通过以下方法获取容器内对象

    • 在执行任务时,需要实例化DeviceCheckJob ,通过CLass调用newInstance 也可通过有参构造器实例化

    • 在此之后 与rabbitmq方法相同

芝士--Quartz

  1. 加依赖

<quartz-version>2.3.2</quartz-version> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz-version}</version> </dependency>
  1. JobDetail

    1. 创建调度器工厂 通过工厂创建调度器

    2. 描述任务详情 JobBuilder.newJob(DriveCheckJob.class)

    3. 触发器 给触发器设置时间

    4. 调度器 把任务详情和触发器绑在一起 触发时启动

    5. 任务执行 execute implements Job 方法里写具体的任务要执行的代码逻辑 (在任务执行中,需要很多容器内的bean对象 创建一个容器 实现ApplicationContextAware这个接口 来获取容器中的对象实例)

业务--新增计价服务

订单的服务需要价格的计算,为了后续的扩展和解耦,独立出一个计价服务

  1. 创建项目架构

  2. 添加依赖(复制之前的依赖)

  3. 基本配置 端口号 数据库连接地址 服务名 nacos注册地址

  4. 接口入参 接口出参

  5. CostService 接口 接口实现类

  6. 新增CostClient接口

  7. 订单服务中订阅 /topic/charging/process 在messageArrived中消费

  8. 服务之间传递要用Dto 设备同步过来的消息通过JsonUtils中的fromJson转换成java格式放在ChargingProcessDto中

  9. ChargingProcessDto用来表示 设备和订单同步的数据 chargingProcessParam用来表示 订单给计价的入参

梳理业务

  1. 设备要同步充电进度 publish /topic/charging/process -->emqx

  2. emqx --> 订单服务 -->订阅 /topic/charging/process 在connectComplete中

  3. 收到消息后 消费 messageArrived --> 调用计价服务CostClient -->同步给用户

业务--计价逻辑

价格的计算 依赖于 计价规则

价格 = 上次计算的价格 +当前价格 价格的累加

计价规则

不同的时间段 尖 峰 平 谷

不同的充电桩

逻辑

我们的计价规则表里有不同的时间段不同的价格等等

所以我们要首先得到计价规则 (计价规则接口 getCostRules(场站id)) 所以我们先要确定哪个场站 得到场站中所有的计价规则

再循环匹配到满足计价的规则(匹配计价规则接口 getMatchCostRuleGunAndTime) -- 确定当前时间 规则匹配 返回规则

计算价格 (计算价格接口 getCost(度数,规则中的单价))我们数据库中的价格是BigDecimal类型 所以返回值也是 BifDecimal

同步策略

包含 包含了上次充电

   不包含 每次同步的就是期间的度数

选择 包含 如果期间数据同步丢失 亏损

同步中的问题 -- 第一次同步 和 第n次同步逻辑不一样 后面的同步要-前面充电度数再*单价 所以要解决是第几次同步 使用全局变量 Map<订单号,充电数据(chargingData)> chargingProcessData 来记录是否第一次

建立一个接口(getChargingData)来操作 Map中的数据 如果是第一次(初始化接口(initChargingData)) 不是第一次 把chargingData中的属性 count+1

业务--ElasticSearch

设备实时同步充电情况给订单服务,订单服务mqttConsume消息到达以后,调用计价服务计算了价格之后,要保存数据.

为什么要存到ES中?

ES存储 时序数据(有时间 有顺序),写入高频,读相对较少,不更新,不删除.

加依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency>

在配置文件中配置连接地址

spring: elasticsearch: uris: http://localhost:9200

新增ChargingProcessPO

@Document 绑定类和表 不过与MySQL不同的是无需创建表,ES会自动创建

在数据库操作层 新加仓库 继承 ElasticsearchRepository<绑定的PO,PO中的主键类型>

保存数据时,通过充血模型计算总花费,并且调用仓库实现保存的方法

查看同步数据

在浏览器中集成开发者工具 es-head ES会直接创建PO中绑定的表名

芝士--ApiPost

Knife4J Postman ApiPost(测试webscoket) 接口测试的工具

芝士--WebSocket

WebSocket是一种基于在单个TCP连接上进行全双工通信的协议,一种浏览器与服务器之间进行全双工通讯的网络技术,解决了HTTP协议不适于实时通信的缺点,相较于HTTP协议,WebScoket协议实现了持久化网络通信,可以实现客户端和服务端的长连接,可以进行双向实时通信,协议名为"ws".基于Netty框架 和网关一样

业务--WebSocket 消息推送

加依赖

<websocket-version>2.6.13</websocket-version> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>${websocket-version}</version> </dependency>

增加WebSocketConfiguration

创建 ServerEndPointExporter

新增WebSocketServer

通过 @ServerEndPoint("/ws/server/{userId}")指定 ws连接地址

通过@OnOpen 等注解 添加Session会话 通过会话推送消息 所以引出会话的持久化

如果把session存储在Map中 重启后数据会丢失 session丢失后 用户和服务连接断开

Session会话持久化

WebSocket推送的消息也要持久化--ES持久化

WebScoket推送消息 --性能优化 结合中间件 MQ 让MqttConsumer把推送的消息发给rabbitMQ ,让消费者在rabbitMQ中消费 实现消息持久化 业务的解耦

业务--利用Redis优化计价服务

加依赖

properties> <redis-version>2.6.13</redis-version> </properties> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>${redis-version}</version> </dependency>

配置

通过创建一个RedisConfiguration

创建 redistemplate

设置 连接工厂

设置 序列化器 (在redis中的Hash属性中 除了设置key value序列化器 还设置了HashKey的序列化器 和value的反序列化器 否则类型转换异常) 如果没有设置序列化器 通过 connection 原生方式写入的数据 采用的是默认的序列化方式

先创建获取Redis和存储Redis的方法

创建Mapper(操作员)和Repository(操作的方法)

修改getCostRule 查询Redis是否有 没有从数据库查 保存在Redis中 有直接拿

这种方法(数据库和缓存配合使用解决业务问题)叫做旁路模式 Cache Aside模式

优化计价规则

新增CostRuleCahcheRepository

新增两个方法

   一个是从redis中查询计价规则

  一个是保存计价规则到redis中

体会Redis中基本类型 String 的get set用法

芝士--连接池

理解池化的概念 连接池的作用就是复用

redis默认的连接池--Lettuce连接池

Spring Boot默认的MySQL连接池--HikariCP连接池

芝士--缓存预热

在项目(设备服务)启动的时候

实现ApplicationRunner接口 重写run方法

从数据库charging_station 中查询场站信息(所有的地理信息要存放在一个redistemplate操作的GEO中)

基本信息存储到Hash 中(String GEO两种类型皆可)

芝士--GEO

  通过Redis 的GEO 数据类型 支持地理位置的查询和存储

  ES也能实现类似地理位置的查询和存储

  GEO的底层实现是Zset 不重复有序

  把经度纬度两个值 通过编码 变成一个值memeber放入Zset中 并且通过score排序

业务--查询附近充电站

位置(GEO)

通过redis的GEO类型 redisTemplate.boundgeoOps("staions") 操作stations

把位置信息存放在 stations

基本信息

通过String类型保存基本信息

通过独立Hash类型保存基本信息 大K保存station的id HashKey保存属性名 value属性值

通过全局Hash类型保存基本信息 大K保存基站s HashKey保存基站id value保存基本信息

业务--场站信息查询

掌握 Redis GEO Point(经纬度--点) Distance(半径) Circle(画一个圆)

通过操作staions 调用radius 传入画的圆的(circle)参数和 前端传来的参数得到满足条件的充电站

芝士--redis五种基本类型

String Set Zset List Hash

手机验证码 String

粉丝排行榜 Zset

购物车 Hash

6.付款

标签:Canal,调用,服务,--,Redis,Nacos,接口,订单,充电
From: https://blog.csdn.net/weixin_69072005/article/details/142844953

相关文章

  • 图解Redis 04 | Set数据类型的原理及应用场景
    介绍Redis的Set类型是一个不允许重复元素的集合,元素存储的顺序不按照插入的顺序,因此属于无序集合。一个Set最多可以存储2^32-1个元素,这与数学中的集合概念类似。Set类型不仅支持增、删、改、查等操作,还支持多个Set之间的交集、并集和差集运算。内部实现Set类......
  • [Java/Spring/Nacos] Java 获取配置的方式
    1、[本地]使用JDK的System.getProperty(key),获取JVM参数(VMOptions)、系统属性参见:系统变量与JVM参数(VMOption)/环境变量/程序启动参数args-博客园/千千寰宇2、[本地]使用JDK的System.getenv(key),获取环境变量3、[本地]使用JDK的main(String[]args......
  • Redis的五种基本类型和业务场景和使用
    目录Redis是什么?Redis的特点依赖配置redis的配置类(用于格式转换,处理乱码)String(字符串)特点业务场景代码使用案例List(列表)特点业务场景代码使用案例Set(集合)特点业务场景代码使用案例Hash(哈希表)特点业务场景代码使用案例SortedSet(有序集合)特点业务场景......
  • Redis 5大数据类型
    这里说的数据类型是value的数据类型,key的类型都是字符串。5种数据类型:redis字符串(String)redis列表(List)redis集合(Set)redis哈希表(Hash)redis有序集合(Zset)哪里去获取redis常用数据类型操作命令:http://redis.cn/commands.html2.1、redis键(key)keys*:查看当前库所有的keyexis......
  • Redis 数据类型hash(哈希)
    目录1基本特性2主要操作命令 2.1设置和获取字段2.1.1 HSETkeyfieldvalue2.1.2 HGETkeyfield2.1.3 HMSETkeyfield1value1[field2value2...] 2.1.4 HMGETkeyfield1[field2...]2.2检查字段是否存在2.2.1 HEXISTSkeyfield2.3获取所有字段和......
  • 搭建Redis哨兵集群并使用RedisTemplate实现读写分离
    一、理论相关通过上篇博客:搭建Redis“主-从-从”模式集群并使用RedisTemplate实现读写分离,我们已经搭建好了Redis“主-从-从”模式集群并且实现读写分离,这里会出现几个问题:如果主库宕机了,我们就需要运行一个新主库,比如说把一个从库切换为主库,把它当成主库。这就会涉及到三个......
  • 希音面试:Redis脑裂,如何预防?你能解决吗?(看这篇就够了)
    文章很长,且持续更新,建议收藏起来,慢慢读!疯狂创客圈总目录博客园版为您奉上珍贵的学习资源:免费赠送:《尼恩Java面试宝典》持续更新+史上最全+面试必备2000页+面试必备+大厂必备+涨薪必备免费赠送:《尼恩技术圣经+高并发系列PDF》,帮你实现技术自由,完成职业升级,薪......
  • Redis面试篇3
    1、Redis的数据类型,以及每种数据类型的使用场景?常见的几种数据类型和使用场景如下:字符串(String):字符串类型是Redis最基本的数据结构,一个键最大能存储512MB。使用场景:适用于计数器、分布式锁、缓存等常见。列表(List):列表是链表结构,可以在头部和尾部添加元素。......
  • 【Redis入门到精通十】Redis哨兵
    目录哨兵(Sentinel)1.哨兵的由来2.哨兵的基本概念3.基于docker安装配置Redis哨兵4.哨兵选取主节点的原理1.主观下线2.客观下线3.选举出哨兵的leader4.leader挑选出合适的slave成为新的master哨兵(Sentinel)    RedisSentinel是Redis的高可用实现方案,在......
  • redis介绍与安装
    Redis简介Redis是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。Redis与其他key-value缓存产品有以下三个特点:Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。Redis不仅仅支持简单的key-value类型的数据,同时还提供l......