
虽然Golang Mutex只有短短的200多行,但是已经是一个极其丰富、精炼的组件,有极其复杂的状态控制.
一、sync.Mutex设计v1/v2版本
其实如果我们去追溯 Mutex 的演进历史,会发现,Mutex最开始是一个非常简单的实现,简单到难以置信的地步,是Go开发者们经过了好几轮的优化才变成了现在这么一个非常复杂的数据结构,这是一个逐步完善的过程.于是我想如果我们是设计者,我们会怎么去设计去优化一个锁的实现呢?
Mutex是Golang 中的锁,主要是控制并发访问资源,保护共享资源。
1、首先从最简单的锁开始设计
Go是一门编译型的和静态的编程语言。 Go诞生于谷歌研究院。 Go的核心设计成员中包括很多有着数十年编程语言研究领域经验的研究者。
短链接系统
用户可以将长 URL 转换为短链接,并能够根据短链接快速跳转到原始 URL,仓库地址
技术栈
Go, Gin, Redis, MySQL, TDDL, 布隆过滤器
项目亮点
- 使用TDDL序列实现分布式唯一 ID 生成器,能在满足高并发的同时保证ID的唯一性
- 使用 Redis 缓存短链接映射数据,减少数据库查询次数,提升系统性能
- 引入布隆过滤器来防止缓存穿透,减少不必要的数据库访问
- 使用令牌桶算法限流,对短链接的生成与访问进行限流,防止恶意刷短链接,保证服务的稳定性
字符串匹配
一、KMP算法
模式串与主串做匹配时,如果是暴力匹配,在主串某趟匹配失败后,模式串要移动第一位,而主串也有苦难需要回退。
在KMP算法中,如果在匹配过程中,主串不需要回退,当匹配失败后,会从当前位置开始继续匹配。而模式串会滑动到某一位开始比较,而不是没都回退到第一位开始比较。
1、前缀表
-
前缀:除最后一个字符以外,字符串的所有头部子串。
-
后缀:除第一个字符以外,字符串的所有尾部子串。
A星算法
A*(A-Star)算法是一种静态路网中求解最短路最有效的方法。公式表示为:f(n)=g(n)+h(n),其中f(n)是节点n从初始点到目标点的估价函数,g(n)是在状态空间中从初始节点到n节点的实际代价,h(n)是从n到目标节点最佳路径的估计代价。
一、算法比较
1、Dijkstra算法
Dijkstra算法从物体所在的初始点开始,访问图中的结点。它迭代检查待检查结点集中的结点,并把和该结点最靠近的尚未检查的结点加入待检查结点集。该结点集从初始结点向外扩展,直到到达目标结点。Dijkstra算法保证能找到一条从初始点到目标点的最短路径,只要所有的边都有一个非负的代价值。(我说“最短路径”是因为经常会出现许多差不多短的路径。)在下图中,粉红色的结点是初始结点,蓝色的是目标点,而类菱形的有色区域(注:原文是teal areas)则是Dijkstra算法扫描过的区域。颜色最淡的区域是那些离初始点最远的,因而形成探测过程(exploration)的边境(frontier):
Redis独立功能
一、发布与订阅
Redis的发布订阅功能由PUBLISH, SUBSCRIBE, PSUBSCRIBE, PUNSUBSCRIBE等命令实现,客户端可以订阅一个或多个频道/模式,服务器根据是否订阅频道、模式是否匹配,决定是否发送给指定客户端消息。
Redis多机
一、复制
Redis中可以使用SLAVEOF <master_ip> <master_port>
实现主从复制,复制功能分两个操作:
- 同步:将从服务器的数据库状态更新至主服务器的最新状态
- 命令传播:在主服务器的数据库状态被修改,导致主从不一致时,让主从数据库重新回到一致状态
Redis单机
一、数据库
1、实现
Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组的每个项都是一个redis.h/redisDb结构,每个redisDb结构代表一个数据库。数组长度(数据库数量)由dbnum控制,默认有16个,通过SELECT
命令切换数据库。
RedisClient结构中的db属性指向当前所使用的数据库,SELECT命令原理即修改该指针。
2、键空间
Redis是一个键值对K-V数据库服务器,服务器中的每个数据库都由一个redis.h/redisDb结构表示,其中,redisDb结构的dict字典保存了数据库中的所有键值对,这个字典称为键空间(key space)。所有针对数据库中数据的操作本质上都是对键空间字典的操作,同时也会进行一些维护: