IT技术博客大学习 共学习 共进步
全部 移动开发 后端 数据库 AI 算法 安全 DevOps 前端 设计 开发者

标签:Go

共 52 篇相关文章

IT 累计浏览 2,581

Golang socket 里面奇怪的 pipe 使用

这篇讲的是一个Go语言代理服务器在排查文件描述符时遇到的蹊跷事。 作者日常监控发现,一个TCP连接数两万多的服务,在系统的`/proc/pid/fd`目录下却有五万多个pipe文件描述符,数量远超socket本身。这不符合直觉,于是开始深挖源码。 根因最终指向了Go在Linux下对`net.Conn.readFrom`方法的优化。为了减少用户态内存拷贝,Go会尝试使用`splice`系统调用在内核态直接完成数据传输。而`splice`要求一方必须是管道,因此其实现略显“绕”:每次`readFrom`操作都会先通过`pipe2`创建一对临时管道,再分别进行`splice`操作,用完即关。这完美解释了那些额外pipe的来源。 作者也指出,尽管这种“管道中转”的实现看起来不甚优雅,但在像代理这样`readFrom`生命周期较长的场景中,其性能收益依然可观,因此通常无需优化。文章通过一次具体的生产现象,清晰揭示了Go网络库中一个精巧但隐蔽的内核级优化机制。

IT 累计浏览 1,881

实现 go 的 goroutine 本地存储又一种方式

这篇讲的是Go语言中goroutine本地存储的一种新颖实现方案。 作者指出,Go本身没有提供便捷的goroutine本地存储,虽然可以通过`context`传递数据,但这要求在调用链上处处传递,侵入性较强。他发现Go标准库中用于性能剖析的`pprof`包里,隐藏着一个可以携带数据的`label`机制。 基于此,作者设计了一个巧妙的方案:利用其中一个label,通过一些底层技巧将一个`map`结构“塞”进去,从而在单个goroutine中携带所需的本地数据。同时,为了与标准库中基于`context`操作label的逻辑兼容,还做了相应的处理,防止数据被意外覆盖。 通过这种方式,作者将对原有pprof功能的干扰降到了最低。为此,他编写并开源了一个简洁的库:`github.com/xiezhenye/gls`,为需要goroutine本地状态的场景提供了一个侵入性较低的新选择。

IT 累计浏览 3,145

内网穿透神器frp

这篇讲的是内网穿透工具frp,它解决了开发者常遇到的一个痛点:如何让内网服务(比如公司内网的调试接口、家里的树莓派)安全便捷地暴露到公网。作者对比了之前流行的ngrok,指出其国内访问慢、配置复杂的问题,而frp凭借开源、速度快、配置简单的特点脱颖而出。 文章的核心是手把手教读者搭建frp。作者先解释了frp的基本架构:在外网服务器部署服务端(frpc),在内网设备部署客户端(frpc),通过简单的配置文件建立隧道。接着,文章展示了配置服务端监听端口和客户端代理SSH、HTTP服务的具体示例,整个过程清晰明了。 作者通过实际搭建经验(服务端跑在Google Cloud上,客户端连家里树莓派)验证了frp的效能,并提到该项目在GitHub上已有过万Star。最终,frp只需十分钟即可完成部署的便捷性,使其成为解决内网穿透问题的高效选择。

IT 累计浏览 14,159

Go Reflect 性能

这篇讲的是Go语言reflect包在带来便利的同时,所付出的性能代价。作者没有停留在理论层面,而是通过一组精心设计的基准测试,量化了不同反射操作与直接操作之间的性能差异。 测试以一个普通的struct类型为例,揭示了几个关键结论:通过反射创建对象比直接new慢约50%;而反射赋值的性能损耗则更为显著。有趣的是,使用FieldByName按字段名赋值比按索引Field赋值慢了近4倍,原因在于前者内部有额外的字段查找循环。 文章指出,反射在需要动态处理通用类型的场景(如json编解码、ORM框架)中不可或缺,但其带来的指令增加和interface{}装箱开销不容忽视。因此,在高性能敏感的场合,可以考虑采用代码生成等方式(如easyjson)来规避反射,实现性能优化。文章通过具体数据与源码示例,为开发者在“便利”与“性能”之间权衡提供了清晰的参考。

IT 累计浏览 1,657

使用 defer 还是不使用 defer?

这篇讲的是Go语言中defer语句的“爱恨情仇”——从最初赞赏它能简化资源清理代码,到发现其性能开销,再到最终理解其适用边界的全过程。 文章首先展示了defer的魅力:它能让锁的获取与释放成对出现,代码清晰且不易出错,因此在标准库中被广泛使用。然而,性能测试揭示了一个关键事实:使用defer释放锁(70.4 ns/op)比直接调用(19.3 ns/op)慢数倍,多个defer叠加时开销更大。这引出了核心矛盾:defer带来的代码简洁性,是以几十纳秒的性能损耗为代价的。 文章进一步探讨了Go官方对此的优化(如1.8版本的改进),并引用了实际案例(如Prometheus项目)。结论并非一刀切地否定defer,而是提出了务实的平衡点:对于大多数业务代码,defer的便利性远胜于其微小开销;但对于高并发下的“热路径”,通过pprof观察到defer成为瓶颈时,手动管理资源释放则是更优选择。简单说,defer并非免费,但它的代价在绝大多数场景下完全值得。

IT 累计浏览 2,209

[译]Go开发中一些有用的模式

作者从使用VB、Java、C#和Python转向Go开发的视角出发,分享了在Go中实现几个经典设计模式的独特方式。文章的核心在于对比:与许多语言依赖注解(Annotation)实现装饰器不同,Go通过函数包装和接口适配来增强功能,使控制流更显式,避免了隐藏的配置陷阱。对于单例模式,Go利用`sync.Once`优雅地解决了其他语言中常见的并发初始化安全与性能问题,甚至结合装饰器模式将不安全的API包装成线程安全版本。此外,文章还介绍了用类型方法实现“静态成员”的技巧,以及如何用带缓冲的channel轻量级模拟信号量。这些示例不仅展示了Go的语法特性,更体现了其通过组合和并发原语来构建清晰、安全代码的哲学,对习惯其他语言范式的开发者很有启发。

IT 累计浏览 2,980

ABTest 平台设计 - 如何进行流量分桶

这篇讲的是ABTest平台设计中一个看似简单却容易踩坑的环节:如何进行用户分桶。作者从很多初创公司常见的错误做法——直接用UserID取模分桶——出发,点明了这种看似随机的方法在长期、交叉实验场景下会导致流量利用率低、实验结果互相干扰以及桶间用户行为产生偏差的三大问题。 为了解决这些痛点,文章引出了业界主流的解决方案:可重叠的分层分桶方法。核心思路是将流量划分为多个逻辑层(如UI层、算法层),在每层内使用不同的随机算法(如Hash(Layer, Tag) % 1000)进行正交分桶。这样,同一份流量可以同时穿过多个实验层而互不干扰,极大提升了实验效率。文章还对比了适用于大公司的“无限分层”探索,指出其对组织管理和数据能力的更高要求。 作者最后提到了Google相关论文作为延伸,并预告下一篇将讨论实验开关与信息传递,为搭建完整的ABTest平台提供了清晰的脉络参考。

IT 累计浏览 4,775

go-kit 入门(一)

这篇讲的是Go语言微服务开发工具集go-kit的入门指南。文章从微服务的背景切入,系统性地介绍了go-kit的核心价值:它旨在解决分布式系统中的常见工程问题,让开发者能够将精力集中在业务逻辑上。 摘要重点梳理了文章详细拆解的八个核心组件。例如,Endpoint被抽象为构建RPC的基础单元;Circuit breaker和Rate limiter则为服务提供了弹性与稳定性保障。文章还深入介绍了如何通过Transport层绑定JSON/HTTP等序列化方式,以及如何借助Logging、Metrics和Request tracing模块实现服务的可观测性。对于服务间调用,go-kit通过loadbalancer模块整合了服务发现与负载均衡,支持Consul、etcd等多种后端。 作者进一步阐明了go-kit的设计目标,即作为一套可插拔、低侵入的函数库,无缝融入现有架构,并强调了使用vendoring进行依赖管理的建议。文章最后还列举了诸多受其启发或与之相关的开源项目,为读者勾勒出清晰的Go微服务生态图谱。对于刚接触微服务的Go开发者而言,这无疑是一份扎实的起点地图。

IT 累计浏览 1,369

APP创业项目后端语言选择

这篇讲的是初创团队在后端语言选择上的务实考量。作者跳出了语言优劣的争论,专注于如何为资源有限的创业项目匹配合适的技术栈。 文章从JAVA、PHP、Python三种主流选择切入,细致分析了它们的实战特点。JAVA生态完善、适合复杂项目,但编译调试流程对小团队可能偏重;PHP作为老牌选择,框架成熟且开发效率高,特别是Phalcon框架在保护源码和提升性能上给出了新思路;Python则凭借其灵活性和在全栈开发上的潜力,通过Django等框架也能胜任后端工作,并且对小型项目尤为友好。 最终,作者给出了清晰的选型建议:如果项目规模较大、需要稳定扩展,PHP(推荐Laravel或Phalcon)是更稳妥的选择;若项目较小、追求快速迭代,Python(配合Django框架)则显得更为轻便灵活。整篇文章没有鼓吹任何一种语言,而是帮助团队根据自身业务规模与团队现状,做出最贴合实际的技术决策。

IT 累计浏览 2,691

谈谈Go语言的字符串设计

作者从一个实际的内存泄漏问题说起:在使用GoJieba库时,一段测试代码的内存持续增长。经过排查,发现问题出在调用C.CString后未手动释放内存——一个因思维惯性导致的“白痴”Bug。 这个Bug的背后,是Go字符串与C字符串在内存模型上的根本差异。C语言以‘\0’作为字符串终结符,导致字符串无法直接复用父字符串的内存。而Go的字符串采用长度记录,设计上支持高效的子串内存共享。因此,当通过cgo的C.CString将Go字符串转换为C字符串时,必须分配全新的内存空间,这就要求开发者必须负责手动调用C.free进行释放,不能像使用C++的c_str()那样想当然地复用内存。 文章最终回归文档,用cgo官方示例明确了这一“必须释放”的责任。这个小小的踩坑经历,提醒所有涉及跨语言内存管理的开发者:务必理解底层设计差异,严格遵守接口契约。

IT 累计浏览 3,396

Docker基础技术:Linux Namespace(上)

这篇讲的是Docker“新瓶装旧酒”背后的关键内核技术——Linux Namespace。作者从Docker并非全新技术切入,指出其核心是巧妙运用了已有的Linux内核能力,旨在带读者“山寨”一个简易Docker。 文章重点解析了Namespace提供的六种隔离机制,包括UTS(主机名)、IPC(进程间通信)、PID(进程ID)等。作者并未停留在概念罗列,而是通过一组清晰的C语言代码示例,一步步演示了如何使用`clone()`系统调用配合不同的`CLONE_NEW*`参数,来实现具体的隔离效果。例如,子进程在独立的UTS命名空间中修改hostname,不会影响宿主机;在独立的PID空间里,其初始进程会成为PID 1。 这种“上代码、看结果”的讲解方式,将抽象的“环境隔离”概念变得直观可感。对于想理解容器技术(不仅仅是Docker)底层原理的开发者而言,文章提供了从理论到动手验证的完整路径,是理解Linux容器化技术基石的实用入门。

IT 累计浏览 4,757

分布式存储Seaweedfs源码分析

这篇文章对分布式文件存储系统 SeaweedFS 0.67 版本的源码进行了一次深入的解剖。作者从其基于 Facebook Haystack 论文的架构思想出发,指出 SeaweedFS 实现了“青出于蓝而胜于蓝”的改进。 文章清晰地梳理了项目的核心模块,重点剖析了其两大支柱:拓扑管理与数据存储。在拓扑层面,详解了由 DataCenter、Rack、DataNode 构成的树状结构,这正是其管理分布式 VolumeServer 的核心。而在数据存储层面,则层层递进,解释了文件唯一标识 Fid 的构成(VolumeId, NeedleId, Cookie),并深入到 Volume 文件内部的布局——SuperBlock 与 Needle 的关系。特别值得一提的是,文中对 SuperBlock 中 TTL(Time To Live)功能的实现原理进行了拆解,阐述了如何通过 Volume 级别的超时标记与清理机制来优雅地实现文件的定时删除。 整体来看,这篇文章并未停留在功能介绍,而是直击代码,帮助读者理解 SeaweedFS 如何用简洁的设计实现高性能的对象存储,对于理解分布式存储系统的工程实现很有参考价值。

IT 累计浏览 1,861

谈谈go语言编程的并发安全

这篇讲的是Go并发安全的一个经典认知误区。作者从修复分布式存储项目Weed-FS中的一个非并发安全问题出发,提交了加锁的PR,却意外被维护者以“单写多读场景不需要加锁”为由拒绝。 这挑战了作者基于C/C++开发经验的常识,促使他深入探究Go内存模型。文章梳理了Go官方建议的核心:对多goroutine访问的数据必须序列化(加锁或使用channel),并引用了社区讨论中的警句——“Don't be clever”。最终,通过go-nuts邮件列表的权威讨论,验证了作者“必须保护”的观点是正确的,维护者也接受了修改。 文章特别指出,许多人存在“每次读取都是原子行为”或“数据竞争最多只是读到旧值”的误解,这其实是非常危险的。作者推荐使用`go run/build/test -race`命令来检测这类难以复现的隐患,并提醒大家,即使程序运行正常,也不代表没有并发问题。

IT 累计浏览 4,143

程序员的“横向发展”

这篇讲的是程序员除了深度与广度之外常被忽视的第三维度——“横向发展”。作者以亲身经历切入:初入职场时,他以为程序算出正确结果就完成了任务,却被项目经理批评未处理网络异常等现实问题。这让他意识到,学校里学的“技术化”编程与生产环境所需的“工业化”要求之间存在巨大鸿沟。 横向发展的核心,是让程序真正健壮可用。它不追求算法更快或语言更多,而是关注异常处理、持续监控、状态记录和故障可诊断性。作者观察到,许多程序员却讨厌这类工作,认为这是“找麻烦”,导致线上程序如同“豆芽菜”般脆弱——不记录运行状态,出了问题无法快速定位,陷入重复排障的循环。 文章指出,与其一味钻研新工具,不如先补上这关键一课:给程序加上“重心”,让它在真实复杂的世界中稳定站立。

IT 累计浏览 1,760

小股东怎样保护自己的利益

这篇讲的是创业公司里小股东如何自保的实战心法。作者从小股东的尴尬处境切入——身份介于股东和打工者之间,话语权低,但完全放弃权益又极易被“复杂股权架构变更”掏空股份。文章的核心观点是:小股东必须主动行动,通过几个关键策略来对冲信息与权力的不对等。 具体策略包括:一是强化契约意识,任何涉及利益的条款都需法律保障,绝不能因“不好意思”而妥协;二是利用在公司任职的便利,通过非正式渠道(如与财务、人事同事交流)主动拼凑信息,预判风险;三是保持自身的“存在感”,确保个人价值不低于持股比例,避免被边缘化;四是及时评估大股东人品,发现问题尽早友好协商退出;五是永远保留独立创业的能力,作为谈判的底气。 文章也罕见地从大股东视角给出了避免冲突的建议,比如要求小股东现金购股、采用分期授予(vesting)机制、以及及时回购不称职者的股份。这使得讨论更为平衡,对创业双方都有参考意义。最后作者提醒,选择合伙人时需警惕纯粹重利、缺乏理想的商人,因为这决定了公司的底线。

IT 累计浏览 2,556

Go 语言简介(下)— 特性

这篇讲的是Go语言的核心并发特性。作者从通勤时间的利用切入,用一系列简洁的代码示例,带你快速上手Go中并发编程的四大金刚:goroutine、原子操作、Channel以及它们的安全性问题。 文章首先展示了如何用`go`关键字轻松启动goroutine,就像给函数调用加了“并发”开关。但真正的并发需要配置`runtime.GOMAXPROCS`。作者特意用一个经典的“卖票程序”作为例子,直观地演示了当多个goroutine同时修改全局变量时,若无保护,票数竟会变成负数。随后,他引出了解决并发数据竞争的两种核心武器:使用`sync.Mutex`互斥锁进行显式加锁,以及对于简单计数器使用`sync/atomic`包进行无锁的原子操作,后者通过一个期望结果为200的累加实验说明了其效率与正确性。 最后,文章聚焦于Go的通信哲学核心——Channel。通过示例代码,清晰地讲解了Channel如何充当goroutine间安全的通信管道,包括如何设置缓冲区大小,以及利用其默认的阻塞特性来协调收发双方的节奏,避免了直接共享内存带来的复杂锁问题。整篇文章用最简短的上下班时间,帮你建立起对Go并发模型从基础到实践的关键认知。

IT 累计浏览 2,854

Go 语言简介(上)— 语法

这篇讲的是Go语言入门语法,作者在一个宅家的周末里,决定以“通勤时间也能轻松读完”为目标,用大量代码和注释搭建了一份极简指南。如果你有C、Python或Unix基础,大约半小时就能对Go建立初步印象。 文章从经典的“Hello World”切入,迅速展示了Go运行与构建的两种方式。随后,核心语法点如静态类型变量声明(其 `:=` 简洁赋值借鉴了Pascal,却更现代)、常量、数组及其类似Python的切片操作被逐一铺陈。作者特别强调了Go控制流的“干净”:`if`/`switch`/`for` 语句均无需圆括号,且`switch`省略了`break`。这些设计让代码看起来更清爽。 更深入一些,文章介绍了Go的内置`map`类型——相比传统语言的哈希表,它的创建、读写和遍历语法都显得异常直观。此外,也提及了Go保留了指针功能。最后,一个有趣的细节是:Go实际上使用分号终结语句,但其词法分析器能根据简单规则自动插入,因此源代码中几乎无需手动输入。这些对比C、Python等语言的语法差异点,正是文章希望帮你快速抓住的Go语言“性格”。对于想快速了解Go独特风格的读者,这是一本带你快速上手的迷你语法手册。

IT 累计浏览 13,911

面向“接口”编程和面向“实现”编程

这篇讲的是编程中一个经典却容易被忽视的原则:我们应该面向“接口”编程,而不是面向“实现”编程。 作者从重读《设计模式》一书出发,结合自己对 Rust 等新语言的思考,通过一个生动的例子对比了这两种方式。如果直接写一个 `start_fire` 函数并让它接收具体的 `Log` 类型参数,那么想传入同样具有 `burn()` 方法的 `Book` 对象时就会报错,因为函数绑定的是具体实现类型。这种方式导致了代码重复和僵化。 而“面向接口”编程则提供了优雅的解决方案。文章定义了 `Burnable` 接口(在 Rust 中是 trait),让 `Log` 和 `Book` 都实现它。于是 `start_fire` 函数可以泛化为接受任何满足 `Burnable` 接口的类型 `T`。这样,无论是木头还是书,甚至是未来新增的、实现了该接口的“纸张”对象,都能无缝地传入该函数,代码的复用性和扩展性大大增强。 这个对比清晰地展示了:面向实现导致紧耦合,而面向接口则通过抽象带来了灵活性。虽然并非所有场景都适用,但遵循这一原则能帮助我们写出更易于维护和扩展的代码,这正是其强大价值所在。

IT 累计浏览 4,587

为什么我们要使用Go语言以及如何使用它的

这篇讲的是SoundCloud团队为何在多种编程语言并行的后端架构中,选择引入Go语言,以及他们基于1.0版本Go的具体实践经验。 作者从公司已有的技术栈(最外层是Ruby on Rails)出发,坦诚了后端语言混杂的现状。核心观点是,Go语言为解决特定场景下的问题——比如性能敏感、需要高并发处理的服务——提供了一个清晰而有力的选项。文章没有停留在语言特性的泛泛对比,而是结合SoundCloud自身的业务需求,分享了Go在实际项目中的应用思路,包括如何集成到现有系统、其编译型语言带来的部署便利性,以及在处理并发任务时的天然优势。 对于同样面临多语言架构管理复杂度、或寻找特定后端模块优化方案的技术团队而言,这篇结合了一线公司选型思考与实践的分享,提供了相当具体的参考。

IT 累计浏览 3,916

从Go看,语言设计(二)

这篇接着上一篇,深入探讨Go语言的设计哲学。作者从Go的核心设计原则出发,聚焦于其独特的并发模型(goroutine与channel)和精简的语法如何影响程序构建与团队协作。 文章将Go与传统多线程模型(如Java线程)进行了对比,指明Go的并发原语如何以更轻量级的方式,降低了并发编程的复杂度与资源开销。作者也提到了Go的快速编译、垃圾回收机制以及对组合优于继承的坚持,这些选择共同塑造了其清晰、高效的代码风格。 最终,文章阐述了这些设计决策的适用边界:Go尤其适合构建需要高并发、快速迭代和易于维护的网络服务与基础设施。它可能不适用于所有场景,但其明确的设计取舍为开发者提供了一种可靠且高效的工程化路径。