- 博客(192)
- 收藏
- 关注
原创 Dubbo 通信流程 - 服务的调用
在中讲到,Dubbo 会为注解了 @DubboReference 的 Bean 创建代理对象并注册到 Spring 容器中。对类成员进行依赖注入时,Spring 会调用工厂对象 ReferenceBean 的 getObject 方法获取 Bean,该方法返回一个懒加载的代理对象。
2025-03-30 17:36:04
873
原创 Dubbo SPI 加载逻辑
Dubbo 通过 loadExtensionClasses 方法加载 SPI。通过 strategies 加载扩展点集合,三个 LoadingStrategy 指定的目录分别为 ‘META-INF/dubbo/internal/, META-INF/dubbo/, META-INF/services/’。
2025-03-23 16:45:40
849
原创 Dubbo 服务发现
比如用户配置了 zookeeper:127.0.0.1:2181,Dubbo 在导出服务时解析出 name = zookeeper,便拿着这个名字到 ExtensionLoader 加载得到 ZookeeperServiceDiscoveryFactory,该工厂类生产出 ZookeeperServiceDiscovery,后续 ServiceDiscoveryRegistry 便可以通过调用 ZookeeperServiceDiscovery 的 doRegister 方法注册服务。
2025-03-16 23:41:14
487
原创 Dubbo 过滤器链设计解析
Dubbo 中的过滤器(Filter)是实现了 org.apache.dubbo.rpc.Filter 接口的类,每个过滤器可以在服务调用的不同阶段执行特定的逻辑,如日志记录、权限验证、异常处理等。实际调用时,会调用 filter1 的 invoke 方法,而每个 filter 的 invoke 方法会调用下一节点的 invoke 方法。服务调用请求依次经过链上的每个过滤器,最终到达目标服务,响应则按照相反的顺序返回。Dubbo 过滤器链的实现是典型的责任链模式。
2025-03-16 17:49:58
147
原创 Dubbo 通信流程 - 服务的创建、导出与注册
在 Spring 容器启动过程中,当所有的 Bean 定义信息(BeanDefinition)加载完成后,但 Bean 实例还未开始创建时,Spring 会优先调用 BeanDefinitionRegistryPostProcessor 的 postProcessBeanDefinitionRegistry 方法。循环扫描出来的 BeanDefinition 集合,在循环体中,从已扫描的 Bean 定义中,提取注解属性和服务接口名,然后创建一个新的 ServiceBean 类型的 Bean 定义。
2025-03-10 00:20:09
815
原创 Dubbo 通信流程 - 客户端代理对象的创建
服务代理创建:客户端通过 ReferenceConfig 引用服务时,Dubbo 会使用代理工厂(ProxyFactory)为服务接口创建一个代理对象。当客户端调用该代理对象的方法时,实际调用的是代理对象的拦截逻辑。拦截器链处理:调用请求会经过一系列的拦截器(Filter),这些拦截器可以对请求进行预处理、日志记录、权限验证等操作。请求编码:经过拦截器链处理后,请求会被编码为适合网络传输的格式,如 Dubbo 协议的二进制格式。网络传输:编码后的请求通过网络发送到服务端。
2025-02-24 00:44:40
835
原创 一个ID生成器的代码重构示例
如何发现代码质量问题?从大处着眼的话,我们可以参考之前讲过的代码质量评判标准,看这段代码是否可读、可扩展、可维护、灵活、简洁、可复用、可测试等等。落实到具体细节,我们可以从以下几个方面来审视代码。
2025-02-01 15:05:06
520
原创 Dubbo知识点总览
Exchange:信息交换层,用于封装请求并模式同步、异步获取响应结果。Cluster:路由层,选择调用的服务提供者,实现路由过滤和均衡负载。Serialize:数据序列化层,将对象和二进制数据进行相互转换。Transport:传输层,将数据通过网络发送至对端服务。Config:RPC调用的配置,如超时时间、重试、缓存。Registry:注册中心,给出调用方IP。Protocol:远程调用层,封装调用过程。Service:服务代码的实现。Proxy:远程调用的服务代理。Monitor:监控层。
2025-01-19 23:05:42
170
原创 DDD FAQs梳理
DDD主要关注:从业务领域视角划分领域边界,构建通用语言进行高效沟通,通过业务抽象,建立领域模型,维持业务和代码的逻辑一致性。
2025-01-19 18:04:16
408
原创 Java ThreadLocal 源码解析
使用 ThreadLocal 时,可以将数据存储在一个特殊的对象中,这个对象会被自动关联到当前线程。如果想要在创建 ThreadLocal 对象时就设置初始值,可以使用如果想要删除 ThreadLocal 中的值,可以调用remove()方法。ThreadLocalMap 的创建是懒加载的;ThreadLocal 的实现是通过将一个 ThreadLocalMap 作为 Thread 对象的成员实现的;每个线程的全部 ThreadLocal 都保存在 ThreadLocalMap 中。
2023-12-28 23:33:27
631
1
原创 Golang sync.Once 源码浅析
本文分析了Golangsync.Once源码,并由此引申,简单讨论了单例模式的实现、atomic包的作用和 Java volatile 的使用。sync.Once。
2023-02-19 17:15:25
735
原创 Spanner 论文小结
Spanner 论文小结,TrueTime API,时间戳分配策略,事务执行流程,死锁预防策略,wait-die, wound-wait。
2022-06-07 14:56:40
514
原创 CockroachDB: The Resilient Geo-Distributed SQL Database 论文阅读笔记
前言本文绝大部分内容源自 CockroachDB 论文。介绍CockroachDB 是一个可扩展(Scalable)的 SQL DBMS,它主要用于支撑 OLTP 工作流,并保持高可用性(High Availability)和强一致性(Strong Consistency)。论文主要呈现了 CockroachDB 创新的事务模型,它在商用硬件上支持一致(Consistent)的分布式事务。论文在 Introduction 提出了一个情景:一个公司在欧洲和澳洲有一个大用户基数,并且美国的用户数也在迅速
2022-05-31 23:07:25
931
1
原创 CockroachDB 分布式事务源码分析之 TxnCoordSender
TxnCoordSenderTxnCoordSender实现了Sender和TxnSender接口,Sender抽象了发送方法Send:// crdb 在 client 侧及 server 侧均有 Sender 接口的实现类型。// 一些实现类型如 client.Txn, kv.TxnCoordSender, storage.Node,// storage.Store, storage.Replica.type Sender interface { // Send 方法发送一个batch用于估算
2022-05-30 14:51:56
825
原创 Golang map源码浅析
设计概述runtime/map.go开头描述了map的设计要点。一个map是一个哈希表(hashtable);数据被组织成bucket数组,每个bucket最多8个键值对;哈希值的低位用于选择bucket下标,每个bucket包含哈希值的若干高位,用于定位一个bucket内的键值对;如果多于八个键被哈希到一个bucket中,将一个额外的bucket连接到其后面(拉链法);当哈希表需要扩容时,分配一个两倍大小的bucket数组;在扩容后,bucket被增量地从旧的bucket数组移到新的buc
2022-03-14 23:41:30
1335
原创 Go HTTP服务器源码浅析
简单服务器 Demo在 Go 编写一个服务器非常简单:func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("hello, world!")) }) http.ListenAndServe(":8080", nil)}之后便可以访问:~ curl localhost:8080/hello, world!也可以用
2022-02-26 11:45:48
1495
原创 Go的五种mock技术
简介良好的单元测试不仅可以在代码发布前验证代码是否可用,并且可以保护代码在以后的某一次修改中功能不被破坏。好的单元测试需要有自我隔离、可靠、无状态等特性。以下介绍五种 mock 技术。1. Higher-Order Functions当需要 mock 一个包级别函数的时候使用。以下代码打开一个数据库连接:func OpenDB(user, password, addr, db string) (*sql.DB, error) { conn := fmt.Sprintf("%s:%s@%s/%s"
2022-01-16 16:07:39
2604
原创 Go并发模式之Pipelines
简介Go的并发原语使构建流数据pipeline变得容易,流数据pipeline可以有效地利用I/O和多个CPU。本文介绍了此类pipeline的示例,强调了操作失败时出现的微妙之处,并介绍了干净地处理故障的技术。何为pipeline一个pipeline是指一系列用通道连接的阶段,每个阶段是一组运行同一个函数的go协程,在每一个阶段中的go协程:从上游管道接收数据在数据上执行一些操作,生成新的值将数据发到下游管道中例子:平方数第一个阶段将给定的数发到管道中,第二个阶段从管道接收数字,取平方
2021-11-16 15:14:26
1177
原创 Go并发模式之Context
简介在Go语言实现的服务器中,每个到达的请求被一个新的go协程处理。请求处理器经常开启额外的go协程访问后端,例如数据库、RPC服务。这一组服务同一个请求的go协程通常需要访问单个请求的某些值,例如终端用户的身份、权限token、请求的最后期限。context包让同一个请求处理的go协程间传值更为方便。它还能够在处理一个请求的一组go协程间传递取消信号、截止时间。ContextContext接口的源码如下:// Context的方法可以被并发调用type Context interface {
2021-11-15 17:01:43
569
原创 btcd交易流程之交易的打包上链(三)
为了了解交易是怎么被打包到区块,最后发布的,首先从 Bitcoin API Reference 以及 btcd API Reference 中查看相关的RPC调用。BitCoin RPCsgetblocktemplategetblocktemplate ( "template_request" )其描述如下:If the request parameters include a ‘mode’ key, that is used to explicitly select between the
2021-10-21 09:25:45
883
原创 btcd交易流程之交易的验证(二)
交易的验证从btcd.go中的main函数开始,调用了btcdMain,btcdMain中有以下代码: // Create server and start it. server, err := newServer(cfg.Listeners, cfg.AgentBlacklist, cfg.AgentWhitelist, db, activeNetParams.Params, interrupt)分析到底是什么Server:// newServer returns a new btcd s
2021-10-19 17:55:39
424
原创 btcd交易流程之交易的创建(一)
从btcd.go中的main函数开始,调用了btcdMain,btcdMain中有以下代码: // Create server and start it. server, err := newServer(cfg.Listeners, cfg.AgentBlacklist, cfg.AgentWhitelist, db, activeNetParams.Params, interrupt)我们看这个到底是什么Server:// newServer returns a new btcd serv
2021-10-19 17:35:45
13668
原创 6.824 Lab 4B: Sharded Key/Value Service
思路每个leader负责poll新的config,将一个config发到raft中,在applyCh收到该config后更新配置;leader依次poll下一个编号的config,并且只有在所有需要发送的shard已经被接收方接收、所有需要接收的shard已经收到后才会apply下一个config;接收shard、删除shard操作都需要写到raft日志中,让一个group里的majority都执行同样的操作;如果一个接收者5秒内没有接收一个shard(即发送AddShard RPC失败),则默认该
2021-09-11 20:36:46
578
原创 6.824 Lab 3B: Fault-tolerant Key/Value Service
简介一个长期运行的raft服务器会积累大量的日志,这些日志放在内存里将占用大量空间。为了压缩日志占用的空间,raft可以通过快照将当前kvserver的状态存储下来,并丢弃已经被apply的日志。思路日志压缩后,因为被包含在snapshot里的entry都被移除,entry的下标 ≠ entry index - 1,这时:entry下标 = entry index - lastIncludedIndex - 1或entry index = entry下标 + lastIncludedIndex
2021-08-27 12:32:14
831
原创 6.824 Lab 3A: Fault-tolerant Key/Value Service
简介lab3主要是用lab2实现的raft做一个容错的键值存储服务。lab3A主要是实现一个没有日志压缩功能的键值存储系统。理想情况下的kvraft思路首先实现一个不存在消息丢失情况下的解决方案。ClientClerk记录一个leaderId,每次发送RPC时从leaderId开始。需要不断重复发送RPC,直至请求成功。Server存储k/v的是一个简单的map[string]string;PutAppend、Get方法调用底层raft的Start方法并在对应的通道上等待消息;在serv
2021-08-22 15:04:39
976
原创 6.824 Lab 2: Raft
简介lab2主要是根据论文 In Search of an Understandable Consensus Algorithm (Extended Version) 做一个复制状态机(replicated state machine)并以此做一个有容错性的存储k/v的分布式系统。思路整个lab2分为ABC三个部分:lab2A主要完成leader election部分,从多个server中选举出一个leader,并让选出的leader周期性地发送心跳包给各follower;lab2B主要完成日志
2021-08-15 11:39:00
1106
原创 6.824 Lab 1: MapReduce
lab源地址简介根据MapReduce Paper构造一个MapReduce系统。该系统主要包括master和worker。master主要负责分发任务、处理worker故障;worker主要负责根据map、reduce函数读写文件。思路任务分发:master将需要完成的任务放到通道中,让worker从通道中拿取任务,根据任务类型完成相应的操作。容错:master跟踪每个任务的完成情况,如果一个任务超过一定时间仍未完成,则重新发布该任务。完成情况判断:master直接判断当前目录的目标文件是否存
2021-07-31 14:15:38
444
原创 1115. 交替打印FooBar
题目描述我们提供一个类:class FooBar { public void foo() { for (int i = 0; i < n; i++) { print("foo"); } } public void bar() { for (int i = 0; i < n; i++) { print("bar"); } }}两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法,另
2021-04-30 23:40:42
342
1
原创 Go实现并发缓存
首先用一个例子演示函数记忆:// A Memo caches the results of calling a Func.type Memo struct { f Func cache map[string]result}// Func is the type of the function to memoize.type Func func(key string) (interface{}, error)type result struct { value interface
2021-04-18 21:28:01
574
2
原创 Go设计并发Web爬虫
串行爬虫首先用最简单的方法实现crawler,用串行的方式爬取页面:在这里用广度优先搜索,将搜索到的页面放到一个队列中,每次再从队列中拿出一个页面进行处理。//crawl函数能爬取一个页面的所有链接func crawl(url string) []string { fmt.Println(url) list, err := links.Extract(url) if err != nil { log.Print(err) } return list}func main() {
2021-04-16 23:47:04
386
原创 go自定义排序规则
实现自定义排序规则定义一个结构体及计算其length的函数:type Track struct { Title string Artist string Album string Year int Length time.Duration}func length(s string) time.Duration { d, err := time.ParseDuration(s) if err != nil { panic(s) } return d}样例数据如下:var
2021-04-15 22:17:04
1011
原创 HashMap源码浅析
HashMap简介HashMap继承了AbstractMap,实现了Map, Cloneable, Serializable接口:HashMap的一些参数HashMap的默认起始大小为16,最大容量为2^30: /** * The default initial capacity - MUST be a power of two. */ static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // ak
2021-04-03 12:04:19
129
原创 ucore lab3
练习1:给未被映射的地址映射上物理页(需要编程)本实验要求完成do_pgfault函数,作用给未被映射的地址映射上物理页。具体而言,当启动分页机制以后,如果一条指令或数据的虚拟地址所对应的物理页框不在内存中或者访问的类型有错误(比如写一个只读页或用户态程序访问内核态的数据等),就会发生页错误异常。产生页面异常的原因主要有:1.目标页面不存在(页表项全为0,即该线性地址与物理地址尚未建立映射或者已经撤销);2.相应的物理页面不在内存中(页表项非空,但Present标志位=0,比如在swap分区或磁盘
2021-03-26 23:53:33
244
原创 ucore lab2
练习1:实现 first-fit 连续物理内存分配算法(需要编程)物理页面的结构体如下:/* * * struct Page - Page descriptor structures. Each Page describes one * physical page. In kern/mm/pmm.h, you can find lots of useful functions * that convert Page to other data types, such as phyical addr
2021-03-26 23:52:56
309
原创 ucore lab1
练习1:理解通过make生成执行文件的过程问题一:操作系统镜像文件ucore.img是如何一步一步生成的?(需要比较详细地解释Makefile中每一条相关命令和命令参数的含义,以及说明命令导致的结果)在Makefile中生成ucore.img的代码如下:# create ucore.imgUCOREIMG := $(call totarget,ucore.img)$(UCOREIMG): $(kernel) $(bootblock) $(V)dd if=/dev/zero of=$@ coun
2021-03-26 23:51:48
330
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人