IT技术博客大学习 共学习 共进步

系统架构

共 731 篇文章

IT 2015-01-04 23:07:06 / 累计浏览 3,794

Feed消息队列架构分析

这篇讲的是微博为应对实时Feed流挑战而构建的消息队列架构。作者从数据流处理从离线走向实时的行业趋势切入,详细拆解了支撑海量社交信息流的底层架构。 核心是一个由三部分构成的体系:中间是feed主流程处理,通过MQ worker异步写入缓存和数据库,完成核心的削峰填谷;左侧是流式计算,用于大数据实时分析;此外还有负责多机房数据同步的“虫洞”模块。整个系统建立在几个关键单元上:单机队列MQ、支持一对多投递的统一通道Firehose(具备基于社交关系的fan-out能力),以及无状态的Worker。 架构设计上,文章强调了其高实时性(要求100ms内处理完成)、线性可扩展性与超高可用性(99.999%)。最后,文章还对比了LinkedIn Databus、Apache Storm和Kafka等技术路线,解释了为何其业务主动写入事件的方案在复杂分库场景下,比数据库触发方案更具原子性和简洁性。

IT 2015-01-04 23:00:49 / 累计浏览 8,692

Feed架构-我们做错了什么

这篇讲的是微博技术团队在Feed架构演进中的一次坦诚复盘与反思。作者从团队过去几年成功解决的工程挑战切入——包括通过冷热分区设计应对长尾数据访问、利用数据库拆分实现存储扩展、依托缓存分级支撑百万级QPS,以及建设高可用的SLA体系。 但文章的重点不在这些成就,而是深入剖析了基于用户关系的分发架构在用户侧引发的“信息过载”问题。核心观点是:架构在解决了可扩展性与性能问题后,却造成了内容组织与消费效率上的新瓶颈。具体表现为:当前架构天然基于用户关系维度组织数据,这很难服务于更高效的“兴趣阅读”需求;同时,低质内容识别、实时反垃圾算法仍面临巨大技术挑战;此外,社交关系带来的“可解释性”要求(用户期望看到好友内容)也与纯粹的算法排序存在矛盾。 作者通过这次复盘,揭示了一个关键认知:Feed架构的难题已从纯粹的后端扩展性问题,转向了如何通过技术更好地理解与满足用户兴趣,同时平衡产品体验的复杂层面。这对于思考推荐系统与社交产品架构的未来方向,提供了很有价值的视角。

IT 2015-01-04 14:17:59 / 累计浏览 2,289

从未降级的搜索-主搜索分层优化

这篇讲的是淘宝主搜索如何通过索引分层技术,将集群架构从二维升级到三维,从而解决长期存在的性能与扩展性瓶颈。 作者从主搜索沿用多年的二维架构出发,指出其存在机器消耗多、低质量商品拖累效率、索引结构单一且难以支持多样化排序等核心问题。文章提出的分层优化方案,核心思路是将商品按质量(Good/Bad)和特定排序需求(如人气)拆分成不同集群,并设计相应的检索策略。例如,对人气排序查询优先走仅包含头部商品的Excellent集群,而对一般查询则优先查Good集群,不足时再补充Bad集群。 这种三维架构带来了显著收益:不仅将集群规模缩减了36%,整体检索性能提升了120%,最终还带动了6%的搜索GMV增长。文章用清晰的架构图和具体数据,展示了如何通过精巧的索引设计,在控制成本的同时满足多样化的排序需求,为主搜索的业务拓展提供了坚实的技术基础。

IT 2014-12-30 12:35:28 / 累计浏览 12,333

好的API设计

这篇文章从一次实际的中间件重构经历出发,探讨了“什么样的API才算是好API”。作者指出,API一旦发布便难以更改,因此在设计之初就需格外审慎。 文章清晰地界定了API不仅限于函数或接口,还包括调用方式、约定与依赖等。其核心部分总结了优秀API应具备的六大特点:易于学习、无文档也易用、不易误用(降低使用者心智负担)、使使用者的代码更易维护、能完备且正交地满足需求,以及易于扩展。 针对如何实现,文章提炼出八条精炼的设计原则:功能单一、体量尽可能小、减少外部依赖、设计不被实现细节所影响、谨慎暴露接口、采用自描述的命名、配套完善的文档,并始终考虑性能。文末附有多个跨语言的参考资料来源,为这些原则提供了扎实的理论依据。 整篇文章没有空谈理论,而是从“发布即定型”的现实约束出发,将API设计拟人化,强调其“秉性”的稳定。它为开发者提供了一份清晰可操作的自查清单,提醒我们在敲下第一行实现代码前,先思考如何设计一个“好相处”的接口。

IT 2014-12-30 12:22:52 / 累计浏览 14,193

无锁消息队列

这篇讲的是如何在共享内存中设计高效的无锁消息队列。作者从实际项目需求出发——为了将耗时的数据落地任务从主逻辑进程中剥离,以提升整体处理能力——提出了用无锁队列替代频繁系统调用的方案。 文章的核心是从简单到复杂,逐步推演无锁队列的设计。首先探讨了最基础的单生产者与单消费者场景,仅需维护 front 和 rear 指针,利用循环队列即可高效工作。接着,为解决多消费者并发出队的问题,引入了 CAS(Compare & Set)原子操作来安全地更新指针。最后,在多生产者多消费者的最复杂场景下,通过增加一个 write_index 变量,结合两次 CAS 操作来协调生产者之间的写入竞争,确保了数据一致性。 文章结合具体图示和伪代码,清晰地阐述了不同并发模型下的实现关键与细微差别,例如利用 CAS 实现“乐观锁”,以及在生产者操作失败时通过 sched_yield() 让出 CPU 的优化技巧。作者在项目中实际应用了其中一种设计,最终观察到 CPU 使用率下降了约10%,验证了该方案的有效性。

IT 2014-12-30 12:17:01 / 累计浏览 1,930

标准化与可复用杂谈

这篇讲的是从一次具体的线上问题排查说起,引申出对软件工程中“标准化”与“可复用”的思考。作者描述了一个典型场景:用户反馈的问题经过层层传递,工程师最后发现是某台服务器在特殊情况下启动了错误版本,导致返回数据异常。这背后暴露的是从代码测试、服务调用到上线发布的全流程中,处处依赖人工细心所潜藏的高风险。 文章的核心观点在于,将全流程中那些不易变的单元(如测试、服务交互规范、发布步骤)进行标准化,并用程序来控制,可以从源头减少低级错误。作者以一个深度使用消息队列但因标准化和抽象不足,导致经验难以复用的团队为例,说明了这一点。同时,文章也对比了国内外对工程师严格要求的差异,指出在业务驱动、快速交付的压力下,形成高质量代码共识与推动标准化建设的不易。 文章的启发在于,它并非空谈架构,而是从运维和开发的共同痛点出发,论证了标准化对于解放工程师精力、提升系统可靠性的实际价值,尤其适合那些正被重复性故障和低效协作困扰的技术团队反思。

IT 2014-12-08 23:39:43 / 累计浏览 3,695

应用层的容错与分层设计

这篇讲的是分布式系统中,如何为应用层远程调用构建健壮容错体系的实践思考。文章从实际项目问题出发,指出系统内部服务间远程调用的不可靠性——无论是网络波动、硬件故障还是服务本身变慢,都可能像多米诺骨牌一样拖垮整个系统。单纯依赖服务端容错还不够,调用端(应用层)必须有独立的防御设计。 作者以微博团队的实践为例,分享了不同场景下的容错策略:访问MySQL时,写操作直接抛异常,读操作则有多级Failover;连接Redis或Memcached则需设置超时、异常标记、定期探测,并通过一致性哈希切换到备份节点;调用HTTP接口则要短超时、谨慎重试,并配合业务降级。 这些分散的实现暴露了问题:各客户端独立编码,原理相通却无法复用,维护成本高,且同步调用消耗大量线程资源。文章进而探讨了统一解决方案的可能性,参考了Twitter的Finagle框架思路——将容错、重试等策略抽象为“Filter”,与服务和Future模型结合,实现异步化的通用网络客户端。一个理想的统一client应该具备分层设计(服务层、网络层)、可扩展协议支持,并内置负载均衡、Failover等高可用能力,最终让开发者更专注于业务逻辑而非繁琐的容错细节。

IT 2014-12-04 13:31:54 / 累计浏览 3,394

Nginx缓存解决方案:SRCache

作者在优化PHP程序时,首先启用了Nginx内置的FastCGI Cache,但发现它不支持分布式缓存,在多服务器场景下存在资源浪费和数据一致性难题。这让他开始寻找更精细的解决方案。 这篇文章的核心就是介绍SRCache这个模块。它作为FastCGI Cache的补充,能实现更细粒度的缓存控制。作者展示了SRCache如何与Memc模块配合处理简单场景,而在需要动态计算缓存键等复杂需求时,则通过Lua脚本进行灵活扩展。 文章详细解读了这套方案的配置实践。通过自定义的Lua脚本,作者实现了对请求的智能判断:只有匹配特定规则的请求才会开启缓存,缓存键由请求方法、主机名和URI等信息动态生成。这种设计既避免了缓存的无效占用,也保证了缓存的精准命中。 整体来看,SRCache提供了一套从粗放式到精细化缓存管理的平滑升级路径。它通过开放的Lua集成,将缓存决策权交给了开发者,能有效应对复杂多变的生产环境需求。

IT 2014-12-04 13:29:25 / 累计浏览 7,994

Redis和Memcached的区别

这篇讲的是Redis和Memcached这两种内存数据库的核心区别。文章从Redis作者的一个经典比较出发,清晰梳理了三者关键差异:首先,Redis支持String、Hash、List等更丰富的数据结构,可以在服务器端直接进行复杂操作,避免了Memcached需要将数据取回客户端修改的额外开销。其次,在内存效率上,若采用hash结构存储,Redis的组合压缩机制可能比Memcached更具优势。最后,性能表现各有特点:处理小数据时Redis的单核性能更优,而在100k以上的大数据场景中,Memcached的多核处理能力则略占上风。 文章随后深入剖析了Redis五种数据类型的实现原理,例如Hash内部如何根据成员数量自动转换存储结构,以及Set如何通过HashMap实现快速去重。这些细节不仅解释了差异背后的技术原因,也揭示了各自的设计考量。 总的来说,如果你的应用需要丰富的数据结构和复杂操作,Redis是更强大的选择;而如果是纯粹的、简单的大规模键值缓存,Memcached在内存利用和特定数据量级下的性能或许更合适。文章为技术选型提供了扎实的对比依据。

IT 2014-12-04 13:20:25 / 累计浏览 2,412

HQueue:基于HBase的消息队列

这篇讲的是阿里一淘团队如何用HBase“搭积木”,造出一个叫HQueue的分布式消息队列。作者从时间序列存储、MapReduce数据输入输出等场景的实际需求出发,选择了站在HBase的肩膀上。 核心思路很巧妙:把消息直接存为HBase的KV对,利用HTable的多Region实现高并发,用Coprocessor来保证消息ID的唯一有序,并处理消息的持久化。这样一来,HBase本身的自动Region迁移、动态负载均衡和数据持久化能力,就直接变成了HQueue的“超能力”,实现了自动容错、消息不丢和性能优化。 文章还详细拆解了它的设计细节:比如用PartitionID+Timestamp+SequenceID组合成RowKey来保证消息全局有序,通过不同的Scanner支持灵活扫描,以及在0.3版本后引入的基于ZooKeeper的订阅推送机制。整体来看,这为需要可靠消息队列又已有HBase技术栈的团队,提供了一个无需额外组件、可随HBase无缝升级的解决方案。

IT 2014-12-04 13:18:23 / 累计浏览 3,514

构建C1000K的服务器(2) – 实现百万连接的comet服务器

这篇讲的是作者如何从零实现一个支持百万并发连接的Comet服务器。在解决了系统内核参数调整的基础问题后,文章将焦点转向了具体的应用实现。 作者选择用C/C++和libevent来构建核心,重点在于如何高效管理百万级的连接与通道。一个巧妙的设计是:服务器启动时便预先分配好100万个通道对象,而动态的订阅者则通过内存池管理,这使得初始内存占用控制在24MB。 最吸引人的是文章展示的实测数据。通过逐步增加连接数进行压力测试,结果非常直观:每个Comet连接大约只消耗2.7KB内存。最终,在支撑100万空闲连接时,进程总内存占用约2.7GB,而CPU使用率维持在0%。这清晰证明了该架构在高并发、低活跃度场景下的高效性。 项目的代码已在GitHub开源,文章提供的测试方法和详细数据,为需要构建类似长轮询服务的开发者提供了一个扎实的参考范例。

IT 2014-12-04 13:17:16 / 累计浏览 4,147

构建C1000K的服务器(1) – 基础

当C10K问题已成为历史,作者将目光投向了更宏大的C1000K挑战。对于Twitter、微博这类需要维持千万级实时连接的平台,单机百万连接(C1000K)的能力能极大降低服务器集群规模。 这篇文章并没有直接给出某个框架或库的解决方案,而是从根源出发,剖析了限制C1000K实现的四大核心因素。作者以Linux为例,深入讲解了如何突破操作系统默认的“最大打开文件数”限制,给出了包括临时修改(ulimit)和永久配置(sysctl.conf, limits.conf)在内的具体方法与命令。文章还通过一个原始的C语言服务器程序,实际测量并验证了操作系统为维护百万连接所消耗的内存,将理论估算与实际开销结合起来分析。 作者强调,解决C1000K问题不能盲目追求新技术,而应先理清操作系统内核、内存分配与网络吞吐这些底层瓶颈。文中的系统参数配置和测试思路,为需要应对海量并发连接的开发者提供了切实可行的排查起点和优化依据。

IT 2014-12-03 23:58:46 / 累计浏览 2,155

Pora2应用中HBase高并发读写性能优化

这篇讲的是淘宝搜索的Pora2实时分析系统在大量使用HBase进行高并发读写时,所遇到的一系列性能“坑”及优化实践。系统上线后出现处理延迟、集群压力大的问题,排查发现根源主要在于HBase的使用方式。 文章拆解了几个典型案例:一是HBase默认的Periodic Flusher机制引发了过于频繁的flush与compact,通过调整其超时阈值得到了缓解;二是下游消费消息队列时未控制Scan频率,对Region Server造成了无谓压力;三是在超大并发下,过多的客户端连接耗尽了服务端Handler,作者的解决方案是减少进程数、增加线程数以复用连接。 此外,还涉及了因rowkey生成代码bug导致的数据访问热点,以及Bulk Load数据未做Major Compaction引起的读取性能衰减。文章最后总结道,高并发场景下必须合理使用HBase,避免不当操作形成“越慢越压、越压越慢”的恶性循环。这些从实战中沉淀的细节,对同类系统的设计与调优很有参考价值。

IT 2014-12-02 00:07:03 / 累计浏览 7,361

memory prefetch浅析

作者在用VTune分析程序性能时,发现大数组的非连续访问成为了CPU热点。经过排查,主要原因是这类访问模式对CPU缓存(Cache)很不友好,导致了大量的缓存未命中,从而拖累了性能。 为了优化这个问题,作者引入了x86架构提供的`prefetch`系列指令。其核心思想是,在程序真正用到数据之前,提前将指定地址的内存数据预取到各级缓存中,从而“掩盖”掉后续访问时的内存延迟。 文中提供了一段详细的测试代码,通过控制内存访问模式(顺序或跳跃)和计算复杂度,量化对比了预取指令的效果。测试数据显示,在跳跃访问内存导致性能严重下降的情况下(例如从22秒涨到66秒),加入恰当的预取操作后,执行时间基本恢复到了顺序访问时的水平(约28秒)。这直观地证明了预取指令在特定场景下能有效隐藏内存访问开销。 文章最终总结出prefetch的适用边界:当程序同时存在可观的内存访问延迟和一定的计算开销时,预取能有效提升性能。但如果计算本身很轻量,或者数据本身已在缓存中(如顺序访问),单纯依靠预取来加速读内存的意义则不大。

IT 2014-12-02 00:04:44 / 累计浏览 4,069

中大型移动互联网公司技术架构选择

这篇讲的是中大型移动互联网公司在技术架构演进中的核心选择与思考。作者从多年经验出发,提出架构需快速部署、天然可扩展、高度自动化与量化,并尽可能保持同构化,以降低整体复杂度。 文章以一张手绘架构图为脉络,自上而下逐层剖析。核心方案强调:在接入层通过定制网络套件屏蔽客户端网络细节;业务层力求统一语言(如Java),避免异构系统带来的重复建设与兼容问题;RPC与队列需框架化,配置管理推荐ZooKeeper;日志系统选用scribe或Kafka,并指向HDFS/HBase进行数据分析。监控与跟踪系统则分别推荐了Ganglia、Nagios与Zipkin。 更底层,文章讨论了使用Docker/LXC进行硬件虚拟化,构建统一的PAAS资源控制与运维平台。在开发流程上,强调从自动部署、测试框架、Maven编译、Sonar代码质量到GitLab代码托管的完整工具链支撑,甚至包括用于故障反思的Post-mortem系统。 作者的最终目标很明确:通过这套从用户层到代码生成层的体系化设计,让开发、测试与运维工作尽可能自动化、标准化,从而支撑起业务的快速迭代与稳定运行。

IT 2014-12-01 23:49:39 / 累计浏览 7,799

POST与GET的区别及RESTful

这篇技术分析直指一个普遍存在的开发困惑:“POST能解决的问题GET都能解决”,但规范使用HTTP方法对于构建健壮、安全的Web应用至关重要。文章从实际用法出发,清晰地对比了GET与POST的核心差异。 GET被定义为“获取资源”,它天然是幂等的、可缓存的,数据附在URL上便于分享和书签,但有长度和字符限制。而POST是“发布新资源”,它非幂等(意味着可能产生副作用)、数据不可见、传输量基本不受限,更适合提交敏感或大量数据。文章还特别用数学例子解释了“幂等”这个关键但难懂的概念:即对同一URL的多次请求,应返回同样结果,这保障了请求的安全性。 最后,文章指出了许多项目未遵循HTTP规范的现状,并自然引出了RESTful架构——它通过将GET、POST、PUT、DELETE分别对应查、增、改、删操作,为这些方法赋予了清晰的语义。这篇内容有助于开发者从规范层面重新审视手头的代码。

IT 2014-11-30 23:33:23 / 累计浏览 10,554

初探单点登录 SSO

这篇讲的是单点登录(SSO)的基本原理,并通过淘宝与京东的实例,对比了两种主流实现策略的差异。 文章先阐释了SSO如何解决多产品线下的用户体验问题,即“一次登录,处处通行”。其核心在于认证系统为每个应用颁发“钥匙”(存于Cookie)。关键差异在于应用间如何获取这把钥匙。 作者通过抓包分析揭示了两种路径:淘宝的策略更偏向“后置式”,用户访问聚划算等未登录站点时,通过一系列跳转,由主站(taobao.com)的凭证去认证中心为当前站点领取新凭证。而京东的策略则是“前置式”,用户登录主站(jd.com)后,页面中的JS代码会立即通过JSONP跨域请求,主动为旗下所有子应用预置好登录凭证,实现更无缝的体验。 这种基于实际网络请求的剖析,清晰展示了SSO在“便利性”与“安全流程”之间的权衡,对于理解企业级统一认证架构的设计思路很有启发。

IT 2014-11-30 23:22:44 / 累计浏览 1,892

基于DRBD的高可用NFS解决方案分析

这篇讲的是如何用 DRBD 和 NFS 搭建高可用文件共享方案的一次实践与踩坑。作者从分析 NFS 协议(特别是 NFSv4 对迁移和故障恢复的定义)出发,设计了一个方案:底层用 DRBD 实时镜像块设备,在其上建立文件系统,再通过 NFS 共享,期望在主机故障时能实现业务无感知的切换。 按照这个思路,作者搭建了测试环境,模拟在线业务时进行 DRBD 倒换、NFS 重启和 IP 漂移。理论上,NFS 协议的“grace time”机制应该能处理服务端重启,让客户端用旧的文件句柄重新连接时依然能定位文件。 但实际测试结果是:客户端报出“NFS句柄无效”的错误。作者分析指出,关键问题在于 DRBD 镜像的块设备在两台主机上各自挂载后,生成的 inode 分配并不一致。尽管文件系统数据完全一样,但 NFS 服务端是通过宿主文件系统看到共享目录的,当发生切换后,对端无法正确解析客户端原有的、基于旧 inode 信息构造的文件句柄,导致访问失败。文章最后也坦诚了验证未能完全成功,并提出了后续可以从 NFS 源码层面探索直接共享 DRBD 设备内容的思路。

IT 2014-11-30 23:21:13 / 累计浏览 2,791

Openstack Swift简介

这篇讲的是 OpenStack 的核心对象存储服务——Swift 的设计哲学与实现原理。它要解决的核心问题,是如何在相对廉价的标准硬件上,构建出一个能承载海量非结构化数据的高可用、可无限扩展的存储系统。 文章深入解析了 Swift 的几个关键设计。为了解决海量数据的寻址难题,它采用了一致性散列技术,并通过一个名为“Ring”的独特数据结构,将数据均匀映射到物理设备上,在增减节点时大幅减少数据迁移。更精妙的是其一致性模型:Swift 在 CAP 理论下选择了“最终一致性”,通过 Quorum 仲裁协议(默认配置3副本、写需2个成功)来平衡可用性与一致性,以适应读写频繁的互联网场景。其清晰的数据模型(账户/容器/对象)和对称、无单点的系统架构,则进一步支撑了其多租户和横向扩展能力。 整体来看,文章从背景原理到架构细节,清晰地勾勒出了一个用软件层面的精巧设计(如一致性散列、Quorum协议)来弥补硬件简陋、并最大化可用性与扩展性的经典分布式系统范例。

IT 2014-11-30 23:16:14 / 累计浏览 3,969

手机应用/服务器开发的一些总结(二)

这篇讲的是自定义TCP socket开发中的实践经验与方案对比。作者从Android客户端和服务器端两个维度展开,重点讨论了阻塞与非阻塞socket的选型及具体实现中的“坑”。 Android端部分,作者对比了传统阻塞socket与NIO的使用差异,特别分享了NIO在实际业务中遇到的问题。例如网络断线时`finishConnect()`可能长时间阻塞,解决方案是通过`setSoTimeout`设置合理超时。同时也指出了NIO下`channel.read`不同返回值(如-1表示关闭、0表示无数据)的准确含义,这些细节对稳定开发至关重要。 Server端部分,作者分析了从Python标准库`ThreadingTCPServer`到异步框架tornado与gevent的演进。他指出,tornado的异步IO虽然性能高,但业务代码不能阻塞,使用起来有一定痛苦;而gevent则兼顾了性能与编码便利性。基于此,作者还封装了`tkola`和`gkola`两个库,采用类似Flask的装饰器风格来简化TCP server开发,并提供了清晰的代码示例。 总的来说,文章不仅梳理了不同场景下的技术选型逻辑,更分享了生产环境中的具体解决方案与开源工具,对从事移动端与服务器网络编程的开发者有较强的实用参考价值。