自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(61)
  • 收藏
  • 关注

原创 深入浅出Redis持久化

redis作为内存数据库,数据都在内存里,如果突然宕机,则数据都会丢失(这里假设不使用非易失性内存),redis提供了持久化机制来防止这种情况发生如果将redis仅作为缓存使用,且不需要宕机后快速生成缓存数据,可以不使用持久化机制,还能提升性能RDB(redis database):定时将某一时刻内存中的数据保存到磁盘上AOF(append only file)

2025-01-16 20:52:55 1007

原创 kratos源码分析:限流器

无论是在单体服务中还是在微服务中,提供的API接口都是有访问上限的当非预期的请求对系统压力过大,我们就必须考虑使用限流来丢弃部分请求,以保障服务整体可用,以防止压力超出系统承载上限而拖垮系统

2024-12-22 18:25:51 1009

原创 kratos源码分析:熔断器

一般来说,当服务器过载(overload)时,需要给client返回服务过载的报错。,可能响应错误码本身没啥成本,但处理请求协议栈,构建响应header等也有一笔开销。接下来分析kratos中熔断器,其采用了google sre的自适应客户端限流算法

2024-12-21 22:16:46 1128

原创 gorm源码解析(四):事务,预编译

前几篇文章介绍gorm的整体设计,增删改查的具体实现流程。本文将聚焦与事务和预编译部分

2024-12-18 23:04:47 1281

原创 gorm源码解析(三):增删改查流程

前两篇文章介绍了ORM框架的必要性,以及gorm框架的整体设计。本文将深入增删改查流程,看gorm具体是怎么将对象转化为sql,以及将结果解析成对象构造clause构造sql执行sql处理结果

2024-12-18 08:33:30 816

原创 gorm源码解析(二):核心设计与初始化

上一篇文章介绍了什么是ORM框架,以及为啥需要ORM框架。从这篇文章开始将介绍gorm的底层实现原理

2024-12-15 23:30:44 850

原创 gorm源码解析(一):ORM概览

ORM(Object-Relational Mapping)是对象关系映射的框架开发者可以使用熟悉的面向对象方式来操作数据库,而无需直接编写繁琐的SQL语句执行增删改时完成从对象到sql的转换。例如当用户create一个对象时,ORM框架需要根据该对象,生成一条INSERT的sql解析查询结果时完成从结果到对象的转换。当从mysql server接收到查询结果时,ORM框架需要将其转换为业务model对象

2024-12-15 18:24:57 696

原创 Go mysql驱动源码分析

根据交互协议,完成往mysql server发送请求和解析响应的具体操作执行客户端预编译操作

2024-12-08 21:24:35 1323

原创 Go database/sql包源码分析

本文将分析database/sql包的架构设计和实现原理 阅读go源码版本:go1.23.3

2024-12-08 09:52:17 1276

原创 分布式唯一ID生成(四):tinyid

tinyid的主要特性有:- 生成全局唯一的64位数字ID- 趋势递增的id:趋势递增的意思是,id是递增但不一定是连续的- 支持生成1,3,5,7,9…序列的ID- 支持配置多个db,每次随机从一个db获取号段,提高可用性- 支持client获取一批ID,然后本地发号,提升性能

2024-11-10 18:07:06 895

原创 分布式唯一ID生成(三):uid-generator

UidGenerator是Java实现的, 基于Snowflake算法的唯一ID生成器以组件形式工作在应用项目中,和leaf 不同,leaf是提供server集群,client调server获取ID通过特殊的workerId分配策略,解决workerId不好手动指定,以及唯一性问题通过时钟不回退解决时钟回拨导致的ID重复问题通过借用未来时间来解决雪花算法天然存在的并发限制下面依次分析这些特性的实现原理

2024-11-10 11:18:18 1387

原创 分布式唯一ID生成(二): leaf

本文将介绍leaf号段模式和雪花算法模式的设计原理,并走读源码leaf提供了,业务只管调leaf server的接口获取ID,leaf serve内部根据号段或雪花算法生成ID,而不是业务服务自己去请求数据库生成id,或自己根据雪花算法生成idleaf提供两种分布式ID生成策略:每次从db获取一批ID,而不是一个ID,减少调DB的频率用双buffer解决TP999耗时高的问题在内存判断参数biz是否合法,提高校验性能使用动态step,解决突发流量造成对db压力仍然大的问题。

2024-11-09 20:06:34 1333

原创 漫谈分布式唯一ID

在大多数业务场景中,需要对每条数据分配一个唯一ID作为标识。大部分关系型数据库提供了自增主键功能来支持该需求但若数据量较大,需要分库分表时,就不能使用每个数据库实例提供的自增键功能,因为不能保证在所有表中唯一,分布式全局唯一ID的需求应运而生全局唯一性:在某个业务场景下唯一,避免数据冲突,这是最基本的要求高性能:生成速度快,不能阻塞业务流程趋势递增:通常会将该ID作为数据库主键,由于mysql innoDB采用聚集索引,若新增的记录主键无序,可能造成 叶分裂和 空间利用率不高。

2024-11-09 13:22:22 1274

原创 深入理解对象池 sync.Pool

当多个 goroutine 都需要创建同⼀种对象的时候,如果 goroutine 数量过多,导致对象的创建剧增,进⽽导致 GC 压⼒增大。并发⼤-->占⽤内存⼤-->增加GC频率-->限制程序执行效率-->处理并发能⼒降低-->并发更⼤此时就需要有⼀个对象池,每个 goroutine 不⾃⼰调mallocgc从runtime分配对象,⽽是从对象池中获取⼀个对象,用完后再把对象放回池里。sync.Pool就是这样一个对象池,可以减少GC频率和内存分配减少GC频率:内存分配少了,出发GC的频率就会降低。

2024-11-05 22:31:07 1482

原创 本地缓存库分析(五):groupcache

groupcache是一个分布式本地缓存库,根据一致性hash算法决定某个key由自己负责,还是别的节点负责存在本地的缓存用LRU管理内存淘汰这个库只暴露了get接口(传一个fn进去,缓存中Get不到时调fn从其他地方获取数据,放入缓存),而不支持set/update/delete操作。因此适用场景有限,适合那种对于给定key来说,value不会变的数据例如静态文件,拿md5当key,value是文件内容这么做的好处是不会有更新导致的缓存一致性问题,因为就更新不了下面对一些关键设计进行分析

2024-11-05 11:57:22 903 1

原创 本地缓存库分析(四):fastcache

什么是fastcache?支持高并发支持存储大量数据,但对GC压力小严格内存限制代码非常简单,易于理解本文将剖析其设计及代码实现,版本:v1.12.2问题解决锁竞争严重解决,用了多个segment大量缓存写入,导致gc标记阶段占用cpu多解决,指针数量约等于总数据量/64KB 个内存占用不可控解决,底层数组占用空间是固定的。索引占用的不固定,但索引占用空间小不支持缓存按时效性淘汰按FIFO淘汰不支持缓存过期不支持缓存数据可以被污染解决,使用序列化后的字节数组。

2024-11-04 21:52:19 969

原创 本地缓存库分析(三):freecache

什么是freecache?0 GC开销支持高并发支持过期时间近似LRU缓存淘汰严格限制内存使用量可以说是功能特性非常全面的一款本地缓存库了,非常适合在工程中使用本文先介绍 freecache 中值得学习的设计细节,然后简要分析主要流程 get 和 set的源码,版本:v1.2.4问题解决锁竞争严重解决,用了多个segment大量缓存写入,导致gc标记阶段占用cpu多解决,不管多大数据量,一共只有512个指针内存占用不可控解决,底层数组占用空间是固定的。

2024-11-04 12:31:02 931

原创 详解varint,zigzag编码, 以及在Go标准库中的实现

当我们用定长数字类型int32来表示整数时,为了传输一个整数1,我们需要传输00000000 00000000 00000000 00000001 32 个 bits,而有价值的数据只有 1 位。这就导致了大量的空间浪费,因为大部分字节并没有实际存储有效的信息

2024-10-27 23:46:27 1210

原创 本地缓存库分析(二):bigcache

一个本地缓存必然要支持并发访问,如果用一个sync.Mutex锁住整个缓存,会导致整个缓存的读写串行化,性能很低。于是BigCache使用了分片机制表面上bigcache中所有的数据是存在一个大cache里面,但实际上底层数据分成了N个不互重合的部分,每一个部分称为一个shard

2024-10-27 12:54:50 1251

原创 本地缓存库分析(一):golang-lru

如果用go自带的map实现本地缓存,大概有两种实现方式:1. sync.Map2. map + mutex.RWLock但有以下缺点:1. 锁竞争严重2. 大量缓存写入,导致gc标记阶段占用cpu多3. 内存占用不可控4. 不支持缓存按时效性淘汰5. 不支持缓存过期6. 缓存数据可以被污染:如果缓存的V是指针,那么业务修改了V的某个值为当前请求用户自己的值,在缓存中的V就被污染了

2024-10-26 12:10:56 922

原创 Golang bufio包源码分析

在上一篇文章中提到了用bufio来高效处理输入输出,本文来分析bufio高效的原理主要看bufio.Reader和bufio.Writer如何包装缓冲区和真正的reader,writer,实现高效IO阅读的go版本:1.22.6为啥要用bufio?提高性能:通过开辟一块缓冲区,减少系统调用的次数bufio.Reader:先调一次真正的reader读取一批数据到缓冲区,接下来的read就直接从缓冲区读,无需再调真正的reader发起系统调用。

2024-10-25 19:55:43 1134

原创 Golang 怎么高效处理ACM模式输入输出

最近在练习牛客上单调栈题目时,要求自己处理出入输出,也就是读题库要求的输入,计算最终结果,并打印输出当我用处理输入,用处理输出时:在数据量较大时超时了。。。算法本身已经是最优复杂度了,那问题只可能在输入输出上于是研究了下用go写算法笔试题时,怎么高效处理输入输出读取输入:需要用带缓冲的包装这里用到方法读取每一行,表示一直读,直到遇到换行符为止读取到每一行数据就好办了,按照空格分隔,转换成数字,调算法处理如果在自己的windows电脑写代码,但提交到OJ平台(一般在linux环境执行)时,需要注意两个平

2024-10-22 23:36:44 729

原创 开源限流组件分析(三):golang-time/rate

根据的分析,令牌桶限流的实现没必要真的准备一个桶,定时往里塞令牌,然后每次获取令牌时从桶中弹出,但这样做,需要开辟桶最大容量大小的空间最佳做法是利用的原理,只用维护一个桶中当前令牌数的变量,本文将分析go官方库提供的限流工具的使用及实现细节,也是令牌桶算法。并对下面这个问题给出合理的解释:在CancelAt方法中,为啥归还令牌时不是归还所有令牌,而是要扣减一个值,版本:v0.7.0。

2024-10-22 12:48:13 1333

原创 开源限流组件分析(二):uber-go/ratelimit

漏桶限流算法思路很简单,水(数据或者请求)先进入到漏桶里,漏桶以一定的速度出水,当水流入速度过大会直接溢出,漏桶算法能强行限制请求的处理速度相比于令牌桶中只要桶内还有剩余令牌,调用方就可以马上消费令牌的策略。漏桶相对来说更加严格,调用方只能按照预定的间隔顺序消费令牌

2024-10-18 20:28:08 1182

原创 开源限流组件分析(一):juju/ratelimit

这篇文章分析下go开源限流组件juju-ratelimit的使用方式和源码实现细节版本:v1.0.2其提供了一种高效的令牌桶限流实现令牌桶相比于其他限流算法(如漏桶算法)的一个显著优势,就是在突发流量到来时,可以短时间内提供更多的处理能力,以应对这些额外的请求直观上来说,令牌桶算法可以实现为:桶用channel实现在后台每隔一段固定的时间向桶中发放令牌要获取令牌时,从channel取数据// 每隔interval时间往channel中塞一个令牌select {// 放令牌。

2024-10-18 08:41:33 1283

原创 通俗易懂 证明欧几里得算法

用欧几里得算法计算最大公约数的方式非常神奇,本文将简要介绍计算步骤,并给出一个非常好懂的正确性证明。

2024-10-16 10:29:56 379

原创 rockscache源码分析:如何解决缓存db的最终一致性

当如下场景发生时,会直接导致缓存数据与数据库数据不一致:本文介绍(版本v0.1.1)中提供的方案,能较好地解决这个问题,让上图中的第5步写不进缓存,来达到最终一致性的效果。同时介绍如何处理缓存穿透,击穿,雪崩核心是两个方法:写数据时,调TagAsDeleted方法,将缓存置为标记删除。

2024-10-16 10:28:28 1121

原创 kratos源码分析:滑动窗口

在限流器、熔断器中,需要根据过去一段时间内的请求数据来判断本次请求是否可以放行此时就需要一个滑动窗口,用于平滑收集并统计这些数据。对于在窗口时间范围外的数据自动丢弃。

2024-10-15 20:53:00 638

原创 深入理解 sync.RWMutex 实现原理

读写锁sync.RWMutex,是互斥锁Mutex的一个改进版,适用于读取数据频率远大于写数据频率的场景例如,程序中写操作少而读操作多,如果执行过程是1次写然后N次读的话,使用Mutex这个过程将是串行的,带来的问题是:即便N次读操作互相之间并不影响,也需要获取到Mutex后才可以操作。如果使用读写锁,多个读操作可以同时持有锁,将大大提升并发能力一个协程拥有写锁时,其他协程获取写锁需要阻塞一个协程拥有写锁时,其他协程获取读锁需要阻塞一个协程拥有读锁时,其他协程获取写锁需要阻塞。

2023-06-02 22:32:44 1013

原创 深入理解 Go sync.Map

sync.Map是线程安全的通过只读和可写分离,使得查询,更新已存在key的value不需要加锁随着程序的运行,dirty和read的差距会越来越大,使得需要加锁访问dirty的概率变大,效率也下降。因此当misses达到阈值时,将dirty提升为read,减低加锁的概率提升后第一次新增键值对时,会将read浅拷贝一份成为dirty,但会过滤掉entry为nil的键值对当 dirty 为 nil 的时候,read 就代表 map 所有的数据;

2023-05-19 23:34:17 718 1

原创 Go 连接池的设计与实现

如果不用连接池,而是每次请求都创建一个连接是比较昂贵的,因此需要完成3次tcp握手同时在高并发场景下,由于没有连接池的最大连接数限制,可以创建无数个连接,耗尽文件描述符连接池就是为了复用这些创建好的连接

2023-04-08 13:18:17 1129

原创 详解go-zero中滑动窗口的实现

常常有这样的需求:统计过去一段时间内的请求总数,过去一段时间内的平均值这种需求用滑动窗口来实现相当适合。

2023-04-06 23:23:40 854

原创 go并发编程 —— singleflight设计模式

singleflight是一种并发编程设计模式,将的多个并发请求成一个请求,以减少对下游服务的压力。

2023-04-04 00:23:32 420

原创 Golang 如何下载ftp文件

由于不是http协议,不能用go自带的http.client下载因此本文介绍如何下载,读取ftp文件。

2023-04-03 23:21:08 1404

原创 深入理解 Go map (3)—— 遍历

如果map正在扩容中,且是两倍扩容方式,如果当前遍历的新桶对应的老桶还没迁移,只去遍历老桶中将来会迁移到该新桶中的元素。位置上得值是否为0,根据刚才的分析可知,SP+280位置代表hiter变量,那么同时也代表其第一个字段,也就是。这样,即使你是一个写死的 map,仅仅只是遍历它,也大概率不会返回一个固定序列的。如果遍历完了,即bucket又回到了startBucket时,将key,elem设为空,返回。主要是维护遍历过程中必须要知道的信息,比如遍历的进度,当前遍历的key/value是什么。

2023-03-24 00:16:31 1131

原创 深入理解 Go map (2)—— 扩容

当调用mapassign当没有正在扩容,元素太多或者太多桶时就会触发扩容怎么判断是否元素过多呢?假设所有桶都装满,负载因子是8,那么当负载因子是6.5时,表示平均来说所有桶了,每次查找和插入,定位到每个桶后平均还要比较3,4次,,此时扩容是很有必要的。最理想的情况是,每个桶的负载因子都是1,这样只需要一次比较就能完成查找和插入操作怎么判断是否有太多桶呢?虽然每个桶的平均负载不高,但是有大量的溢出桶,此时查找和插入效率也会比较低,因为键值对分散在各个溢出桶中,需要不断地去溢出桶中查找插入。

2023-03-21 23:41:09 1494

原创 深入理解 Go map (1)—— 基本原理

如果小于8个,则会消耗更多空间,且需要不断的去溢出桶中找,两个桶的空间不是一块分配的,因此大概率不在一个cpu cache中,效率也会降低。定位到桶后,用hash的高8位去桶bmap的tophash数组中挨个匹配,如果匹配成功,且key和桶中对应位置的key相同,则定位到键值对。当桶中装不下更多元素,且key又被hash到这个桶时,就会放到溢出桶,原桶的overflow字段指向溢出桶。对哈希表来说,除了桶的结构以外,最重要的就是如何根据key定位到桶,以及桶中的键值对

2023-03-19 10:20:03 600

原创 深入理解 Go slice 扩容机制

容量小于1024时为2倍扩容,大于等于1024时为1.25倍扩容小于256时为2倍扩容,大于等于256时的扩容因子逐渐从2减低为1.25不管1.18前后,最终需要按照内存分配块向上修正

2023-03-18 14:43:35 1233

原创 深入理解Go函数调用原理

在程序运行的过程中,会涉及到对函数的调用,调用时IP寄存器会指向被调用函数的地址,函数返回后继续执行本函数剩下的代码程序执行单元(线程或者协程)在执行过程中需要记录程序上下文的数据结构,包括局部变量,BP,参数,返回值等。程序用栈帧这种结构来记录这些信息这两个信息存在使用BP,SP和IP中:BP:存储函数调用堆栈基址指针的寄存器,即SP:存储当前函数栈顶的位置,也就是IP

2023-03-12 14:16:08 380

原创 Go开发者常犯的错误,及使用技巧 (1)

变量名要有意义,不能随便取a,b,c如果for语句块简短还好,如果很长,顺着读下去在后面可能都不记得v代表什么,如果将v换成user,会减少很多理解成本

2023-02-18 21:02:13 715

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除