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

后端

共 1964 篇文章

IT 2017-03-11 23:37:46 / 累计浏览 2,423

分布式程序设计早知道-关于分布式程序设计常见问题分析

这篇讲的是分布式系统设计里那些“小”但影响深远的共性问题。作者从日常开发经验出发,梳理了六个关键点:接口日期该用可读格式还是long型,浮点数传输为何必须转成字符串以避免精度丢失,以及如何设计一个统一的返回值结构(包含status、errorCode、message和data)。 文章着重探讨了幂等性的实现——如何让重复的网络请求不产生副作用,建议为所有接口增加全局唯一的requestId。在接口安全方面,对比了appCode、对称加密和非对称加密三种鉴权方式,分析了它们在多对多场景下的安全性与效率权衡。最后,作者点明了维护数据字典对于解决多团队协作中属性命名混乱的重要性。 这些问题虽不新奇,但一旦忽视,会在系统复杂化后引发大量冗余代码和错误。文章提供了一套实用的设计检查清单。

本机暂存
IT 2017-03-01 23:15:47 / 累计浏览 3,662

【死磕Java并发】—–Java内存模型之happend-before

这篇深入探讨了Java并发编程中一个关键却容易混淆的概念:happens-before原则。作者从多线程环境下变量修改的可见性问题出发,解释了JMM如何通过happens-before来建立内存可见性的保证。 文章系统梳理了happens-before的八大核心规则,例如程序次序规则(单线程内操作有序)、volatile变量规则(写操作对后续读操作可见)以及锁定规则(解锁先于加锁)。除了这些JVM原生规则,作者还列举了诸如线程安全集合操作、Future.get()等场景下的六条推导规则,构建了完整的判断体系。 为了帮助理解,文章通过简单的代码示例,一步步演示了如何应用这些规则来判断一段非同步代码是否存在线程安全风险。它明确了happens-before的本质:它并非强制操作顺序,而是保障了在存在该关系时,一个操作的结果对另一个操作的可见性。这为我们在并发编程中分析数据竞争、设计线程安全代码提供了根本依据。

本机暂存
IT 2017-03-01 23:14:25 / 累计浏览 2,203

MAMP Pro 里面自带的 PHP 命令行执行特别慢的问题

这篇讲的是作者在 Mac 上使用 MAMP Pro 开发环境时遇到的一个颇为古怪的问题:升级系统后,命令行执行 PHP 命令会异常缓慢。作者尝试用 dtruss(Mac 下的系统调用追踪工具)进行调试,但未能定位到具体卡顿点。 经过查阅资料,发现问题根源在于某些 PHP 调用会触发不必要的 DNS 查询,导致执行延迟。最终的解决方案出人意料地简单:在 Mac 的 hosts 文件中,为自己的计算机名添加了本地解析条目。具体操作是,在 `127.0.0.1` 和 `::1`(IPv6)后添加形如 `YourComputer.local` 的主机名(主机名需在系统偏好设置的“共享”面板中查看)。设置完成后,PHP 命令行的执行速度恢复正常,可谓“药到病除”。 文章通过作者亲身实践的调试过程与最终验证的解决方案,为遇到类似 MAMP Pro 环境下命令行迟钝问题的开发者,提供了一个清晰且可直接操作的排查思路和修复方法。

本机暂存
IT 2017-03-01 23:06:03 / 累计浏览 2,144

【死磕Java并发】—–Java内存模型之重排序

这篇文章深入探讨了Java内存模型中的重排序机制,解释了编译器和处理器为何以及如何在不破坏程序最终结果的前提下调整指令顺序。 作者从“as-if-serial”语义出发,结合具体代码示例(如`int a=1; int b=2; int c=a+b;`),清晰地阐述了在单线程环境下,只要不影响最终结果,操作间的顺序可以被优化重排。文章还特别指出了JVM对异常处理的特殊照顾,以确保`try-catch`块中的逻辑不被重排序破坏。 然而,文章的重点在于揭示重排序对多线程程序的潜在风险。通过一个使用了`volatile`的经典示例,作者展示了当两个线程共享变量且没有同步控制时,指令重排序(如赋值操作的顺序调换)可能导致其他线程观察到“中间状态”,从而破坏了程序预期的执行语义。这明确区分了重排序在单线程与多线程环境下的不同影响。 对于开发者而言,理解重排序是掌握Java并发编程中可见性问题的基础,它解释了为何在多线程场景下必须谨慎使用同步工具(如`volatile`或锁)来建立必要的内存屏障。

本机暂存
IT 2017-03-01 23:01:17 / 累计浏览 2,922

【死磕Java并发】—–Java内存模型之分析volatile

这篇讲的是volatile关键字在Java内存模型(JMM)中的深层实现原理。作者从volatile的两大核心特性——可见性与禁止重排序出发,深入剖析了JMM是如何通过“内存屏障”这一底层机制来保证这些语义的。 文章通过一个经典的`VolatileTest`代码示例,生动演示了volatile读写操作如何与happens-before原则配合,确保跨线程的数据可见性。更硬核的部分在于对内存屏障插入策略的详解:JMM采取了保守策略,在volatile读/写前后精确插入StoreStore、StoreLoad、LoadLoad、LoadStore等屏障指令,以此强制维护操作的顺序性。 但巧妙之处不止于此。作者引用《Java并发编程的艺术》中的例子进一步说明,编译器在实际执行时会进行优化,只要不破坏volatile的内存语义,就可以省略部分冗余的屏障指令。这让我们看到,JMM的实现既保证了正确性,也蕴含着对性能的考量。对于想弄清楚volatile“凭什么”能起作用的开发者来说,这篇文章从理论到图解都梳理得相当清晰。

本机暂存
IT 2017-03-01 22:58:18 / 累计浏览 2,143

【死磕Java并发】—–Java内存模型之从JMM角度分析DCL

这篇讲的是Java并发编程中一个经典而隐蔽的陷阱——双重检查锁定(DCL)在实现单例模式时,看似高效完美,实则潜藏因指令重排序导致的对象未初始化即被引用的严重问题。 作者从一个常见的错误懒汉式单例写法入手,逐步推导到试图优化性能的DCL写法。其核心矛盾在于:对象实例化包含“分配内存”、“初始化对象”和“引用赋值”三个步骤,而JVM或CPU可能对后两步进行重排序。这就意味着,在多线程环境下,其他线程可能看到一个已完成引用赋值、但尚未完成初始化的对象“半成品”,导致程序行为不可预期。 文章进而给出了两种标准解决方案。一种是利用`volatile`关键字的内存屏障语义,禁止实例初始化步骤的重排序,从而确保对象完全构造完毕后对其他线程才可见。另一种则是利用类加载机制,通过静态内部类延迟初始化,借助JVM对类初始化过程加锁的保证,来实现线程安全的单例。后者巧妙地将同步问题委托给了JVM本身,代码也更为简洁。 理解DCL的问题根源及解决方案,对于掌握Java内存模型中多线程可见性与指令重排序的实际影响至关重要。

本机暂存
IT 2017-02-19 23:54:58 / 累计浏览 1,861

Springboot 实现 Restful 服务,基于 HTTP / JSON 传输

这篇讲的是如何用Springboot快速搭建一个标准的Restful API服务。作者从一个完整的Web案例切入,演示了从数据库准备、项目结构解析到运行测试的全过程。核心聚焦在控制层的实现上,作者通过一个城市的增删改查Demo,清晰展示了如何使用`@RequestMapping`来映射不同的HTTP动词(GET/POST/PUT/DELETE),并配合`@PathVariable`和`@RequestBody`注解优雅地处理URL参数和请求体。文章还对REST风格的五大要素和HTTP方法做了简要知识梳理,帮助读者理解背后的设计理念。这是一个很典型的、即开即用的Springboot RESTful入门示例,体现了框架在简化Web服务开发上的便捷性。

本机暂存
IT 2017-02-19 23:53:55 / 累计浏览 3,023

为什么 Windows 的文件系统会有盘符,使用反斜杠分割路径

这篇技术博客从一个轻松的讨论切入——Windows系统在挂载大量盘符后会出现双字母命名的“诡异”现象,进而探讨其背后的设计逻辑。作者指出,虽然从现代视角看,盘符和反斜杠似乎是冗余的历史包袱,但其根源深植于MS-DOS的早期发展。 文章追溯到MS-DOS 1.0时代,当时主流软盘没有层级目录。盘符(A:、B:)的设计直接借鉴了更早的CP/M系统,方便用户在两个软盘驱动器间操作。随着IBM PC/XT引入10MB硬盘,盘符扩展到了C:。而路径分隔符选用反斜杠“\”而非Unix的“/”,是因为MS-DOS的开发者继承了DEC系统使用“/”作为命令行参数分隔符的惯例,为避免混淆,只能选择其他符号作为目录分隔符。 作者通过这段历史对比了Windows与Unix系系统的设计哲学:Unix将物理存储通过挂载点透明地整合进统一文件树,而Windows保留了显式的盘符概念。这些早期设计决策,最终形成了我们今天看到的、让不少程序员感到“深恶痛绝”的Windows路径风格。

本机暂存
IT 2017-02-06 23:18:08 / 累计浏览 3,188

关于TCP可靠性的一点思考,借此浅谈应用层协议设计

这篇讲的是,作者从网络游戏开发转向网络存储、机器学习等场景后,对TCP“可靠性”的重新审视。他提出,在需要重连重试的严肃应用中,TCP的ACK机制和操作系统的发送成功通知并不可靠——比如网络故障后,应用层无法获知哪些数据丢失,已提交的缓冲区也可能被释放,导致数据无法重发。 文章的核心,是剖析了三个基于TCP的应用层协议设计陷阱:发送方无法确认接收状态、无法区分“成功”与“未失败”、以及重试可能导致数据重复。针对这些“坑”,作者给出了具体的应对方案:必须在应用层设计确认应答(ACK);对于大文件追加,应采用带偏移量的positioned write;对于重复消息,则需在应用层进行去重。 最后,文章也讨论了优雅关闭连接的原则:应由接收最后一条消息的一方主动发起关闭。整篇文章从实际场景中的问题切入,深入浅出地阐明了在设计RPC协议时,不能盲目信任传输层,而必须在应用层构建自己的可靠性机制。

本机暂存
IT 2017-02-06 22:55:51 / 累计浏览 6,981

使用Mitmproxy分析接口

这篇讲的是如何使用开源的Mitmproxy来抓包分析移动端接口,作者从Charles收费、Fiddler Mac版不稳定的现状出发,引出了这款免费且稳定的替代工具。 文章不仅讲了安装,更重点演示了如何配置证书以拦截HTTPS请求。作者以汽车之家APP为例,完整展示了从配置代理、捕获流量到分析接口的实战过程。过程中有个有趣的发现:APP并非直接调用域名,而是通过HttpDNS获取IP,并在请求头中携带Host信息。直接访问截获的IP地址会无效,必须补充Host才行。 更精巧的是,在尝试获取品牌数据时,作者发现即使地址正确,返回结果也是空的。通过仔细比对请求与响应中的时间戳,他推测APP实现了一套自定义的缓存机制。主动调低请求中的ts参数后,成功拿到了完整的品牌列表数据。照此方法,他最终顺利获取了车系和车型的全部接口。 虽然演示基于特定版本的APP,但文章提供的这套从工具配置到逆向分析接口参数的方法论,具有很强的通用性,为服务端开发者打开了一扇观察移动端数据流向的窗口。

本机暂存
IT 2017-02-06 22:52:02 / 累计浏览 2,342

【死磕Java并发】—–深入分析synchronized的实现原理

这篇讲的是Java开发者最熟悉的synchronized关键字,但深入到了它鲜为人知的底层实现。文章从开发者早期对synchronized“重量级锁”的刻板印象出发,系统剖析了JDK 1.6对其进行的一系列优化,彻底改变了这一认知。 作者首先拆解了同步代码块与同步方法在JVM字节码层面的不同实现(monitorenter/monitorexit指令与ACC_SYNCHRONIZED标志),并指出这一切的基础在于Java对象头中的Mark Word和Monitor结构。其中,Mark Word被设计成可随锁状态动态复用的高效数据结构,是理解锁升级的关键。 文章的核心价值在于清晰梳理了JVM的锁优化机制:从通过“自旋等待”避免线程频繁挂起,到引入“适应性自旋”让虚拟机智能调整等待次数;从利用逃逸分析“消除”不必要的锁,到将连续操作“粗化”为更大范围的锁。最终,重点阐释了锁状态如何从无锁、偏向锁、轻量级锁一步步升级到重量级锁的完整路径,以及每一步升级的触发条件与设计意图。这不仅是理解synchronized的百科全书,也为开发者在实际编程中合理使用同步工具提供了底层视角。

本机暂存
IT 2017-01-16 00:13:57 / 累计浏览 3,061

订单号的生成规则

订单号生成是电商、O2O等系统的经典难题:既要保证全局唯一,又不能暴露每日流水等商业机密,同时还得满足语义性、快速路由分库分表以及控制长度等实际需求。这篇文章从这一核心矛盾出发,拆解了业内几种主流的生成策略。 文章具体分析了大众点评、美团团购和淘宝的实践。例如大众点评采用“时间戳+用户标识码+随机数”来兼顾唯一与信息隐藏;美团团购和淘宝则巧妙地结合了“单表自增ID/发号器ID”与“买家ID的后几位”,这种设计不仅保证了唯一性,更关键的是能通过订单号直接计算出数据路由,快速定位到对应的库与表。 除此之外,文章还介绍了分布式ID发号器的整体架构(如美团的Leaf),解释了如何通过独立服务来生成全局有序或趋势递增的ID号段,以支撑高并发和分库分表的场景。对于正在设计订单系统或对分布式ID生成感兴趣的开发者来说,这些来自大厂的实战总结提供了清晰的思路和可靠的参考方案。

本机暂存
IT 2016-12-22 23:35:13 / 累计浏览 1,921

HTTPS 常见部署问题及解决方案

这篇文章整理了作者在 HTTPS 和 HTTP/2 部署实践中收集的典型故障与解决方案,堪称一份实用的排错手册。 遇到问题时,作者推荐首先使用 Qualys SSL Labs 的在线测试工具进行诊断。针对 Let's Encrypt 证书申请验证失败的情况,文章建议改用 acme.sh 的 DNS 验证模式,通常能绕过服务器访问限制。对于 Chrome 53 浏览器报告的 ERR_CERTIFICATE_TRANSPARENCY_REQUIRED 错误,根因是 Chrome 的一个 Bug,解决方案是升级浏览器版本。 当浏览器提示证书错误时,文章指出需检查证书链的完整性,特别是不要遗漏中间证书。如果问题仅出现在老旧浏览器(如 IE8),则很可能是未启用 SNI(服务器名称指示)导致,可通过将站点部署在不同服务器、使用 SAN 证书或直接忽略这些旧浏览器来解决。 启用 HTTP/2 后访问异常(如 ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY),通常是因为 CipherSuite 配置不当,可参考 Mozilla 或 CloudFlare 的权威配置进行调整。若浏览器在 Nginx 启用 HTTP/2 后仍降级为 HTTP/1.1,则可能是 OpenSSL 版本过低(低于 1.0.2)不支持 ALPN 协议协商所致。 最后,升级 HTTPS 后网站部分资源无法加载,原因往往是混用了 HTTP 资源,解决方案是确保所有外链资源均使用 HTTPS 协议。文章内容会持续更新,为开发者提供了具体的排查思路和改进方案。

本机暂存
IT 2016-12-22 23:28:32 / 累计浏览 3,183

PHP的性能演进(从PHP5.0到PHP7.1的性能全评测)

这篇评测通过CPU基准测试脚本,系统比较了PHP从5.0到7.1各主要版本的性能表现。作者发现,性能提升主要发生在主版本迭代时,而非小版本更新。例如,PHP 5.1比5.0性能翻倍,PHP 5.4有一次显著跃升,而PHP 7.0则实现了重大突破,其重新设计的Zend Engine使性能得到质的飞跃。 测试数据直观展示了这一历程:在bench.php脚本中,PHP 7.0比5.0快了数倍,而试验性的JIT分支(预览PHP 8)更是将差距拉大到40倍以上。文章也梳理了各版本的核心优化点,从PHP 5.1的编译变量与执行器优化,到PHP 5.4的内部字符串优化,再到PHP 7.0全面重构的数据结构与内存管理。 除了回顾,文章也展望了引入JIT编译技术的PHP 8,指出这将是另一个性能飞跃点,但同时也提醒其效果因场景而异。对于PHP开发者而言,这份横跨十余年的评测,不仅验证了每次重大升级的价值,也为性能优化与版本升级决策提供了扎实的数据参考。

本机暂存
IT 2016-11-06 22:22:31 / 累计浏览 2,684

Python 代码规范小结

这是一份从实践中总结的 Python 代码编写规范清单。作者从一次 code review 的小结出发,强调了两个核心原则:一切都与复杂度有关,以及代码应当易于理解。 文章将规范具体化到了编码的各个环节。在基础风格上,它指出代码被阅读的次数远多于编写和修改的次数,因此可读性至关重要。接着,文章系统性地梳理了注释、命名、常量、变量、数据结构以及表达式的写法,并深入到了控制流(分支、循环、异常处理)的具体实现建议。对于函数和类的设计,文中也给出了相应的组织思路。最后,内容还延伸到了模块、抽象与整体设计层面。 特别值得一提的是,文章提出了一个评估项目可行性的公式:可行性=(当前价值+未来价值)/(实现成本+维护成本),强调了降低长期维护成本的优先级。这些从具体语法细节到宏观设计思想的总结,为写出更规范、更易于维护的 Python 代码提供了清晰的路线图。

本机暂存
IT 2016-11-06 22:20:50 / 累计浏览 1,085

Lua 中 Cache 冷数据的落地

这篇讲的是如何在 Lua 虚拟机中,为缓存模块设计一个安全的冷数据落地机制。作者从一个实际 bug 讨论出发,详细分析了不同方案的演进。 文章最初提出一个基于时间戳的朴素方案,但发现其无法保证业务正在使用数据时,数据不会被错误地异步写回。随后,作者引入 Lua 弱表和 `__gc` 元方法进行改进,利用垃圾回收机制来判断数据是否“冷”。然而,这个方案存在一个微妙的“第三状态”漏洞:当对象被 GC 回收、但其 `__gc` 方法尚未将其“复活”到待处理表时,系统会短暂地失去对该数据的追踪,导致可能从数据库加载出旧版本的数据。 为解决这个并发与状态管理的核心难题,文章最终提出了基于元表代理的方案。通过让 cache 表存储代理对象,将真正的数据隔离在另一个全局表中,从而稳定了数据从缓存中移除的时机,并使冷数据落地流程可以清晰地通过集合差集来识别目标,避免了复杂的状态竞争问题。这实质上是用间接层换取了状态管理的清晰与安全。

本机暂存
IT 2016-07-17 23:52:37 / 累计浏览 2,842

一次连接超时问题排查的历程

这是一次典型的、从迷茫到顿悟的故障排查历程。作者从一个Java应用启动时偶尔发生、且目标服务器不固定的数据库连接超时问题出发,展开了一场层层深入的调查。 排查始于网络抓包,但发现了更怪异的现象:部分TCP连接的SYN包似乎从未发出,而另一些则在收到服务器SYN/ACK后被客户端立即RST。通过strace工具,作者确认了所有connect系统调用均已执行,超时发生在内核的poll等待阶段,这解释了RST的由来,但问题的源头——从系统调用到网络发包之间那段莫名的“延迟”——依然成谜。 对内核网络栈的初步探索未果后,一次未过滤ARP包的抓包带来了转机。作者发现,连接失败的IP地址对应的ARP请求首次均无响应,需等待1秒后重试才成功。这1秒的延迟,足以让设定为50毫秒的连接超时大量失败。根因在于局域网存在广播限流,导致启动时ARP请求被丢弃,而一旦应用启动成功,持续的通信就会维持ARP缓存,故运行时再无此问题。 从复杂内核栈排查到基础的ARP缓存,作者也感慨这个原因“如此操蛋没技术含量”。但这个过程生动地说明,面对诡异的系统问题,保持开放的排查思路,并扎实地追踪数据流的每一环,是定位真相的关键。

本机暂存
IT 2016-06-06 23:44:40 / 累计浏览 5,042

Kindle 电子书生成工具

这篇讲的是开发者如何为纯粹阅读打造一款 Kindle 电子书生成工具。作者从自身需求出发,为了解决手机阅读干扰多、伤眼的问题,花了两个晚上钻研 OPF 和 EPUB 格式,最终构建了一个能将网络内容一键转换为 Kindle 电子书的命令行工具。 该工具的核心原理是依据 OPF 规范生成 KF8 格式的 .mobi 文件。它的数据来源相当灵活:既可以通过指定 URL 和 DOM 选择器抓取单篇文章,也能直接订阅 RSS 源获取更新,甚至能处理本地 Hexo 博客生成的 HTML 文件。程序会智能分析和过滤数据,对 Hexo 文件做了特殊适配,并且能自动下载页面中的远程图片和 CSS 样式,确保电子书内容完整。 项目已将 Amazon 官方的 kindlegen 工具内置,目前默认支持 Mac 系统,但通过社区贡献也提供了 Windows 平台的支持方案。整个流程被简化为编辑配置文件或运行命令行,目标是让技术爱好者和内容创作者都能轻松地把零散的网页文章“打包”成一本本精致的电子书。

本机暂存
IT 2016-06-06 23:43:17 / 累计浏览 3,546

Spark性能优化——和shuffle搏斗

这篇讲的是Spark性能调优中一个最头疼的问题——shuffle。作者把shuffle比作必须击败的“大boss”,因为它会触发大量网络传输和序列化,让原本在内存中飞快的计算慢下来。 文章没有堆砌理论,而是直接切入实战技巧。比如,作者用一个从3小时缩短到20分钟的例子,说明“先各自去重,再合并”为何能大幅减少shuffle数据量;还对比了`mapValues`与`map`、`reduceByKey`与`groupByKey`,点明哪些操作会偷偷引发shuffle,而哪些能保持本地高效计算。 针对常见的大小表join,文章给出了一个巧妙思路:把小表广播出去,用`broadcast`加`filter`直接替代耗时的`join`操作,能完全避免shuffle。对于数据倾斜导致单节点过载的问题,作者也指出了改进key设计的解决方向。 整篇文章就像一位有经验的工程师在分享如何“避坑”,从原理到代码示例都很具体,最后还提醒了关于`collect`、避免RDD嵌套操作等容易忽略的细节。对于用Spark处理大数据的人来说,这些围绕shuffle的优化思路相当实用。

本机暂存
IT 2016-06-06 23:35:11 / 累计浏览 4,667

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开发者而言,这无疑是一份扎实的起点地图。

本机暂存