Ryo's blog

归档 · 全部

首页

关于

归档

loading..
Golang

Golang 编译器优化那些事

一、背景去年写了一篇 Golang Memory Model 文章。当时在文章里面贴了验证一个线程可见性问题Demo,具体代码如下: func main() { running := true go func() { println("start thread1") count := 1 for running { count++ } println("end thread1: count =", count) // 这句代码永远执行不到为什么? }() go func() { println("start thread2") for..

更多
loading..
Golang

Golang Memory Model

一、背景1.1 一个 Code Review 引发的思考一个同学在 Golang 项目里面用 Double Check(不清楚的同学可以去百度搜下,Java中比较常见)的方式实现了一个单例。具体实现如下: var ( lock sync.Mutex instance *UserInfo ) func getInstance() (*UserInfo, error) { if instance == nil { //---Lock lock.Lock() defer lock.Unlock() if instance == nil { instance = &UserInfo{..

更多
eng-practices

数据传输系统落地和思考

一、背景我们的产品需要支持 Multi-Geo 功能。 什么是Multi-Geo?简单的说就是:“将一个租户下不同用户/设备/组织等数据,分散存储在不同的地理位置的能力”,在同一个租下管理员可以配置任意用户的数据驻留地(Preferred Data Location简称PDL)。 该功能主要是解决跨国企业,数据合规存放的问题。支持同一个企业下,不用国家的用户,数据存放在不同的国家的机房。 Multi-Geo的功能涉及到几点核心能力。 数据的路由能力。比如,我们服务在CN收到一个User数据查询需求,首先我们要知道这个User是归属于CN还是i18n(国外)的Unit,然后再把请求转发给相应的Unit的服务。 数据的定位能力,管理员更新用户的PDL时候,我们需要把用户所有的数据(存量和增量)找出来,然后发..

更多
Golang

深入理解 Golang Stack

一、基础知识1.1 Linux 虚拟地址空间布局我们知道CPU有实模式和保护模式,系统刚刚启动的时候是运行在实模式下,然后经过一系列初始化工作以后,Linux会把CPU的实模式改为保护模式(具体就是修改CPU的CR0寄存器相关标记位),在保护模式下,CPU访问的地址都是虚拟地址(逻辑地址)。Linux 为了每个进程维护了一个单独的虚拟地址空间,虚拟地址空间又分为“用户空间”和“内核空间”。 虚拟地址空间更多相关可以看Linux内核虚拟地址空间这篇文章。 1.2 Golang 栈和虚拟地址空间栈的区别Golang 的内存管理是用的 TCMalloc(Thread-Caching Malloc)算法, 简单点说就是 Golang 是使用 mmap 函数去操作系统申请一大块内存,然后把内存按照 ..

更多
MiddlewareMySQL

MySQL Insert 死锁问题研究

背景不想看废话的,建议直接去最后看死锁的本质原因。 问题背景线上一个很简单结构的表,报insert死锁,这个表基本上只有insert操作,所以引出一个问题insert 和insert之间为什么会死锁? 顺便说下我们线上库的隔离级别都是RC,日志格式是ROW,我下面所有测试都是在RC下。 *** (1) TRANSACTION: TRANSACTION 2404187192, ACTIVE 0 sec inserting mysql tables in use 1, locked 1 LOCK WAIT 8 lock struct(s), heap size 1136, 2 row lock(s) MySQL thread id 118913019, OS thread handle 140411115681..

更多
loading..
LinuxMemory

Linux内核虚拟地址空间

x86-32位虚拟地址空间就我们所知,Linux内核一般将处理器的虚拟地址空间划分为两个部分。底部比较大的部分用于用户进程,顶部则专用于内核。虽然(在两个用户进程之间的)上下文切换期间会改变下半部分,但虚拟地址空间的内核部分总是保持不变。 Linux将虚拟地址空间划分为:0~3G为用户空间,3~4G为内核空间 点我查看原图 用户地址空间 保留区 - 0x08048000位于虚拟地址空间的最低部分,未赋予物理地址。任何对它的引用都是非法的,用于捕捉使用空指针和小整型值指针引用内存的异常情况。 它并不是一个单一的内存区域,而是对地址空间中受到操作系统保护而禁止用户进程访问的地址区域的总称。大多数操作系统中,极小的地址通常都是不允许访问的,如NULL。C语言将无效指针赋值为0也是出于这..

更多
Compiler

LLVM编译器基础知识

一、基础概念1.1 Interpreter 和 Compile Interpreter 解释器 Compile 编译器 程序步骤 1、创建代码 2、没有文件链接或机器代码生成 3、源语句在执行过程中逐行执行 1、创建代码 2、将解析或分析所有语言语句的正确性 3、将把源代码转换为机器码 4、链接到可运行程序 5、运行程序 Input 每次读取一行 整个程序 Output 不产生任何的中间代码 生成中间目标代码 工作机制 编译和执行同时进行 编译在执行之前完成 存储 不保存任何机器代码 存储编译后的机器代码在机器上 执行 程序执行是解释过程的一部分,因此是逐行执行的 程序执行与编译是分开的,它只在整个输出程序编译后执行 生成程序 不生成输出程序,所以他们在每次执行过程中都要..

更多
Linuxebpf

《eBPF 核心技术与实战》

概览eBPF 是什么呢? 从它的全称“扩展的伯克利数据包过滤器 (Extended Berkeley Packet Filter)” 来看,它是一种数据包过滤技术,是从 BPF (Berkeley Packet Filter) 技术扩展而来的。 BPF 提供了一种在内核事件和用户程序事件发生时安全注入代码的机制,这就让非内核开发人员也可以对内核进行控制。随着内核的发展,BPF 逐步从最初的数据包过滤扩展到了网络、内核、安全、跟踪等,而且它的功能特性还在快速发展中,这种扩展后的 BPF 被简称为 eBPF(相应的,早期的 BPF 被称为经典 BPF,简称 cBPF)。实际上,现代内核所运行的都是 eBPF,如果没有特殊说明,内核和开源社区中提到的 BPF 等同于 eBPF。 tcpdump 和 BCC 之所以..

更多
Golang

Go 泛型初窥

一、基础知识1.1 形参和实参func min(a, b int) int { if a > b { return b } return a } func main() { minNum := min(100, 200) } 如上a、b叫形参(parameter),100和200叫实参(argument)。 1.2 类型形参、类型实参、类型约束、类型形参列表func sumNum[T int32 | float32](n []T) T { var s T for _, item := range n { s += item } return s } func main() { data1 :=..

更多
GolangGoSourceCode

Go源码——Sync.Mutex

一、背景sync.Mutex是我们常用到的一把锁。网上讲这个锁的文章也比较多,这里面主要是为了简单做个自我总结。 Sync.Mutex 慢路径底层依赖的是runtime_SemacquireMutex和runtime_Semrelease,对这个不了解可以先去看下 runtime.semaphore 。 二、Sync.Mutex 源码2.1 发展历史sync.Mutex第一版 代码 是2008年的时候 @rsc 提交的。最早的实现比较简单,是通过简单的CAS加信号量的方式来实现的。信号量具体可以参考 runtime-sema 这篇文章。 @dvyukov 2011年的时候,提交了第一次优化了 sync: improve Mutex to allow successive acquisitions,这一版中加..

更多
GolangGoSourceCode

Go源码——runtime.semaphore

一、背景sync.Mutex里面用了runtime_SemacquireMutex和runtime_Semrelease,所以看下这个runtime的信号量是如何实现的。 二、基础知识2.1 信号量信号量(英语:semaphore)又称为信号标,是一个同步对象,用于保持在0至指定最大值之间的一个计数值。当线程完成一次对该semaphore对象的等待(wait)时,该计数值减一;当线程完成一次对semaphore对象的释放(release)时,计数值加一。当计数值为0,则线程等待该semaphore对象不再能成功直至该semaphore对象变成signaled状态。semaphore对象的计数值大于0,为signaled状态;计数值等于0,为nonsignaled状态。 信号量的概念是由荷兰计算机科学家艾兹赫..

更多
GolangGoSourceCode

Go源码——runtime.mutex

一、背景在Go的runtime包中封装了一个 mutux ,这个mutex被runtime包中大量组件使用,比如 channel、netpoll、检查活跃的定时器 等等。 sync.Mutex和runtime.mutext区别:简单说就是sync.Mutex是用户层的锁,Lock抢锁失败会造成goroutine阻塞(会调用gopark)。runtime.mutex 是给 runtime使用的锁,Lock抢锁失败,会造成m阻塞(线程阻塞,底层调用的futex)。 二、基础知识2.1 MutexMutex 全称是Mutual Exclusion ,俗称互斥体或者互斥锁。是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。 2.2 mmap 函数mmap它的主要功能是将一个虚拟内..

更多
GolangGoSourceCode

Go源码——Sync.Map的前生今世

一、背景前段时间有个朋友来问我Go的Sync.Map性能怎么样,一般什么场景推荐使用。一句话介绍的话,就是Sync.Map底层有两个map,一个是read,一个是dirty,读写read中数据不需要加锁,读写dirty不用需要加锁,适用于读多写少的场景。 碎碎念其实2020年的时候Go源码里面一些比较常用的包都大致看了一遍,当时跟槊槊、大飞哥、周老板空闲时间天天讨论各种技术细节,包括但不仅限于操作系统、MySQL、Redis、分布式、Go、项目架构方法论等。很多时候观点不合还会争的面红耳赤,最后还会上升到人生攻击,你不服我,我也不服你(实际上互有对错,我也被打过几次脸)。因为有的东西,网上有很多错误的资料,导致我养成了一个习惯,找资料的时候我一般都是去看一些权威的技术书或者直接去看开源组件源码,能用代码说的..

更多
Note

《五蠹》摘抄

一、背景看 《Clean Architecture》的时候,看到书里面介绍什么架构师,大致内容如下。 首先,软件架构师自身需要是程序员,并且必须一直坚持做一线程序员,绝对不要听从那些说应该让软件架构师从代码中解放出来以专心解决高阶问题的伪建议。不是这样的!软件架构师其实应该是能力最强的一群程序员,他们通常会在自身承接编程任务的同时,逐渐引导整个团队向一个能够最大化生产力的系统设计方向前进。也许软件架构师生产的代码量不是最多的,但是他们必须不停地承接编程任务。如果不亲身承受因系统设计而带来的麻烦,就体会不到设计不佳所带来的痛苦,接着就会逐渐迷失正确的设计方向。 然后就吐槽了下某些 PPT架构师 只会脱离业务去谈一些高大上的架构,完全都落不了地。然后某个博览群书的技术大佬推荐我看下《五蠹》说里面就有映射这种..

更多
Golang

GO非类型安全指针-Unsafe.Pointer

一、背景朋友发了一段测试代码里面不正确的使用了atomic.StorePointer,导致GC的时候程序Panic了。 var current int64 atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&current)), unsafe.Pointer(&latest)) 为什么会Panic这里先按下不表。之前对 unsafe.Pointer 用的并不多,也没有系统了解过。所以就想系统看下。看了下 unsafe.Pointer 官方文档还挺详细的,可能只之前使用出错的人太多了,所以 rsc 单独提了一个 CR 来说明unsafe.Pointer的用法。 二、unsafe.Pointerunsafe.Pointer表示指向任意类型..

更多
Golang

Go 自定义引用包的域名

一、 背景最近在看 Go源码的时候,发下部分库最早是在 x-pkg 里面的,经过一段时间迭代才进了runtime包里面。 x-pkg 里面介绍了用途和源码地址。 golang.org/x 文档 我发现 x-pkg 的源码地址都在 https://go.googlesource.com, 但是我们项目里面导入某个x-pkg库的路径确是 import "golang.org/x/sync/semaphore" 比较好奇,这import的别名是在哪里做的,感觉是个挺冷门的知识,于是搜了下相关资料。 二、实现步骤找到了官网相关资料: hdr-Remote_import_paths 简单说就是在你的网址里面加入如下信息。 <meta name="go-import" content="example.or..

更多
Note

《人月神话》

什么是人月神话? 一个项目有10人/月的工作量,把人增加到100人,所以只用3天就能开发完,这就是人月神话。 一个谬误的思考方式是在估计和进度安排中使用的工作量单位:人月。成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此。因此我认为用人月作为衡量一项工作的规模是一个危险和带有欺骗性的神话。它暗示着人员数量和时间是可以相互替换的。 一、焦油坑(The Tar Pit)史前史中,没有别的场景比巨兽在焦油坑中垂死挣扎的场面更令人震撼。上帝见证着恐龙、猛犸象、剑齿虎在焦油中挣扎。它们挣扎得越是猛烈,焦油纠缠得越紧,没有任何猛兽足够强壮或具有足够的技巧,能够挣脱束缚,它们最后都沉到了坑底。 过去几十年的大型系统开发就犹如这样一个焦油坑,很多大型和强壮的动物在其中剧烈地挣扎。他们中大多数开发出了可运..

更多
Note

《原则:应对变化中的世界秩序》

一、大周期概述人类的生产率是驱动世界总财富、权力和生活水平逐步提高的最重要的力量。随着时间的推移,生产率稳步提高(生产率是人均产出,受人类的学习、积累和发明的驱动)。然而,不同群体的生产率增速有差异,其原因总是一样的:不同的教育质量、创造力、职业道德以及将想法转化为产出的经济体制。决策者需要理解这些原因,以使自己的国家获得可能实现的最佳结果。投资者和公司也需要理解这些原因,以便确定最佳的长期投资对象。 下图及下页图显示过去500年的人均产出[即实际GDP(国内生产总值)估值]和预期寿命。这可能是两种公认的福祉衡量方法(但数据可能并不精确)。你可以看到这些数据渐进的上行幅度相对于围绕趋势线的波动幅度。 与围绕趋势线的波动相比,这些上行趋势非常明显,这一事实表明,相对于其他任何事物,人类的创造力极其强大。从整体..

更多
Note

《非暴力沟通》

一、由衷的给予非暴力沟通帮助我们与他人和自己建立连结,使我们得以流露与生俱来的慈悲之心。它指引我们通过将注意力聚焦在观察、感受、需要和请求这四个要素,来重新构建表达和聆听的方式。 非暴力沟通培育深度倾听的能力,让我们带着尊重和同理心对待他人,并且发自内心地相互给予。用非暴力沟通的方式,有的人学会了爱自己,有的人在人际关系中创造了更深厚的连结,有的人在工作或政治领域中建立了更有效的关系。在世界各地,非暴力沟通还被用来调和各个层面的纠纷和冲突。 二、疏离生命的语言由衷的给予和接受,是人类天性所乐见的。然而我们习得了太多疏离生命的语言形式,导致我们的说话和行为方式给他人和自己带来伤害。其中的一种形式是道德评判,即认为那些不符合我们价值观的人是不对的、不好的。另一种形式是做比较,让人们难以升起对人对己的善意。疏离生..

更多
Golang

一次线上内存使用率异常问题排查

一、背景朋友的一个服务,某个集群内存的RSS使用率一直在80%左右,他用的是8核16G, 双机房一共206个实例。 但是在pprof里面查的堆内存才使用了6.3G左右,程序里面主要用了6G的LocalCache所以heap用了6.3G是符合预期的。 朋友让我帮忙看下,额外的内存到底是被啥占用了。 二、基础知识2.1 TCMalloc 算法Thread-Caching Malloc 是Google开发的内存分配算法库,最开始它是作为Google的一个性能工具库perftools的一部分。 TCMalloc是用来替代传统的malloc内存分配函数。它有减少内存碎片,适用于多核,更好的并行性支持等特性。 2.2 mmap 函数mmap它的主要功能是将一个虚拟内存区域与一个磁盘上的文件关联起来,以初始化这个虚拟..

更多
MiddlewareMySQL

MySQL 自增列 Duplicate Error 问题分析

一、背景最近我们在做线上的数据迁移测试(可以理解就是把A数据中心的数据迁移到B数据中心,A和B数据中心的MySQL是同构的,迁移过程中,A、B的MySQL都有正常的业务数据写入,具体背景可以看 数据传输系统落地和思考 这篇文章)。每次我们触发迁移的时候,就有业务方反馈他们写入数据的时候就会有Error 1062: Duplicate entry 'xxx' for key 'PRIMARY'这样的错误。业务方同学还反馈他们写数据的时候并没有指定ID,所以他们对这样的报错比较困惑,具体他们的数据写入的伪代码如下: type Data struct { ID int64 `gorm:"primaryKey;column:id"` PageID string..

更多
Golang

Go for-range 的奇技淫巧

背景朋友发了两个代码片段给我看,让我猜输出的内容是啥。具体代码如下: // Demo1 // 1. 这个循环是否能停下来? // 2. 如果能停下来,打印的 arr 内容是什么? arr := []int{1, 2, 3} for _, v := range arr { arr = append(arr, v) } fmt.Println(arr) // Demo2 // 1. idx 和 value 输出多少? // 2. 输出几行? str := "你好" for idx, v := range str { fmt.Printf("idx = %d , value = %c\n", idx, v) } 不卖关子,先说下第一个Demo输出的是: [1 2 3 1 2 3] 第二..

更多
NoteDistribution

《Raft-分布式共识算法》

一、背景在分布式系统中,一致性算法至关重要。在所有一致性算法中,Paxos最负盛名,它由莱斯利·兰伯特(Leslie Lamport)于1990年提出,是一种基于消息传递的一致性算法,被认为是类似算法中最有效的。 Paxos算法虽然很有效,但复杂的原理使它实现起来非常困难,截止目前,实现Paxos算法的开源软件很少,比较出名的有Chubby、LibPaxos。此外,Zookeeper采用的 ZAB(Zookeeper Atomic Broadcast)协议也是基于Paxos算法实现的,不过ZAB对Paxos进行了很多改进与优化,两者的设计目标也存在差异——ZAB协议主要用于构建一个高可用的分布式数据主备系统,而Paxos 算法则是用于构建一个分布式的一致性状态机系统。 由于Paxos算法过于复杂、实现困难,..

更多
loading..
MiddlewareMySQL

MySQL DateTime和Timestamp时区问题

一、背景最近负责一个数据传输的项目,其中一个需求就是能把一个DB里面的数据拉出来 ,然后回放到另外一个同构的DB。两个DB的服务不在一个时区(其实这不是重点),可能配置不同。之前有过类似的项目,当时是基建的同事负责做数据同步,同步过去以后DateTime、Timestamp字段的时区信息都丢了。老板让我调研下问题根因,不要踩之前的坑。 最早的时候看了下同事写的当时MySQL时区信息丢失的问题总结文档,文档里面当时把DateTime和Timestamp两个时区问题混为一起了,也没分析本质原因,导致我当时没看太明白,然后的武断的认为,之所以时区丢失了,是因为基础组件同步DateTime和Timestamp的时候同步的是字符串,比如2021-11-27 10:49:35.857969这种信息,我们传输的时候..

更多
NoteGolang

DDD在Message服务的实践

一、背景我们message服务经过4年的迭代,项目的可维护性、代码的可读性、功能的可扩展性越来越差,经常改一个小功能牵一发而动全身,新来的同学对message服务不能快速上手,而且因为代码可读性不高,导致新同学修代码经常会出现bug。还有一部分原因是大多数人都是第一次用Golang,对项目的分层也没有一个统一的规范,导致最后成了一个四不像的框架。 然后我们今年的两个主要目标,一是项目的稳定性、二是为了支持KA私有划部署战略,我们需要合并微服务数量,降低运维和部署成本。 基于上背景,老板让我牵头对Message服务基于DDD做一次大规模重构,重构目标很明确: 对项目有个明确的分层,提高项目代码可读性、可维护性、可扩展性。降低新人上手成本。 升级RPC框架,合并Message相关服务,提高优化项目资源利用率。..

更多
DataStructure

遍历二叉树的几种思路

一、背景最近在公司面试(一面、二面)候选人的时候,大多数候选人基本都能正确的写出非递归版的前序遍历和中序遍历二叉树,但是大多数人都不能正确的写出非递归版的后续遍历。跟一个曾经拿过NOI银牌同事私下讨论了下后续遍历算法到底难不难。结论是,说难也难说不难也不难,说不难是因为,如果你看过相关解法,你可以很快就就理解解法的思路。说难,是如果你没看过,或者看了过了很久又忘了,要在15分钟左右写个Bug free的版本还是有点难的。 跟同事讨论下二叉树遍历的几种写法,所以就有了这篇文章。 二、二叉树几种解法的思考2.1 递归版前序遍历递归 func preOrderRecursion(node *TreeNode, ans *[]int) { if node == nil { return ..

更多
Note

《黑客与画家》

第一章节:为什么书呆子不受欢迎首先这里“书呆子”指的“高智商”的人。 解开这个谜的关键是把问题换一种提法。为什么聪明的小孩没有让自己变得受欢迎?如果他们真的很聪明,为什么找不到受欢迎的诀窍呢?他们在标准化测试中表现得这么好,为什么就不能在这方面也大获成功呢? 有一种观点认为,其他小孩妒忌聪明学生,所以聪明的学生不可能受到欢迎。我倒希望这种解释是对的。回想起来,要是初中里真的有人妒忌我,那么他们一定费了很大力气才把这种妒忌隐藏得无法发现。而且,在任何情况下,如果聪明真的令他人妒忌,这反而会招来女生。因为女生喜欢被其他男生妒忌的男生。 在我就读过的学校,聪明根本就是无足轻重的一样东西。同学们既不看重它,也不唾弃它。如果别的事情都相同,那么大家还是愿意自己变得聪明一点,因为这总比做个笨人好。但是总的来说,智力在大..

更多
Note

《清醒思考的艺术》

1. 幸存偏误为什么你该去逛逛墓地 幸存偏误是指:由于日常生活中更容易看到成功、看不到失败,你会系统性地高估成功的希望。不了解现实的你(与雷托一样)对成功抱有一种幻想,认识不到成功的概率有多微弱。每位成功的作家背后都有100个作品卖不出去的作家,每个作品卖不出去的作家背后又有100个找不到出版社的作者,每个找不到出版社的作者背后又有数百个抽屉里沉睡着刚动笔的手稿的写作爱好者。而我们总是听到成功者的故事,认识不到作家的成功概率有多小。摄影师、企业家、艺术家、运动员、建筑师、诺贝尔奖得主、电视制作人和选美冠军的情况也是一样。媒体没兴趣去刨挖失败者的墓地,这事也不归他们负责。这意味着:要想缓解幸存偏误,你就得了解这些。 幸存偏误意味着:你系统性地高估了成功概率。解决办法:尽可能常去逛逛曾经大有希望的项目、投资和事..

更多
Note

《被讨厌的勇气》

引言提出论点:“人可以改变,而且人人都可以获得幸福。” 青年:世界是简单的,人生也是如此。假若这种命题中含有几分真理,那也是对于孩子的世界而言。孩子的世界没有劳动或纳税之类的现实义务,他们每天都在父母或社会的呵护下自由自在地生活,未来充满无限希望,自己也似乎无所不能。孩子们的眼睛被遮盖了,不必去面对丑恶的现实。的确,孩子眼中的世界呈现出简单的姿态。 但是,随着年龄的增长,世界便逐渐露出真面目。人们不得不接受“我只不过如此”之类的现实,原以为等候在人生路上的一切“可能”都会变成“不可能”。幸福的浪漫主义季节转瞬即逝,残酷的现实主义时代终将到来。 人一旦长大,就会被复杂的人际关系所困扰,被诸多的责任所牵绊。工作、家庭或者社会责任,一切都是。当然,孩提时代无法理解的歧视、战争或阶级之类的各种社会问题也会摆在你眼前..

更多
LinearAlgebra

MIT - 线性代数

一、Lesson 11.1 方程组的几何解释 上面方程组我们可以写成矩阵形式 上面的矩阵可以看成 Ax = b的形式 : 系数矩阵(A):将方程系数按行提取出来,构成一个矩阵 未知向量(x):将方程未知数提取出来,按列构成一个向量。 向量(b) :将等号右侧结果按列提取,构成一个向量 1.1.1 行图像在坐标系上画出“行图像”,可以知两个线交点就是我们要求的解 1.1.2 列图像从列图像的角度,我们再求这个方程可以看成矩阵: 1.2 方程组的几何形式推广1.2.1 高维行图像我们将方程维数推广,从三维开始,如果我们继续做行图像求解,那么会的到一个很复杂的图像。 矩阵如下: 如果绘制行图像,很明显这是一个三个平面相交得到一点,我们想直接看出 这个点的性质可谓是难上加难,比较靠谱的思路是先联..

更多
MiddlewareEnvoy

Envoy 编译调试

Debian9 上编译调试主要参考Envoy官方的Bazel编译文档 下载bazelisk-linux-amd64 sudo wget -O /usr/local/bin/bazel https://github.com/bazelbuild/bazelisk/releases/latest/download/bazelisk-linux-amd64 sudo chmod +x /usr/local/bin/bazel 安装依赖 sudo apt-get install \ autoconf \ automake \ cmake \ curl \ libtool \ make \ ninja-build \ patch \ ..

更多
Note

《Clean Code》

什么是整洁代码 能通过所有测试; 没有重复代码; 体现系统中的全部设计理念; 包括尽量少的实体,比如类、方法、函数等。 童子军军规光把代码写好可不够。必须时时保持代码整洁。我们都见过代码随时间流逝而腐坏。我们应当更积极地阻止腐坏的发生。 让营地比你来时更干净。 有意义的命名名副其实名副其实说起来简单。我们想要强调,这事很严肃。选个好名字要花时间,但省下来的时间比花掉的多。注意命名,而且一旦发现有更好的名称,就换掉旧的。这么做,读你代码的人(包括你自己)都会更开心。 变量、函数或类的名称应该已经答复了所有的大问题。它该告诉你,它为什么会存在,它做什么事,应该怎么用。如果名称需要注释来补充,那就不算是名副其实。 避免误导程序员必须避免留下掩藏代码本意的错误线索。应当避免使用与本意相悖的词。例如,hp、aix ..

更多
Note

《Clean Architecture》

零、概述软件架构设计是一件非常困难的事情,这通常需要大多数程序员所不具备的经验和技能。同时,也不是所有人都愿意花时间来学习和钻研这个方向。做一个好的软件架构师所需要的自律和专注程度可能会让大部分程序员始料未及,更别提软件架构师这个职业本身的社会认同感与人们投身其中的热情了。 采用好的软件架构可以大大节省软件项目构建与维护的人力成本。让每次变更都短小简单,易于实施,并且避免缺陷,用最小的成本,最大程度地满足功能性和灵活性的要求。 0.1 设计与架构究竟是什么?一直以来,设计(Design)与架构(Architecture)这两个概念让大多数人十分迷惑——什么是设计?什么是架构?二者究竟有什么区别? 本书的一个重要目标就是要清晰、明确地对二者进行定义。首先我要明确地说,二者没有任何区别。一丁点区别都没有! “架..

更多
NoteRedis

《Redis核心技术与实战》

数据结构Redis数据结构简单来说,底层数据结构一共有 6 种,分别是简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组。它们和数据类型的对应关系如下图所示: 全局哈希表 因为这个哈希表保存了所有的键值对,所以,我也把它称为全局哈希表。哈希表的最大好处很明显,就是让我们可以用 O(1) 的时间复杂度来快速查找到键值对——我们只需要计算键的哈希值,就可以知道它所对应的哈希桶位置,然后就可以访问相应的 entry 元素。 渐进式 rehash简单来说就是在第二步拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entr..

更多
Note

DDD-领域驱动设计

一、DDD的基础概念1.1 什么是 DDD 2004 年埃里克·埃文斯(Eric Evans)发表了《领域驱动设计》(Domain-Driven Design –Tackling Complexity in the Heart of Software)这本书,从此领域驱动设计(Domain Driven Design,简称 DDD)诞生。DDD 核心思想是通过领域驱动设计方法定义领域模型,从而确定业务和应用边界,保证业务模型与代码模型的一致性。领域驱动设计,主要是用来指导如何解耦业务系统,划分业务模块,定义业务领域模型及其交互。领域驱动设计这个概念并不新颖,早在 2004 年就被提出了,到现在已经有十几年的历史了。不过,它被大众熟知,还是基于另一个概念的兴起,那就是微服务。不过,我个人觉得,领域驱动设计有点..

更多
NoteChip

《说透芯片》

基础知识晶体管想了解晶体管,你得先了解它的“前身”——电子管。电子管是中文翻译后的名称,英文原文其实是真空管。从这个名字,你可以想象,它其实是把参与工作的金属薄片,也就是电极,封装在一个真空的容器内,真空容器一般指的是玻璃瓶。 整个电子行业,并不是从芯片开始的,而是从电子管开始。电子管最鼎盛时期的代表作,就是世界上的第一台电子计算机。这台 1946 年诞生的电子计算机,占地 150 平方米,重达 30 吨,里面的电路使用了 17468 只电子管、7200 只电阻、10000 只电容、50 万条线。 这台计算机虽然运算速度不快,但基本具备了现代计算机的主要结构和功能,这也是电子管能达到的最高成就了。其实从上图你也可以看出来,电子管最大的缺点就是,真空容器对于电子产品来说体积太大了。 如果人类停留在电子管技术上..

更多
Golang

Golang RWMutext 代码走读

type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // 写的信号量 readerSem uint32 // 读的信号量 readerCount int32 // 等待写的个数 readerWait int32 // 等待读的个数 } // 加“读锁” // 对readerCount + 1 。 // 然后看 readerCount是不是小于0 // 小于0表示 正在加写锁,然后阻塞到rw.readerSem 这个信号上。 func (rw *RWMutex) RLock() { if atomic.AddInt32(..

更多
NoteMiddleware

K8S学习笔记

环境配置Docker File 编写#源镜像 FROM golang:latest # 容器环境变量添加,会覆盖默认的变量值 ENV GOPROXY=https://goproxy.cn,direct ENV GO111MODULE="on" ENV test="on" # 作者 LABEL author="fanlv" LABEL email="fanlvlgh@gmail.com" #设置工作目录 WORKDIR /go/src/gitee.com/fanlv/GolangDemo/GoTest/docker # 复制仓库源文件到容器里 COPY . . # 编译可执行二进制文件(一定要写这些编译参数,指定了可执行程序的运行平台,参考:https://www.jianshu.com/p/4b345a..

更多
Sort

常用的排序算法

插入排序func insertSort(nums []int) { for i := 1; i < len(nums); i++ { tmp := nums[i] for j := i; j >= 0; j-- { if j > 0 && tmp < nums[j-1] { nums[j] = nums[j-1] } else { nums[j] = tmp break } } } } 折半插入排序func binaryInsertSor..

更多
MiddlewareRedis

Redis 高可用解决方案总结

一、主从复制什么是主从复制我们正常在项目中对redis进行应用,一般都不会是单点的。因为,单点的宕机即不可用,不能保证可用性。另外,单点redis读写指令都会打到同一个服务里面,也会影响性能。在通常的应用中,对redis的读操作远远多于写操作,所以,我们一般会选择“一主多从”的集群策略。 主中的数据有两个副本(replication)即从redis1和从redis2,即使一台服务器宕机其它两台服务也可以继续提供服务。 主中的数据和从上的数据保持实时同步,当主写入数据时通过主从复制机制会复制到两个从服务上。 只有一个主redis,可以有多个从 redis。 主从复制不会阻塞master,在同步数据时,master可以继续处理client请求。 一个可以即是主又是从,如下图: 主从复制过程一般当slav..

更多
NoteMiddlewareETCD

《ETCD实战》

背景ectd 常见问题 etcd 基础 etcd 实践 etcd v2 功能 etcd v2 存在的问题 第一,etcd v2 不支持范围查询和分页。分页对于数据较多的场景是必不可少的。在 Kubernetes 中,在集群规模增大后,Pod、Event 等资源可能会出现数千个以上,但是 etcd v2 不支持分页,不支持范围查询,大包等 expensive request 会导致严重的性能乃至雪崩问题。 第二,etcd v2 不支持多 key 事务。在实际转账等业务场景中,往往我们需要在一个事务中同时更新多个 key。 然后是 Watch 机制可靠性问题。Kubernetes 项目严重依赖 etcd Watch 机制,然而 etcd v2 是内存型、不支持保存 key 历史版本的数据库,只在内存中使用滑动..

更多
Note

《设计模式》

前言什么是设计模式设计模式讲的是如何写出可扩展、可读、可维护的高质量代码,所以,它们跟平时的编码会有直接的关系,也会直接影响到你的开发能力。 为什么要学习设计模式 应对面试中的设计模式相关问题。 告别写被人吐槽的烂代码。我见过太多的烂代码,比如命名不规范、类设计不合理、分层不清晰、没有模块化概念、代码结构混乱、高度耦合等等。这样的代码维护起来非常费劲,添加或者修改一个功能,常常会牵一发而动全身,让你无从下手,恨不得将全部的代码删掉重写! 提高复杂代码的设计和开发能力。 让读源码、学框架事半功倍。 为你的职场发展做铺垫 如何评价代码质量的高低?仔细看前面罗列的所有代码质量评价标准,你会发现,有些词语过于笼统、抽象,比较偏向对于整体的描述,比如优雅、好、坏、整洁、清晰等;有些过于细节、偏重方法论,比如模块化、..

更多
Note

《30天自制操作系统》

30天自制操作系统启动区(boot sector)软盘第一个的扇区称为启动区。那么什么是扇区呢?计算机读写软盘的时候,并不是一个字节一个字节地读写的,而是以512字节为一个单位进行读写。因此,软盘的512字节就称为一个扇区。一张软盘的空间共有1440KB,也就是1474560字节,除以512得2880,这也就是说一张软盘共有2880个扇区。那为什么第一个扇区称为启动区呢?那是因为计算机首先从最初一个扇区开始读软盘,然后去检查这个扇区最后2个字节的内容。如果这最后2个字节不是0x55 AA,计算机会认为这张盘上没有所需的启动程序,就会报一个不能启动的错误。(也许有人会问为什么一定是0x55 AA呢?那是当初的设计者随便定的,笔者也没法解释)。如果计算机确认了第一个扇区的最后两个字节正好是0x55 AA,那它就..

更多
Note

《数据密集型应用系统设计》

数据密集型应用(data-intensive applications)正在通过使用这些技术进步来推动可能性的 边界。一个应用被称为数据密集型的,如果数据是其主要挑战(数据量,数据复杂度或数据变化速度)—— 与之相对的是计算密集型,即处理器速度是其瓶颈。 数据系统的基石可靠性、可扩展性、可维护性现今很多应用程序都是数据密集型(data-intensive)的,而非计算密集型(compute-intensive)的。因此CPU很少成为这类应用的瓶颈,更大的问题通常来自数据量、数据复杂性、以及数据的变更速度。 可靠性(Reliability)系统在困境(adversity)(硬件故障、软件故障、人为错误)中仍可正常工作(正确完成功 能,并能达到期望的性能水准)。 人们对于一个东西是否可靠,都有一个直观的想法。人..

更多
NoteArchitecture

《从0开始学架构》

架构设计理念架构设计理念,可以提炼为下面几个关键点: 架构是系统的顶层结构。 架构设计的主要目的是为了解决软件系统复杂度带来的问题。 架构设计需要遵循三个主要原则:合适原则、简单原则、演化原则。 架构设计首先要掌握业界已经成熟的各种架构模式,然后再进行优化、调整、创新。 框架设计需要考的因素/影响架构复杂性的几个因素 高性能, 衡量软件性能包括了响应时间、TPS、服务器资源利用率等客观指标,也可以是用户的主观感受。 高可用,高可用性就是技术实力的象征,高可用性就是竞争力。99.99%(俗称4个9)网站不可用时间=52.56分钟 可扩展性,设计具备良好可扩展性的系统,有两个基本条件:“正确预测变化、完美封装变化”。 低成本,语言选择、方案选择。 安全,功能安全XSS、CSRF等,架构安全、访问策略。 规模..

更多
NoteLinux

《Linux内核技术实战》

Page Cache什么是 Page Cache? 通过这张图片你可以清楚地看到,红色的地方就是 Page Cache,很明显,Page Cache 是内核管理的内存,也就是说,它属于内核不属于用户。 $ cat /proc/meminfo ... Buffers: 1224 kB Cached: 111472 kB SwapCached: 36364 kB Active: 6224232 kB Inactive: 979432 kB Active(anon): 6173036 kB Inactive(anon): 927932 kB Active(file): 51196 kB Inactive(..

更多
NoteLinux

《Linux性能优化实战》

CPU性能篇uptime 什么是平均负载?简单来说,平均负载是指单位时间内,系统处于可运行状态和不可中断状态的平均进程数,也就是平均活跃进程数,它和 CPU 使用率并没有直接关系。这里我先解释下,可运行状态和不可中断状态这俩词儿。 所谓可运行状态的进程,是指正在使用 CPU 或者正在等待 CPU 的进程,也就是我们常用 ps 命令看到的,处于 R 状态(Running 或 Runnable)的进程。 不可中断状态的进程则是正处于内核态关键流程中的进程,并且这些流程是不可打断的,比如最常见的是等待硬件设备的 I/O 响应,也就是我们在 ps 命令中看到的 D 状态(Uninterruptible Sleep,也称为 Disk Sleep)的进程。 比如,当一个进程向磁盘读写数据时,为了保证数据的一致性,在得到..

更多
Note

《趣谈网络协议》

通信协议综述IP && MACIP 地址是一个网卡在网络世界的通讯地址,相当于我们现实世界的门牌号码。既然是门牌号码,不能大家都一样,不然就会起冲突。比方说,假如大家都叫六单元 1001 号,那快递就找不到地方了。所以,有时候咱们的电脑弹出网络地址冲突,出现上不去网的情况,多半是 IP 地址冲突了。 下面这个表格,详细地展示了 A、B、C 三类地址所能包含的主机的数量。在后文中,我也会多次借助这个表格来讲解。 无类型域间选路(CIDR) 于是有了一个折中的方式叫作无类型域间选路,简称 CIDR。这种方式打破了原来设计的几类地址的做法,将 32 位的 IP 地址一分为二,前面是网络号,后面是主机号。从哪里分呢?你如果注意观察的话可以看到,10.100.122.2/24,这个 IP 地址中有..

更多
Note

《深入浅出计算机组成原理》

基础篇计算机的基本硬件组成 第一,广。组成原理中的概念非常多,每个概念的信息量也非常大。比如想要理解 CPU 中的算术逻辑单元(也就是 ALU)是怎么实现加法的,需要牵涉到如何把整数表示成二进制,还需要了解这些表示背后的电路、逻辑门、CPU 时钟、触发器等知识。 第二,深。组成原理中的很多概念,阐述开来就是计算机学科的另外一门核心课程。比如,计算机的指令是怎么从你写的 C、Java 这样的高级语言,变成计算机可以执行的机器码的?如果我们展开并深入讲解这个问题,就会变成《编译原理》这样一门核心课程。 第三,学不能致用。学东西是要拿来用的,但因为这门课本身的属性,很多人在学习时,常常沉溺于概念和理论中,无法和自己日常的开发工作联系起来,以此来解决工作中遇到的问题,所以,学习往往没有成就感,就很难有动力坚持下去。..

更多
12