话不多说,先上一个类图。NamingClientProxyDelegate是这一块比较核心的类,像一个装配工厂一样,将各个工具类组装起来,对外提供接口。
Nacos权限模块整合方案
Nacos是阿里巴巴开源的,用于服务发现和配置管理的中间件。配置中心已经使用Apollo,所以我们只需要使用服务发现能力即可。
问题
学习研究Nacos过程中,发现如下几点:
- Nacos的支持插件机制,包括权限模块
- Nacos管理后台,支持使用LDAP的方式对接已有权限系统
- Spring-cloud-nacos客户端需要配置用户名和密码,才能正常注册
第2点是为了用户方便使用公司内部账号访问Nacos。但这结合第3点使用就出现了冲突。假设一个部门多个人同时进行开发,这样某个人的用户名和密码就会暴露给了其他开发人员。
1 | spring.cloud.nacos.discovery.namespace=provider |
Nacos本地身份验证和Ldap身份验证的区别
翻了一下源码,这两个方式,主要区别在于,ldap方式会先用Nacos本地身份验证,如果验证失败,才会使用ldap方式验证。
manager类涉及到身份认证,区别在上述已经说明。authPluginService涉及权限验证,两种方式代码完全是一样的,不存在差别。
Go语言协程调度器GPM模型
Consul leader节点Cpu占用高排查
利用工具分析Leader节点
进行dump
1、按照文档dump https://developer.hashicorp.com/consul/commands/debug
命令: consul debug -interval=5s -duration=30s -capture agent
2、使用可视化工具查看
需要安装golang,安装Graphviz,这里不多做赘述。
命令:go tool pprof profile.prof
输入:web
[ RocketMQ源码阅读 7 ] CommitLog文件刷盘方式
之前我们进行RocketMQ的搭建,其中有一个参数是用来配置刷盘方式的。存在“同步”和“异步”两种方式。
1 | flushDiskType=ASYNC_FLUSH|SYNC_FLUSH |
和刷新磁盘逻辑相关的代码可以从这里开始看DefaultFlushManager
1 | class DefaultFlushManager implements FlushManager { |
从构造函数可以看到,要理解刷盘的行为,需要搞懂GroupCommitService同步刷盘,FlushRealTimeService 异步刷盘和CommitRealTimeService这三个类的名称取的不是很便于记忆和理解。
为了理解刷盘操作,我们去看更上一层的逻辑。在Broker接收到客户端的消息写入请求,并完成一系列的解析、校验放入内存等工作后。后续就需要将消息持久化到磁盘。
1 | public CompletableFuture<PutMessageStatus> handleDiskFlush(AppendMessageResult result, MessageExt messageExt) { |
GroupCommitService和FlushRealTimeService的主要区别在于调用flush传入的刷新数据页数(RocketMQ内部逻辑概念,和计算机系统的页无关)。GroupCommitService每次都做刷新都传入0,FlushRealTimeService则按照规则进行计算出页数。我这边按照原逻辑改写的容易理解的伪代码:
1 | int flushPhysicQueueLeastPages = 4; |
这段代码避免了短时间内进行多次全量刷盘,从而提高了刷盘效率和性能呢。正因为异步刷盘不是每次都是全量刷盘,从这个角度来看才会被称为异步刷盘,其实本质上都是异步进行刷盘的。
transientStorePoolEnable
我们在上述刷盘代码中看到了此配置项。该配置项是为了提高IO性能,但是在Broker JVM进程异常退出的时候增加丢消息的风险。感兴趣的同学可以看这篇文章
[ RocketMQ源码阅读 6 ] Broker磁盘文件格式与作用
Broker的功能点很多,安装程序启动的顺序去看源码,发现代码量比之前的组件要大很多。阅读过程中发现Broker会去持久化一些配置,并且会将消息数据存储在磁盘上。
整理和检索了网上的一些资料,列出了这些文件和相应的作用,如下。
- store
- commitlog
- 000000000
- xxxxxxxxxx
- compaction
- compactionLog
- {topic}
- 0
- 1
- …
- {queueId}
- {topic}
- compactionCq
- {topic}
- 0
- 1
- …
- {queueId}
- {topic}
- compactionLog
- config
- delayOffset.json
- broker.properties
- topics.json
- topicQueueMapping.json
- consumerOffset.json
- lmqConsumerOffset.json
- consumerOrderInfo.json
- subscriptionGroup.json
- timercheck
- timermetrics
- consumerFilter.json
- messageRequestMode.json
- tieredStoreMetadata.json
- consumequeue
- {topic}
- 0
- 00000000000000000000
- 1
- …
- {queueId}
- 0
- {topic}
- index
- 20240305101010000
- abort
- checkpoint
- lock
- timerwheel
- timerlog
- 00000000000000000000
- commitlog
中年人的第一台NAS
最近闲来无事,想体验一下NAS的玩法。那么说干就干。
发扬垃圾佬的精神,追求极致性价比。性能、功耗、价格不可能三角,尽量把钱花在刀刃上。考虑静音,所以必须要no fans。
网上查了一些资料,大概看了如下几款cpu。
cpu | 制程 | 主频 | TDP | 价格 |
---|---|---|---|---|
J3160 | 14nm | 4核4线程 1.6GHz | 6w | 板u 100 rmb左右 |
J1900 | 22nm | 4核4线程 2.42GHz | 10w | 整个小主机或者软路由某鱼200rmb |
N5095 | 10nm | 4核4线程 2GHz | 15w | 板U 538rmb |
从这3个cpu看,J3160不论功耗还是价格,对我来说是最为合适的。而且ddr3的内存也是价格实惠。功耗比较喜人才6w。算一下一年电费多少,假设整机功耗10w:
10 * 24 * 365 * 0.6元/1000 = 52元
相当喜人。。。
配件 | 来源 | 价格 |
---|---|---|
铭瑄N3160 | 闲鱼 | 106 |
动力之星dc转atx电源转换卡 | 拼多多 | 43 |
悠品12V5Adc电源 | 京东一手 | 38 |
ddr3 1600内存条8GB台式机内存 | 闲鱼 | 43 |
开机按钮 | 拼多多 | 5 |
硬盘120GB SSD | 闲鱼 | 43 |
8GB u盘 安装黑群晖 | 京东 | 14 |
SATA线*2 | 京东 | 9 |
总计 | 301 |
[ RocketMQ源码阅读 5 ] 集群部署与架构
[ RocketMQ源码阅读 4 ] ControllerManager
该组件的核心就是一个Raft协议的实现。这个Raft协议的实现用的也不是淘宝系的JRaft,而是第三方的产品DLedger。对于生产要求比较严格的大厂,这个倒是比较意外。
用这个组件一般就是用来实现选主,或者当一个存储数据库来使用。前几篇有说过RocketMQ使用ControllerManager组件来实现的灾备切换,那么我们来看一下究竟是如何实现的。
对外接口
ControllerRequestProcessor
名称 | 描述 | Raft操作类型 |
---|---|---|
CONTROLLER_ALTER_SYNC_STATE_SET | 往Raft日志同步syncStateSet | 写 |
CONTROLLER_ELECT_MASTER | 进行leader选举,将最终选出的Leader同步到Raft日志。让人震惊的是选主没有使用到Raft,而是自己实现的策略。 | 写 |
CONTROLLER_GET_REPLICA_INFO | 按照brokerName获取所有broker信息 | 读 |
CONTROLLER_GET_METADATA_INFO | 获取当前Raft集群所有Peer信息 | 读 |
BROKER_HEARTBEAT | Broker进行心跳 | 无 |
CONTROLLER_GET_SYNC_STATE_DATA | 获取syncStateSet数据 | 读 |
UPDATE_CONTROLLER_CONFIG | 更新ControllerManager配置 | 无 |
GET_CONTROLLER_CONFIG | 读取ControllerManager配置 | 无 |
CLEAN_BROKER_DATA | 清理Broker数据 | 写 |
CONTROLLER_GET_NEXT_BROKER_ID | 获取下一个BrokerId | 读 |
CONTROLLER_APPLY_BROKER_ID | 写入BrokerId | 写 |
CONTROLLER_REGISTER_BROKER | 使用唯一的BrokerId注册Broker | 写 |