哨兵

导读

  1. Redis Sentinel是Redis的高可用实现方案:故障发现、故障自动转移、配置中心、客户端通知
  2. Redis Sentinel从Redis2.8版本开始才正式生产可用,之前版本生产不可用
  3. 尽可能在不同物理机上部署Redis Sentinel所有节点
  4. Redis Sentinel中的Sentinel节点个数应该为大于等于3且最好为奇数
  5. Redis Sentinel中的数据节点与普通数据节点没有区别
  6. 客户端初始化时连接的是Sentinel节点集合,不再是具体的Redis节点,但Sentinel只是配置中心不是代理
  7. Redis Sentinel通过三个定时任务实现了Sentinel节点对于主节点、从节点、其余Sentinel节点的监控
  8. Redis Sentinel在对节点做失败判定时分为主观下线和客观下线
  9. 看懂Redis Sentinel故障转移日志对于Redis Sentnel以及问题排查非常有帮助
  10. Redis Sentinel实现读写分离高可用可以依赖Sentinel节点的消息通知,获取Redis数据节点的状态变化

基本概念

名词 逻辑结构 物理结构
主节点(master) Redis 主服务 / 数据库 一个独立的 Redis 进程
从节点(slave) Redis 从服务 / 数据库 一个独立的 Redis 进程
Redis 数据节点 主节点和从节点 主节点和从节点的进程
Sentinel 节点 监控 Redis 数据节点 一个独立的 Sentinel 进程
Sentinel 节点集合 若干 Sentinel 节点的抽象组合 若干 Sentinel 节点进程
Redis Sentinel Redis 高可用实现方案 Sentinel 节点集合和 Redis 数据节点进程
应用方 泛指一个或多个客户端 一个或者多个客户端进程或者线程

主从复制问题

优点:

作为主节点的一个备份,一旦主节点出了故障不可达的情况,从节点可以作为后备“顶”上来,并且保证数据尽量不丢失(主从复制是最终一致性)

从节点可以扩展主节点的读能力

缺点:

一旦主节点出现故障,需要手动将一个从节点晋升为主节点,同时需要修改应用方的主节点地址,还需要命令其他从节点去复制新的主节点,整个过程都需要人工干预-->Redis高可用问题

主节点的写能力、存储能力受到单机的限制-->Redis分布式问题

Redis Sentinel的高可用性

高可用:

  1. 判断节点不可达的机制
  2. 怎样保证只有一个被晋升为主节点
  3. 通知客户端新的主节点机制是否足够健壮

当主节点出现故障时,Redis Sentinel能自动完成故障发现和故障转移,并通知应用方,从而实现真正的高可用

Redis Sentinel是一个分布式架构,其中包含若干个Sentinel节点和Redis数据节点,每个Sentinel节点会对数据节点和其余Sentinel节点进行监控,

当它发现节点不可达时,会对节点做下线标识。如果被标识的是主节点,它还会和其他Sentinel节点进行“协商”​,

当大多数Sentinel节点都认为主节点不可达时,它们会选举出一个Sentinel节点来完成自动故障转移的工作,同时会将这个变化实时通知给Redis应用方。

1主2从3哨兵

  1. 主节点出现故障,此时两个从节点与主节点失去连接,主从复制失败。
  2. 每个Sentinel节点通过定期监控发现主节点出现了故障
  3. Sentinel节点对主节点的故障达成一致,选举出sentinel-3节点作为领导者负责故障转移
    1. 对其执行slaveof no one命令使其成为新的主节点
    2. 原来的从节点(slave-1)成为新的主节点后,更新应用方的主节点信息,重新启动应用方
    3. 客户端命令另一个从节点(slave-2)去复制新的主节点(new-master)
    4. 待原来的主节点恢复后,让它去复制新的主节点。
  4. Sentinel领导者节点执行了故障转移

    故障>协商>从节点1--slaveof no one--升主>通知client>从节点2复制新的主节点>原来的主节点恢复后复制新的主节点



Redis Sentinel具有以下几个功能:

  1. 监控(Monitoring):Sentinel节点会定期检测Redis数据节点的状态
  2. 通知(Notification):Sentinel节点会将故障转移后的结果通知给应用方
  3. 故障转移(Failover):实现自动的故障转移
  4. 配置中心(Configuration):在Redis Sentinel架构中,客户端连接的是Sentinel节点集合而不是直接连接的Redis数据节点

安装和部署

角色 ip port 别名(为了后文中方便)
master 127.0.0.1 6379 主节点或者 6379 节点
slave - 1 127.0.0.1 6380 slave - 1 节点或者 6380 节点
slave - 2 127.0.0.1 6381 slave - 2 节点或者 6381 节点
sentinel - 1 127.0.0.1 26379 sentinel - 1 节点或者 26379 节点
sentinel - 2 127.0.0.1 26380 sentinel - 2 节点或者 26380 节点
sentinel - 3 127.0.0.1 26381 sentinel - 3 节点或者 26381 节点

部署数据节点

  1. 主节点
vi redis-6379.conf

port 6379
daemonize yes
logfile "/var/log/redis-6379.log"
dbfilename "dump-6379.rdb"
dir "/var/redis/data/"
  • daemonize yes # 后台运行
  • logfile "/var/log/redis-6379.log" # 日志文件
  • dbfilename "dump-6379.rdb" # 持久化文件名
  • dir "/var/redis/data/" # 持久化文件存放目录

redis-server redis-6379.conf

  1. 从节点
vi redis-6380.conf

port 6380
daemonize yes
logfile "/var/log/redis-6380.log"
dbfilename "dump-6380.rdb"
dir "/var/redis/data/"
slaveof 127.0.0.1 6379
vi redis-6381.conf

port 6381
daemonize yes
logfile "/var/log/redis-6381.log"
dbfilename "dump-6381.rdb"
dir "/var/redis/data/"
slaveof 127.0.0.1 6379
  • slaveof 127.0.0.1 6379 # 从节点复制主节点的地址和端口

redis-server redis-6380.conf

redis-server redis-6381.conf

redis-cli -p 6379 info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6380,state=online,offset=491,lag=0
slave1:ip=127.0.0.1,port=6381,state=online,offset=491,lag=1
master_repl_offset:491
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:490

此时拓扑如下:

部署Sentinel节点

vi redis-sentinel-26379.conf  # 26379、26380、26381的配置文件类似,只是端口不同

port 26379
daemonize yes
logfile "/var/log/26379.log"
dir /var/redis/data/
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel down-after-milliseconds mymaster 30000
sentinel parallel-syncs mymaster 1
sentinel failover-timeout mymaster 180000

Sentinel节点的默认端口是26379

sentinel monitor mymaster 127.0.0.1 63792

sentinel-1节点需要监控127.0.0.1:6379这个主节点,

2代表判断主节点失败至少需要2个Sentinel节点同意,

mymaster是主节点的别名

超过了down-after-milliseconds配置的时间且没有有效的回复,则判定节点不可达

parallel-syncs就是用来限制在一次故障转移之后,每次向新的主节点发起复制操作的从节点个数



sentinel failover-timeout mymaster 180000 # 故障转移超时时间

sentinel auth-pass mymaster mypassword # 认证密码

sentinel notification-script mymaster /var/redis/notify.sh # 故障通知脚本,当故障转移发生时,会执行这个脚本

sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # 客户端重新配置脚本,当故障转移发生时,会执行这个脚本

启动:

redis-sentinel redis-sentinel-26379.conf
redis-server redis-sentinel-26379.conf --sentinel
redis-cli -p 26379 info sentinel
# Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=mymaster,status=ok,address=127.0.0.1:6379,slaves=2,sentinels=3

此时拓扑如下:

Seninel配置优化

Redis安装目录下有一个sentinel.conf,是默认的Sentinel节点配置文件

port 26381
daemonize yes
logfile "/var/log/26381.log"
dir "/var/redis/data"
sentinel monitor mymaster 127.0.0.1 6379 2
sentinel config-epoch mymaster 0
sentinel leader-epoch mymaster 0
sentinel known-slave mymaster 127.0.0.1 6380
# Generated by CONFIG REWRITE
sentinel known-slave mymaster 127.0.0.1 6381
sentinel known-sentinel mymaster 127.0.0.1 26380 187ef7cee830e5728fdcf913682f8acc69bca9f6
sentinel known-sentinel mymaster 127.0.0.1 26379 131c66c696c7d604728d2102475dfce8b37d15b2
sentinel current-epoch 0
  • 部署技巧
  1. Sentinel节点不应该部署在一台物理“机器”上
  2. 部署至少三个且奇数个的Sentinel节点

3个以上是通过增加Sentinel节点的个数提高对于故障判定的准确性,因为领导者选举需要至少一半加1个节点,奇数个节点可以在满足该条件的基础上节省一个节点

sentinel API

Sentinel节点是一个特殊的Redis节点,它有自己专属的API

sentinel masters  # 查看所有被监控的主节点信息
sentinel master mymaster # 查看指定主节点的详细信息
sentinel slaves mymaster # 查看指定主节点的所有从节点信息
sentinel sentinels mymaster # 查看指定主节点的所有Sentinel节点信息
sentinel get-master-addr-by-name mymaster # 查看指定主节点的地址和端口
sentinel reset mymaster # 清除 Sentinel 内部关于 mymaster 的所有状态信息、重新发现并注册 mymaster 的从节点和哨兵节点(通过向主节点发送 ROLE 命令获取拓扑信息)
sentinel failover mymaster # 手动触发故障转移
sentinel ckquorum mymaster # 检查 Sentinel 集群是否可以就故障转移达成共识
sentinel flushconfig # 将Sentinel节点的配置强制刷到磁盘上,通常用于磁盘损坏导致配置丢失
sentinel remove mymaster # 移除监控的主节点
sentinel monitor mymaster 127.0.0.1 6379 2 # 添加监控的主节点,和配置文件的一致

实现原理

三个定时任务

Redis Sentinel通过三个定时监控任务完成对各个节点发现和监控

  1. 每隔10秒,每个Sentinel节点会向主节点和从节点发送info replication命令获取最新的拓扑结构-->master、slave

  2. 每隔1秒,每个Sentinel节点会向主节点、从节点以及其他Sentinel节点发送ping命令做一次心跳检测

  3. 每隔2秒,每个Sentinel节点会向Redis数据节点的__sentinel__:hello频道上发送该Sentinel节点对于主节点的判断以及当前Sentinel节点的信息

简单的说,就两个作用
1. 了解其他的Sentinel节点信息
2. 了解其他Sentinel节点对于主节点的状态判断 具体细节:
每个 Sentinel 节点既是消息的发布者,也是订阅者。
Sentinel 会向所有已知的数据节点(master 和 slave)发送发布 / 订阅命令 Sentinel 启动时:
向所有已知的 master 和 slave 节点发送 SUBSCRIBE __sentinel__:hello 命令,订阅该频道。
定时任务触发时:
向所有已知的 master 和 slave 节点发送 PUBLISH __sentinel__:hello "消息内容" 命令,发布自身状态和主节点判断。
消息传递逻辑:
无论消息发布到 master 还是 slave,只要节点在线,订阅该频道的其他 Sentinel 都能收到消息(因为 Redis 的 Pub/Sub 是节点级别的,不依赖数据同步)。

主观下线和客观下线

  1. 主观下线

  2. 客观下线

    当Sentinel主观下线的节点是主节点时,该Sentinel节点会通过sentinel is-master-down-by-addr命令向其他Sentinel节点询问对主节点的判断

    当超过个数的Sentinel节点认为主节点确实有问题,这时该Sentinel节点会做出客观下线的决定,这样客观下线的含义是比较明显了,也就是大部分Sentinel节点都对主节点的下线做了同意的判定,那么这个判定就是客观的

    例如sentinel-1节点对主节点做主观下线后,会向其余Sentinel节点发送该命令:

    sentinel is-master-down-by-addr 127.0.0.1 6379 0 *

日志分析

先kill掉主节点,然后启动原主节点

2793:X 18 Jun 13:39:34.452 # +sdown master mymaster 127.0.0.1 6379  # Sentinel(进程 ID 2793)主观认为 mymaster 主节点(127.0.0.1:6379)下线(不可达)
2793:X 18 Jun 13:39:34.536 # +new-epoch 6 # 开启一个新的选举纪元(Epoch 6)
2793:X 18 Jun 13:39:34.539 # +vote-for-leader 187ef7cee830e5728fdcf913682f8acc69bca9f6 6 # # 当前 Sentinel 投票给节点 187ef7...(另一个 Sentinel)作为领导者
2793:X 18 Jun 13:39:34.539 # +odown master mymaster 127.0.0.1 6379 #quorum 2/2 # Sentinel 集群达成共识,认为 mymaster 客观下线。
2793:X 18 Jun 13:39:34.539 # Next failover delay: I will not start a failover before Wed Jun 18 13:45:34 2025 # 此次故障转移后,6分钟内不会再次发起故障转移
2793:X 18 Jun 13:39:35.616 # +config-update-from sentinel 127.0.0.1:26380 127.0.0.1 26380 @ mymaster 127.0.0.1 6379 # 从 Sentinel 节点 127.0.0.1:26380 接收新的配置信息。
2793:X 18 Jun 13:39:35.616 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381 # 故障转移成功,新主节点切换为 127.0.0.1:6381。
2793:X 18 Jun 13:39:35.616 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381 # 新主节点(6381)开始管理从节点。
2793:X 18 Jun 13:39:35.616 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381 # 新主节点(6381)开始管理从节点。
2793:X 18 Jun 13:40:05.696 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381 # Sentinel 认为从节点(6379)下线。 2797:X 18 Jun 13:39:34.455 # +sdown master mymaster 127.0.0.1 6379 # +sdown:主观下线
2797:X 18 Jun 13:39:34.532 # +odown master mymaster 127.0.0.1 6379 #quorum 3/2 # +odown:Sentinel 集群达成共识,确认主节点客观下线
2797:X 18 Jun 13:39:34.532 # +new-epoch 6 # +new-epoch 6:开启一个新的选举纪元(Epoch),用于区分不同轮次的故障转移。
2797:X 18 Jun 13:39:34.532 # +try-failover master mymaster 127.0.0.1 6379 # +try-failover:尝试发起故障转移,但不立即执行。需要等待领导者选举完成。
2797:X 18 Jun 13:39:34.533 # +vote-for-leader 187ef7cee830e5728fdcf913682f8acc69bca9f6 6 # +vote-for-leader:投票给领导者
2797:X 18 Jun 13:39:34.538 # 127.0.0.1:26381 voted for 187ef7cee830e5728fdcf913682f8acc69bca9f6 6 # 其他 Sentinel 节点(127.0.0.1:26381 和 26379)也投票给 187ef7...
2797:X 18 Jun 13:39:34.540 # 127.0.0.1:26379 voted for 187ef7cee830e5728fdcf913682f8acc69bca9f6 6 # 其他 Sentinel 节点(127.0.0.1:26381 和 26379)也投票给 187ef7...
2797:X 18 Jun 13:39:34.605 # +elected-leader master mymaster 127.0.0.1 6379 # +elected-leader:获得多数票,当选为故障转移领导者
2797:X 18 Jun 13:39:34.605 # +failover-state-select-slave master mymaster 127.0.0.1 6379 # +failover-state-select-slave:领导者开始选择从节点作为新的主节点候选者。
2797:X 18 Jun 13:39:34.706 # +selected-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 # +selected-slave:选中从节点 127.0.0.1:6381 作为新主节点。
2797:X 18 Jun 13:39:34.706 * +failover-state-send-slaveof-noone slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 # +failover-state-send-slaveof-noone:向选中的从节点(6381)发送 SLAVEOF NO ONE 命令,使其成为独立主节点。
2797:X 18 Jun 13:39:34.783 * +failover-state-wait-promotion slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 # +failover-state-wait-promotion:等待从节点(6381)完成主节点晋升
2797:X 18 Jun 13:39:35.543 # +promoted-slave slave 127.0.0.1:6381 127.0.0.1 6381 @ mymaster 127.0.0.1 6379 # +promoted-slave:从节点(6381)成功晋升为新主节点。
2797:X 18 Jun 13:39:35.543 # +failover-state-reconf-slaves master mymaster 127.0.0.1 6379 # +failover-state-reconf-slaves:开始重新配置其他从节点,使其复制新主节点(6381)。--127.0.0.1 6379:原主节点的 IP 和端口(故障转移后,该节点将作为从节点存在)。
2797:X 18 Jun 13:39:35.614 * +slave-reconf-sent slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 # +slave-reconf-sent:向从节点(6380)发送 SLAVEOF 命令,使其复制新主节点。
2797:X 18 Jun 13:39:36.622 * +slave-reconf-inprog slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 # +slave-reconf-inprog:从节点(6380)正在与新主节点(6381)建立复制连接。
2797:X 18 Jun 13:39:36.623 * +slave-reconf-done slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6379 # +slave-reconf-done:从节点(6380)完成配置,开始复制新主节点。
2797:X 18 Jun 13:39:36.678 # -odown master mymaster 127.0.0.1 6379 # -odown:取消原主节点(6379)的客观下线状态(但此时它仍是下线的)。
2797:X 18 Jun 13:39:36.678 # +failover-end master mymaster 127.0.0.1 6379 # +failover-end:故障转移流程结束
2797:X 18 Jun 13:39:36.678 # +switch-master mymaster 127.0.0.1 6379 127.0.0.1 6381 # +switch-master:主节点已从 127.0.0.1:6379 切换为 127.0.0.1:6381。
2797:X 18 Jun 13:39:36.679 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ mymaster 127.0.0.1 6381 # +slave:记录新的从节点列表
2797:X 18 Jun 13:39:36.679 * +slave slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381 # +slave:记录新的从节点列表
2797:X 18 Jun 13:40:06.697 # +sdown slave 127.0.0.1:6379 127.0.0.1 6379 @ mymaster 127.0.0.1 6381 # +sdown:原主节点(6379)作为从节点暂时不可达。
  1. 故障检测:Sentinel 先主观判断主节点下线(+sdown),后通过法定人数达成客观下线共识(+odown)。
  2. 领导者选举:Sentinel 通过投票选出负责故障转移的领导者(+elected-leader)。
  3. 新主选择与晋升:从从节点中选出最优节点(6381),并将其提升为新主(+promoted-slave)。
  4. 集群重组:通知其他从节点(6380、6379)复制新主(+slave-reconf-done)。
  5. 故障转移完成:更新集群拓扑(+switch-master),恢复服务可用性。
  • 故障转移

Redis五-哨兵的更多相关文章

  1. Redis之哨兵机制(五)

    什么是哨兵机制 Redis的哨兵(sentinel) 系统用于管理多个 Redis 服务器,该系统执行以下三个任务: ·        监控(Monitoring): 哨兵(sentinel) 会不断 ...

  2. redis架构~哨兵模式

    一 哨兵模式稳定版本  redis哨兵模式是redis自带的高可用框架,稳定版本为redis2.8以上二 哨兵模式建立  1 避免单点故障,建立启动多个哨兵进程  2 哨兵模式启动命令 redis-s ...

  3. redis的哨兵集群,redis-cluster

    #主从同步redis主从优先1.保证数据安全,主从机器两份数据一主多从2.读写分离,缓解主库压力主redis,可读可写slave身份,只读   缺点1.手动主从切换假如主库挂了,得手动切换master ...

  4. redis:哨兵集群配置

    最少配置1主2从3哨兵 一.引言 上一篇文章我们详细的讲解了Redis的主从集群模式,其实这个集群模式配置很简单,只需要在Slave的节点上进行配置,Master主节点的配置不需要做任何更改,但是有一 ...

  5. redis之哨兵集群

    一.主从复制背景问题 Redis主从复制可将主节点数据同步给从节点,从节点此时有两个作用: 一旦主节点宕机,从节点作为主节点的备份可以随时顶上来. 扩展主节点的读能力,分担主节点读压力. 但是问题是: ...

  6. Redis五种数据结构简介

    Redis五种结构 1.String 可以是字符串,整数或者浮点数,对整个字符串或者字符串中的一部分执行操作,对整个整数或者浮点执行自增(increment)或者自减(decrement)操作. 字符 ...

  7. redis五种数据类型的使用(zz)

    redis五种数据类型的使用 redis五种数据类型的使用 (摘自:http://tech.it168.com/a2011/0818/1234/000001234478_all.shtml ) 1.S ...

  8. redis 五种数据结构详解(string,list,set,zset,hash)

    redis 五种数据结构详解(string,list,set,zset,hash) Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存 ...

  9. redis五种数据类型的使用

    redis五种数据类型的使用 redis五种数据类型的使用 (摘自:http://tech.it168.com/a2011/0818/1234/000001234478_all.shtml ) 1.S ...

  10. redis五种数据类型的使用场景

    string 1.String 常用命令: 除了get.set.incr.decr mget等操作外,Redis还提供了下面一些操作: 获取字符串长度 往字符串append内容 设置和获取字符串的某一 ...

随机推荐

  1. Open diary(每天更新)

    .col-md-8 img { display: none } .comment img { display: unset } 这是一个open diary,就是公开日记. 为什么标题用英文呢?因为觉 ...

  2. Cursor预测程序员行业倒计时:CTO应做好50%裁员计划

    提供AI咨询+AI项目陪跑服务,有需要回复1 前两天跟几个业内同学做了一次比较深入的探讨,时间从15.00到21.00,足足6个小时! 其中有个问题特别有意思:从ChatGPT诞生到DeepSeek爆 ...

  3. AndrodStudio构建时报错Could not find com.android.tools.build:gradle:xxx

    检查配置的版本号在maven仓库里有没有. maven仓库地址: https://repo1.maven.org/maven2/com/android/tools/build/gradle/ 选择需要 ...

  4. lua随写

    --local util={}--function util.Split(str, sep)-- local sep, fields = sep or ":", {}-- loca ...

  5. (原创)[开源][.Net Framework 4.5] SimpleMVVM(极简MVVM框架)更新 v1.1,增加NuGet包

    一.前言 意料之外,也情理之中的,在主业是传统行业的本人,技术的选型还是落后于时代. 这不,因现实需要,得将大库中的 WPF MVVM 相关部分功能拆分出来独立使用,想着来都来了,就直接开源得了,顺便 ...

  6. 康谋分享 | ADTF过滤器全面解析:构建、配置与数据处理应用

    在ADTF (Automotive Data and Time-Triggered Framework)中,过滤器(Filter)扮演着数据处理的核心角色.过滤器是处理数据流的基本单元,它们接收.处理 ...

  7. Python 潮流周刊#98:t-string 语法被正式接纳了(摘要)

    本周刊由 Python猫 出品,精心筛选国内外的 250+ 信息源,为你挑选最值得分享的文章.教程.开源项目.软件工具.播客和视频.热门话题等内容.愿景:帮助所有读者精进 Python 技术,并增长职 ...

  8. js多线程new worker报错cannot be accessed from origin 问题

    ---- Web Workers 为 Web 前端网页上的脚本提供了一种能在后台进程中运行的方法.一旦它被创建,Web Workers 就可以通过 postMessage 向任务池发送任务请求,执行完 ...

  9. infiniswap用到的技术

    infiniswap来自 NSDI'17,其代码主要用到以下技术: configfs(主要) configfs-用户空间控制的内核对象配置 https://www.kernel.org/doc/Doc ...

  10. java串口通信

    实体 package com.hwd.campus.common.common.utils.http; import gnu.io.SerialPort; /** * 串口参数封装类 * @autho ...