戴老师的博客 - 系统架构
type: channel
link: https://www.tushu.info/tag/%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/
items: 订单系统分库分表实践
items: 贯穿应用开发始终的八大性能陷阱
items: YouTube系统设计（第二部分）
items: Linkedin网站技术架构简介
items: Twitter网站架构学习笔记
items: 新浪微博技术架构分析
items: 订单表的分库分表方案设计(大数据.html)
items: 再谈最终一致
items: Java开源建站工具
items: 低代码编程及其市场机遇剖析 | 低代码技术内幕

订单系统分库分表实践
type: item
date: 2026-07-09T04:39:27+00:00
description: 背景与挑战订单单表大小早已突破 200GB，由于查询维度较多，即使增加了两个从库并优化了索引，仍然存在很多查询性能不理想的情况。随着去年大量抢购活动的开展，数据库达到瓶颈，应用只能通过限速、异步队列等机制对其进行保护。此外，业务需求层出不穷，原有的订单模型很难满足新的业务需求，但基于原订单表的 DDL 变更非常吃力，无法达到业务要求。随着这些问题越来越突出，订单数据库的切分变得愈发急迫。这次切分的目标是：未来十年内不需要担心订单容量的问题。总体架构演进垂直切分先对订单库进行垂直切分，将原有的订单库分为基础订单库、订单流程库等（本文不再展开详述）。垂直切分示意图垂直切分缓解了原来单集群的压力，但是在抢购场景下依然捉襟见肘。水平切分原有的订单模型已经无法满足业务需求，于是我们设计了一套新的统一订单模型。为同时满足 C 端用户、B 端商户、客服、运营等多方需求，我们分别通过 用户 ID 和 商户 ID 进行切分，并通过 PUMA（我们内部开发的 MySQL binlog 实时解析服务）同步到一个运营库。水平切分示意图分库分表策略1. 查询切分将 ID 和库的 Mapping 关系记录在一个单独的库中。查询切分示意图优点：ID 和库的 Mapping 算法可以随意更改。缺点：引入额外的单点风险。2. 范围切分比如按照时间区间或 ID 区间来切分。范围切分示意图优点：单表大小可控，天然支持水平扩展。缺点：无法解决集中写入瓶颈的问题。3. Hash 切分一般采用 Mod 来切分，下面着重讲一下 Mod 的策略。Hash 切分示意图数据水平切分后，我们希望方案是一劳永逸或易于水平扩展的，所以推荐采用 mod 2^n 这种一致性 Hash 策略。以统一订单库为例，我们分库分表的方案是 32 * 32 的：通过 UserId 后四位 mod 32 分到 32 个库中。同时将 UserId 后四位 Div 32 Mod 32，将每个库分为 32 个表。共计分为 1024 张表。线上部署情况为 8 个集群（主从），每个集群 4 个库。为什么这种方式易于水平扩展？我们分析如下两个场景：场景一：数据库性能达到瓶颈方法一：按照现有规则不变，可以直接扩展到 32 个数据库集群。扩展方法一方法二：如果 32 个集群也无法满足需求，那么将分库分表规则调整为 (32 * 2^n.html) * (32 / 2^n.html)，可以达到最多 1024 个集群。扩展方法二场景二：单表容量达到瓶颈（或者 1024 张表无法满足需求）方法：扩展方法三假如单表都已突破 200GB，200 * 1024 = 200TB（按照现有的订单模型估算，大概一万千亿订单，相信这一天指日可待）。没关系，采用 32 * (32 * 2^n.html) 策略，这时分库规则不变，单库里的表再进行裂变。当然，在目前订单这种规则下（用 UserId 后四位 mod）还是有极限的，因为只有四位，所以最多拆 8192 个表。至于为什么只取后四位，后面会有篇幅讲到。另外一个维度是通过 ShopID 进行切分，规则 8 * 8 和 UserID 比较类似，就不再赘述。需要注意的是，Shop 库我们仅存储了订单主表，用来满足 Shop 维度的查询。唯一 ID 生成方案这个方案很多，主流的有以下几种：1. 利用数据库自增 ID优点：最简单。缺点：单点风险、单机性能瓶颈。2. 利用数据库集群并设置相应的步长（Flickr 方案）优点：高可用、ID 较简洁。缺点：需要单独的数据库集群。3. Twitter Snowflake优点：高性能高可用、易拓展。缺点：需要独立的集群以及 ZK（ZooKeeper）。4. 一大波 GUID、Random 算法优点：简单。缺点：生成 ID 较长，有重复几率。我们的方案为了减少运营成本并减少额外的风险，我们排除了所有需要独立集群的方案，采用了带有业务属性的方案：时间戳 + 用户标识码 + 随机数有下面几个好处：方便、成本低。基本无重复的可能。自带分库规则：这里的用户标识码即为用户 ID 的后四位。在查询的场景下，只需要订单号就可以匹配到相应的库表而无需用户 ID。只取四位是希望订单号尽可能的短一些，并且评估下来四位已经足够。可排序：因为时间戳在最前面。当然也有一些缺点，比如长度稍长，性能要比 int/bigint 的稍差等。其他关键问题事务支持：我们是将整个订单领域聚合体切分，维度一致，所以对聚合体的事务是支持的。复杂查询：垂直切分后，就跟 Join 操作说拜拜了。水平切分后，查询的条件一定要在切分的维度内，比如查询具体某个用户下的各位订单等。禁止不带切分维度的查询。即使中间件可以支持这种查询（可以在内存中组装），但是这种需求往往不应该在在线库查询，或者可以通过其他方法转换到切…

贯穿应用开发始终的八大性能陷阱
type: item
date: 2026-07-09T04:39:16+00:00
description: 贯穿应用开发始终的八大性能陷阱编者注：本文为历史博文归档，内容涉及 JDK、框架与工具链版本请以当前官方文档为准。文中引用外链及图片可能失效，阅读时请注意时效性。摘要： 将应用交付给终端用户正变得越来越复杂，涉及的组件越多，犯错的可能性就越大。技术性能公司 Compuware 总结了贯穿应用交付流程始终的八大性能陷阱，这些陷阱不仅局限于开发阶段，还涉及从终端用户到后台系统的所有组件、数据库以及第三方服务。希望运维人员、架构师、测试人员和开发人员能引以为戒。常见的性能陷阱包括数据库访问低效、框架配置错误、内存使用过度、网页臃肿，以及不遵循常见 Web 性能最佳实践等。以下是 CSDN 摘译的详细内容：一、臃肿的 Web 前端面向群体： 运维人员、架构师、测试人员、开发人员通常企业在重构代码、优化 SQL 语句、应用缓存等方面都做了充足的优化，但其中大部分优化对应用的最终用户并不可见。然而，直接与用户交互的 Web 前端却常常被完全忽视。根据跟踪数据，传递给用户的页面在过去的 3-4 年里，无论是大小还是复杂度都稳步增长，同时用户对性能的要求也在提高。企业需要意识到，他们认为重要的功能其实并不是最重要的，更需要解决的是如何迎合用户的需求。但如何判断 Web 前端是否臃肿？通常的做法是与主要竞争对手以及行业领导者进行比较，通过横向对比更容易设定一个合理的目标。另外，理解用户为什么会离开你的网站也能够帮助解决客户体验问题：离开网站的主要是哪类人群？臃肿、缓慢的页面上是否有他们需要的应用功能？你可以使用缓存、压缩以及 CDN（Content Delivery Network，内容分发网络）来应对这样的问题，同时应该更严格地审核每一个新添加的功能，必要时做一些精简，以提供更好的用户体验。推荐阅读：Performance Improvement is not Performance OptimizationSuper Bowl Sunday 2013 – Winners, Losers, and Casualties二、缓慢的第三方内容和 CDN面向群体： 运维人员、架构师、测试人员仅仅关注自己的内容容易导致忽略外部组织对网站性能的影响。随着企业越来越多地使用第三方资源，应用性能管理（APM）变得更加复杂，即使这些第三方服务是为提升性能而引入的。通过观察过去 12 个月的性能峰值时期（比如假日购物季和超级碗）的数据，我们发现了两大趋势：第三方服务在用户集中访问的高峰期难以支撑，CDN 也在庞大的流量下艰难应付。分析、社交媒体、网络字体以及流行的 JavaScript 库等项目往往来自于无法直接控制的第三方服务，但你却依赖它来保证网站有效、可靠。当这些服务出问题时，用户记住的是“你”出问题了，而对这背后的第三方服务一无所知，导致你的企业品牌受损。监视、管理第三方意味着需要将它们当作独立应用、独立的基准、独立的 SLA（Service Level Agreement，服务品质协议）或者独立的 SLO（Service Level Objective，服务水平目标）。因此你需要自问：系统进行过负载测试了吗？网站三大用户高峰期同时遇到时，第三方服务是否能够抗住压力？遇到性能问题时是否存在扩展计划？过去的 12 个月最繁忙的 8 个小时中，网站用户体验达到平均性能要求了吗？最后，你的团队还需要应对这样的场景：如果相关第三方服务/CDN 遇到严重服务故障或者降低你网站的性能指标怎么办？永远要准备好 B 计划、C 计划，以缓解这些意外的问题。具体操作包括：在访问高峰期移除第三方标签、图片、内容；将内容移动到备用云服务商；多 CDN 间负载平衡；在访问高峰期将用户切换至简化版本的网站，直到流量恢复正常。想要真正控制第三方服务，你必须了解其对网站性能的影响，甚至控制第三方组件的方方面面。推荐阅读：You only control 1/3 of your Page Load Performance!Third Party Content Management applied: Four steps to gain control of your Page Load Performance!The Ripple Effect of Facebook's Outage, Third-Party Issues and the Performance Ripple EffectWebsite's Vulnerability to Third-Party Services ExposedSuper Bowl Sunday 2013 – Winners, Losers, and CasualtiesWhy Bon Ton needs real-time visibility…

YouTube系统设计（第二部分）
type: item
date: 2026-07-09T04:38:58+00:00
description: 本文是 YouTube 系统设计系列的第二篇文章。我们将承接 第一部分 的内容继续讨论，如果您尚未阅读，建议先查阅前文。在 上一篇文章 中，我们主要探讨了数据库和存储方案。本周，我们将深入讨论更多主题，包括可扩展性（Scalability）、Web 服务器、缓存策略以及安全性。数据库扩展一旦产品拥有数百万甚至数十亿的用户，就需要解决许多架构问题，其中可扩展性是最关键的挑战之一。基本上，将所有数据存储到单个数据库中不仅效率低下，而且在规模扩大后不可行。那么，您将如何扩展 YouTube 的数据库？扩展数据库时，我们可以遵循许多通用规则。最常见的方法是按需扩展。换句话说，不建议在项目第一天就完成所有工作（例如对数据库进行分区），因为几乎可以肯定的是，当您真正需要扩展时，整个基础设施和产品形态已经发生了巨大的变化。因此，合理的思路是从单个服务器开始。随后，您可以过渡到具有多个读取副本的单个主节点架构（主从模型)）。在某个阶段，您将必须对数据库进行分区并采用分片（Sharding）方法。例如，您可以按用户的位置拆分数据库，当请求到来时，将请求路由到相应的数据库分片。对于 YouTube，我们可以进一步优化这一策略。YouTube 的核心功能是视频。因此，我们可以通过将数据分为两个集群来优先处理流量：视频集群和常规集群。我们可以为视频集群提供大量资源，而其他社交网络功能则路由到资源配置较低的集群。这里的一个普遍理念是：在解决可扩展性问题时，应首先确定瓶颈，然后对其进行优化。在这种情况下，瓶颈在于视频观看流量。缓存策略我不会在此主题上过多谈论缓存，因为我们在上一篇文章"设计缓存系统"中已对此进行了详细介绍。但这里有几点值得一提。首先，谈到缓存时，大多数人的反应是关于服务器端缓存。实际上，前端缓存同样重要。如果要使网站快速运行并具有低延迟，则无法避免为前端设置缓存。这是在构建网站界面时非常常见的技术。其次，正如我们在上一篇文章中简要讨论的那样，缓存在提供视频内容方面不会带来显著好处。这主要是因为 YouTube 的大多数流量来自那些长尾视频（Long-tail Videos），为所有视频设置缓存将非常昂贵。因此，这里的总体思路是：如果您要构建类似的长尾产品，请不要在缓存上投入过多的赌注。安全性与反作弊YouTube 中有很多可以讨论的安全性话题。我想在这里介绍一个有趣的话题——视图造假（View Hacking）。在每个 YouTube 视频下，它都会显示观看次数，这表示视频的受欢迎程度。人们可以通过编程方式发送请求以伪造观看计数，那么我们应该如何保护它呢？最直接的方法是，如果特定 IP 发出太多请求，则将其阻止。或者，我们甚至可以限制每个 IP 的观看次数贡献。该系统还可以检查诸如浏览器代理（User Agent）和用户过去的历史记录之类的信息，这可能会阻止很多作弊攻击。人们可能会使用 Tor 之类的) 服务来隐藏 IP，而 Mechanical Turk 之类的 网站则允许您以非常低的成本向人们付费以单击视频。但是，黑客入侵系统比大多数人想象的要难。例如，观看次数高但参与度低的视频非常可疑。YouTube 拥有大量视频，因此提取实际观看次数的模式并不难。为了破解系统，您需要提供合理的参与度指标，例如分享数、评论数、观看时长等。几乎不可能伪造所有这些指标而不被检测到。Web 服务器架构许多人忽略了 Web 服务器，因为就系统设计而言，它似乎没有太多要讨论的内容。但是，对于大型系统（如 YouTube），您需要考虑很多事情。我想分享一些 YouTube 使用的技术策略。YouTube 服务器最初是用 Python 构建的，因此可以快速灵活地进行开发和部署。您可能会注意到，许多初创公司选择 Python 作为其服务器语言，因为迭代速度更快。Python 有时会遇到性能问题，但是有许多 C 扩展允许您优化关键部分，这正是 YouTube 早期的工作方式。要扩展 Web 服务器，您可以简单地拥有多个副本并在它们之上构建负载均衡器（Load Balancer）。服务器主要负责处理用户请求和返回响应。它应该没有什么繁琐的逻辑，其他所有东西都应该内置到单独的服务器中。例如，建议系统应该是一个单独的组件，以允许 Python 服务器从中获取数据。总结在本文中，我们尝试涵盖尽可能多的不同主题，并且可以在单独的文章中对每个主题进行更深入的讨论。将来我仍然想谈论很多事情，但是读者可以考虑一下并在评论中进行讨论。例如，YouTube 推荐是一个很大的话题，它极大地推动了用户参与度指标。您将如何建立推荐系统？此外，您如何确定当天的热门视频并向相关受众推荐？说明：本文基于早期 YouTube 架构案例整理，部分技术栈描述（如 Python 主导）反映的是历史演进阶段…

Linkedin网站技术架构简介
type: item
date: 2026-07-09T04:38:42+00:00
description: LinkedIn 网站技术架构简介以下是 LinkedIn 网站早期的基本运营数据与技术架构概况。基本运营数据用户总量：2,200 万月度独立访客：400 万日均页面浏览量 (Page View.html)：4,000 万日均搜索流量：200 万日均邀请发送量：25 万日均回答提交量：100 万日均邮件消息发送量：200 万这是一个具备世界顶尖流量的网站，以下是其当时的系统架构细节。技术栈概况操作系统：Solaris（运行于 Sun x86 平台及 Sparc 架构）应用服务器：Tomcat 和 Jetty数据库：Oracle 和 MySQL数据访问：无 ORM 框架（如 Hibernate），直接使用 JDBC消息队列：使用 ActiveMQ 发送 JMS 消息（按消息类型分区，后端由 MySQL 支持）搜索引擎：基于 Lucene 构建框架架构：使用 Spring 作为逻辑架构的粘合剂（Glue）架构演化历程随着流量的增长，LinkedIn 的架构经历了以下阶段的演化：2003 ~ 2005 年单体 Web 应用程序。单一核心数据库。所有网络关系图（Network Graph）缓存于 Cloud 中（Cloud 是用于缓存的独立服务器）。搜索功能基于 Lucene，同样运行在 Cloud 中。2006 年数据库复制：复制另一个数据库以减少核心数据库的直接负载，由另一台服务器管理非只读数据的更新。搜索独立：将搜索服务从 Cloud 中移出，单独使用服务器运行搜索。引入 Databus 数据总线：作为分布式更新的核心组件，任何组件的数据更新均需通过 Databus。2008 年服务拆分：Web 应用不再处理所有业务逻辑，将逻辑拆分为多个部分，通过服务器群处理。Web 应用主要负责提供用户界面，而用户资料、小组等数据由服务器群管理。数据库分域：每个服务拥有自己的域数据库。开放架构：新架构允许其他应用链接 LinkedIn，例如支持新增的招聘和广告业务。核心缓存层（The Cloud）这里的 "Cloud" 指的是 LinkedIn 内部自主研发的缓存层，而非公共云计算服务。核心地位：Cloud 是整个架构最重要的部分，LinkedIn 的整个网络关系图都缓存在其中。数据规模：2,200 万节点（Nodes），1.2 亿边（Edges）。内存需求：单个实例需要 12GB RAM。生产部署：生产环境需运行 40 个实例。重建耗时：从硬盘重建一个 Cloud 实例需要 8 小时。实时更新：通过 Databus 进行实时更新。持久化：关闭时将数据持久化到硬盘。实现语言：缓存通过 C++ 实现，通过 JNI 调用。LinkedIn 选择 C++ 而非 Java 主要基于以下原因：尽可能减少 RAM 的使用。避免垃圾收集（GC）暂停导致系统不可用（尽管当时已采用最新的 GC 程序）。设计权衡：将所有数据放入缓存是一种限制，但 LinkedIn 指出，分割业务图将带来更大的复杂性。硬件支持：Sun 提供了 2TB 的 RAM 支持。通信架构（Communication Architecture）通信服务（Communication Service）主要用于提供持久化信息，例如收件箱消息和 Email。异步通讯：整个系统通过 JMS 进行异步通讯。消息发送：客户端通过 JMS 发送消息。路由机制：消息通过路径服务器到达相应的邮箱，或直接放入 Email 处理进程。推送模式：同时使用 Pull（用户主动获取信息）和 Push（如发送 Email）模式。技术实现：使用 Spring 及 LinkedIn 专业的 Spring 插件完成，基于 HTTP-RPC。扩展技术（Scaling Techniques）功能划分：按发送、接收、文档等功能进行划分。类别划分：按用户信箱、访问者信箱等类别进行划分。等级划分：按用户 ID 等级、Email 等级等进行划分。异步处理：所有的操作均采用异步方式。参考资料LinkedIn Communication ArchitectureA Professional Network built with Java Technologies and Agile Practices原文地址：http://www.liyingfei.com/read.php/9.htm说明：本文内容主要基于 2008 年左右的技术分享资料，反映了 LinkedIn 早期的架构设计。随着技术发展，LinkedIn 后续已迁移至更多现代技术栈（如 Kafka、Rest.li、Cloud 云服务等），文中部分组件（如 Solaris、Oracle、内部 Cloud 缓存）可能已不再适用当前生产环境。

Twitter网站架构学习笔记
type: item
date: 2026-07-09T04:38:35+00:00
description: 编者注：本文为历史博文归档，主要反映 Twitter 早期（约 2011 年前后）的架构设计。文中涉及的 JDK、框架与工具链版本请以当前官方文档为准。部分引用外链图片可能失效，阅读时请注意时效性。Twitter 网站架构学习笔记作为 140 字符限制的缔造者，Twitter 既简单又复杂。简单在于，仅用 140 个字符便使数次世界性事件的传播速度超越了任何媒体；复杂在于，要为数亿用户提供这看似简单的服务，背后的架构挑战巨大。正所谓“因为简单，所以复杂”。本文将对 Twitter 网站架构的学习体会与大家分享。一、Twitter 网站基本情况概览截至 2011 年 4 月，Twitter 的注册用户约为 1.75 亿，并以每天 30 万的新用户注册数增长。但其真正的活跃用户远小于这个数目，大部分注册用户没有关注者或未关注他人，这也是其与 Facebook 当时 6 亿活跃用户不能相提并论的原因。主要运营数据如下：独立访问用户数：每月约 180 万，其中 75% 的流量来自 Twitter.com 以外的网站。API 请求：每天通过 API 产生约 30 亿次请求。Tweet 产生量：每天平均产生约 5500 万次 Tweet。用户终端：37% 的活跃用户为手机用户。来源分布：约 60% 的 Tweet 来自第三方应用。技术栈平台：Ruby on Rails、Erlang、MySQL、Mongrel、Munin、Nagios、Google Analytics、AWStats、Memcached下图是 Twitter 的整体架构设计图：二、Twitter 的平台组成Twitter 平台大致由 Twitter.com 官网、手机客户端以及第三方应用构成，如下图所示：其中，流量主要以手机和第三方应用为主要来源。以下是核心组件的技术选型与说明：Ruby on Rails：Web 应用程序框架。Erlang：通用的面向并发的编程语言。开源项目地址：http://www.erlang.org/AWStats：实时日志分析系统。开源项目地址：http://awstats.sourceforge.net/Memcached：分布式内存缓存组件。Starling：Ruby 开发的轻量级消息队列。Varnish：高性能开源 HTTP 加速器。Kestrel：Scala 编写的消息中间件。开源项目地址：http://github.com/robey/kestrelComet Server：Comet 是一种 Ajax 长连接技术，利用 Comet 可以实现服务器主动向 Web 浏览器推送数据，从而避免客户端轮询带来的性能损失。libmemcached：一个 Memcached 客户端库。MySQL：关系型数据库服务器。Mongrel：Ruby 的 HTTP 服务器，专门应用于 Rails。开源项目地址：http://rubyforge.org/projects/mongrel/Munin：服务端监控程序。项目地址：http://munin-monitoring.org/Nagios：网络监控系统。项目地址：http://www.nagios.org/三、缓存架构缓存在大型 Web 项目中起到了举足轻重的作用，毕竟数据越靠近 CPU 存取速度越快。下图是 Twitter 的缓存架构图：大量使用 Memcached 作缓存计数优化：例如，如果获得一个 count 非常慢，可以将 count 在 1 毫秒内写入 Memcached。朋友状态：获取朋友的状态涉及安全等复杂问题，因此朋友状态更新后直接写入缓存而不是查询数据库，避免接触数据库层。ActiveRecord 对象：由于对象很大所以没有被整体缓存。Twitter 将 critical 的属性存储在一个哈希（Hash）里，并且在访问时进行迟加载（Lazy Load）。API 请求缓存：90% 的请求为 API 请求，所以在前端不做任何 Page 和 Fragment 缓存。页面非常时间敏感，直接缓存效率不高，但 Twitter 缓存了 API 请求。Memcached 缓存策略改进在 Memcached 缓存策略中，Twitter 做了如下改进：直写式向量缓存（Vector Cache）：包含了一个 Tweet ID 的数组，Tweet ID 是序列化的 64 位整数，命中率是 99%。直写式行缓存（Row Cache）：包含了数据库记录（用户和 Tweets）。这一缓存有着 95% 的命中率。直读式碎片缓存（Fragment Cache）：包含了通过 API 客户端访问到的 Tweets 序列化版本，这些 Tweets 可以被打包成 JSON、XML 或者 Atom 格式，同样也有着 95% 的命中率…

新浪微博技术架构分析
type: item
date: 2026-07-09T04:37:50+00:00
description: 新浪微博技术架构分析新浪微博在短短一年时间内从零发展到五千万用户，我们的基础架构也经历了几个版本的演进。本文将从架构演进的角度，分析微博在不同发展阶段面临的技术挑战与解决方案。第一版架构：快速实现与推模式第一版架构的核心目标是快速实现模块功能。从架构层面分析，微博产品主要需要解决「发表」和「订阅」的问题。消息模式：第一版采用的是推（Push）模式。例如，一个明星用户拥有 10 万个粉丝，当他发表一条微博时，系统会将这条消息攒成 10 万份，分别推送给粉丝。技术栈：典型的 LAMP 架构。存储引擎：使用 MyISAM 存储引擎，其优点是读取速度非常快。部署模式：采用 MPSS 模式（多端口/进程部署）。关于部署模式的思考：假设一个互联网应用包含三个单元，通常有两种部署方式：分离部署：将三个单元分别部署在三台不同的服务器上。全量部署（MPSS）：将这三个单元部署在每一台服务器上。我们选择了第二种模式，主要解决了两个问题：负载均衡：每一个单元都有多个结点处理请求。防止单点故障：在模式一下，任何一个结点故障都会影响系统服务；而在模式二下，单个结点故障不会影响整体服务。第一版遇到的问题第一版上线后，用户增长迅速，但技术层面很快遇到了瓶颈：发表延迟：尤其是明星用户发表微博时，由于粉丝量大，推模式导致严重的延迟。资源争抢：处理明星用户发表时的延迟，可能会影响同一时间发表普通用户的体验。数据规模：数据库表从一百万增长到一亿，单库单表模式无法满足需求，需要进行拆分。锁表问题：高并发下出现锁表，考虑更改存储引擎。发表过慢：同步处理流程过长，考虑引入异步模式。第二版架构：模块化与异步优化针对上述问题，第二版架构进行了模块化拆分与异步化改造。1. 投递模式优化推模式是延迟的首要原因。我们将用户分为有效用户和无效用户：策略：如果一个用户有 100 个粉丝，发微博时不需要推给所有粉丝。例如，只推送给当天登录过的「有效粉丝」。效果：大幅减轻了推送压力，减小了投递延迟。2. 数据拆分与存储随着用户量增多，数据拆分势在必行。拆分维度：互联网产品常用 UID 拆分，但微博用户访问特点集中在「最近内容」。因此，我们按照时间拆分（例如一个月一张表）。内容与索引分离：索引数据：如微博发表地址。内容数据：采用 Key-Value 方式存储，易于扩展。分页定位问题：如果索引按月拆分，用户访问第 5 页时很难定位记录所在表。解决方案：在索引上建立二次索引。记录每个月用户发表的偏移量（ID 范围），从而迅速定位记录。3. 异步处理发表操作涉及入库、统计索引、进入后台等繁重步骤。优化：采用异步模式。前端提示发表成功后，后台通过消息队列慢慢处理索引统计。工具：使用了新浪开源的 MemcacheQ，其 stats queue 指令对大规模部署运维非常有利。架构演进驱动力：从 V2 到 V3第二版改进后，用户和访问量仍在持续增长，新的问题随之出现：系统稳定性：单点故障可能导致雪崩。访问速度：国内网络环境复杂，不同地区访问图片、JS 等资源速度差异大。数据压力与峰值：MySQL 复制延迟、慢查询；热门事件（如世界杯）可能导致每秒发表量达到数百条。平台化需求：开放平台需要支持 Web 系统与 API 系统。API 客户端请求具有不间断性，且用户行为难以预测。参考 Google 首席科学家的理念：「一个大的复杂系统，应该要分解成很多小的服务。」 例如在 Google.com 执行一个搜索查询，内部可能调动一百多个服务。因此，第三版架构的核心思路是：先有服务，才有接口，最后才有应用。第三版架构：服务化与多机房部署1. 分层架构基础服务层：分布式存储、去中心化、自动化操作。平台服务层：将微博常用功能封装成独立小服务。应用服务层：专门考虑平台各种应用的需求。API 层：支撑第三方应用。优势：平台服务与应用服务分离，实现模块隔离。即使应用服务访问量过大，也不会直接影响平台服务。2. 核心引擎改进关注关系：改为多维度索引结构，性能极大提高。计数器优化：旧版：绝对计数，容易产生一致性问题。新版：基于偏移（Offset） 思路。例如用户原读 ID 为 10000，系统最新 ID 为 10002，则未读数为 2。这种技术基本不会出错。3. 存储与部署DB 冷热分离与多维度拆分：微博主业务按时间拆分，但如私信等业务按 UID 拆分更简单。去中心化存储：极大提高用户上传与查看图片的速度。多 IDC 动态内容更新：支持动态内容在多机房同时更新，这是国内比较新颖的实践。高性能与高可用设计目前新浪微博拥有五千万用户，最高发表速率超过 3000 条/秒，明星用户微博会被几百万用户同时读取。架构设计需解决高访问量、海量数据下的三个核心问题：易于扩展、低延迟、高可用与异地分布。1. 扩展性设计面对数十亿次外部网页及 AP…

订单表的分库分表方案设计(大数据.html)
type: item
date: 2026-07-09T04:37:17+00:00
description: 订单表的分库分表方案设计在业界的大数据场景下，订单表的分库分表（Sharding）设计通常主要有两类思路：按照订单号切分或按照用户 ID 切分。以下是对这两种方案的详细分析、优缺点对比以及常见问题的解决方案。主流分库分表方案方案一：按照订单号 Hash 分散该方案将订单号视为字符串，通过 Hash 算法将数据分散到多个数据库服务器中。路由规则：具体存储到哪个库、哪张表，通常由订单号中的数字特征决定。典型案例：例如微信红包的订单分库分表，是对订单号进行 Hash 计算（非简单的取模或取整），以实现数据的均匀分散。订单号末尾的 3 位数字往往包含了库名和表名的信息。查询挑战：如果需要查询某用户的所有订单，由于数据是根据订单号分散的，该用户的订单可能分布在多个库、多张表中。若全库全表扫描，效率极低。对比：即便是按照用户 ID（UID）切分，查询特定订单号时也会面临类似问题（不知道数据在哪个库）。方案二：按照用户 ID 分散以用户 ID（UID）作为切分键，业界使用较为普遍。主要有两种思路：范围切分：例如 0-2000 万 UID 对应库 A，2000 万 -4000 万 UID 对应库 B。缺点：容易出现数据热点。若某个范围内的用户下单量特别大，会导致对应库压力过高，而其他库闲置。取模运算（推荐）：使用 UID % N 的方式。优点：处理简单，数据能均匀分散到多个库，不易出现单库性能瓶颈。缺点：扩容麻烦。扩容通常需要进行数据迁移。扩容策略：为了减少迁移量，一般以倍数形式增加库数量（例如从 8 库扩容到 16 库，再到 32 库）。这种方式虽不能彻底避免迁移，但能显著减少迁移数据量，且一次扩容可支撑较长时间的业务增长。基于用户 ID 分片的详细设计以下以“按照用户 ID 取模”为例，分析具体的库表定位规则。1. 路由算法逻辑假设使用用户 ID 末尾 4 位数字进行计算：库名称定位：用户 ID 末尾 4 位 % 32Mod 表示取余数。例如 15 % 4 = 3。余数范围 0-31，对应 32 个数据库实例。库名示例：order_db_0 至 order_db_31。表名称定位：(用户 ID 末尾 4 位 / 32.html) % 32Dev 表示取整数商（向下取整）。例如 15 / 4 = 3.75，取整为 3。代码表示：floor(15/4.html)。表名示例：order_tb_0 至 order_tb_31。每个库内包含 32 张表。2. 容量估算按照上述规则：32 个库 * 32 张表 = 1024 张表。若单表数据量控制在 1000 万至 5000 万行，理论上可支撑海量数据。若希望表数量更少，可调整取模的基数（如将 32 改小）。查询场景与挑战方案一的查询问题若按照订单号分散数据，查询某用户的所有订单时，必须进行跨库、跨表查询，效率低下，通常不可行。方案二的查询问题若按照用户 ID 分散数据，虽然查询用户订单列表很方便，但在实际应用中会面临以下高频查询需求：按订单号查询：前台或后台输入订单号查询详情（Select）。按订单号更新：修改订单状态（Update）。由于数据是按用户 ID 分散的，仅凭订单号无法直接定位到具体的库和表。若全库扫描，性能无法接受。解决方案：建立索引映射表没有一种技术方案是十全十美的。针对“按用户 ID 分片后无法通过订单号查询”的问题，常见的解决思路是建立订单号与用户 ID 的索引关系表。1. 核心思路映射表设计：建立一张 order_user_idx 表，存储两项核心数据：订单号 、 用户 ID。查询流程：输入订单号，查询索引表获取用户 ID。根据用户 ID 利用路由算法定位到具体的库和表。查询订单详情。写入流程：创建订单时，需同步插入关系记录。为降低用户等待时间，该操作可异步化（如加入消息队列处理）。2. 索引表的性能优化随着时间推移，一个用户的订单量可能达到几百甚至更多，索引表本身也可能成为瓶颈。索引表分片：order_user_idx 表本身也需要分库分表。建议直接根据订单号取模进行分片。缓存策略：订单与用户的绑定关系创建后通常不会变更。可将该关系表放入内存缓存（如 Redis）。查询时优先走缓存，未命中再查数据库，以提升速度。复杂业务场景思考思考一：B2B 平台的分片键选择在 B2C 平台，卖家通常是平台自身。但在 B2B 平台，买家和卖家均需查看订单。按买家 ID 分片：卖家查询自己的所有订单时，因商品被多个买家购买，订单分散在不同库表，导致跨库查询性能低下。按卖家 ID 分片：买家在多个店铺下单，订单同样分散，买家查询自身订单时性能低下。行业实践（如淘宝）：采用数据冗余方案，拆分买家库和卖家库。买家库：按买家 ID 分库分表。卖家库：按卖家 ID 分库分表。同步机制：下单时写两份数据。…

再谈最终一致
type: item
date: 2026-07-09T04:37:03+00:00
description: 再谈最终一致构建全球可靠的分布式系统，往往需要在一致性与可用性之间进行权衡。2008 年，亚马逊公司（Amazon）的 CTO Werner Vogels 发表了一篇文章，描述了在大型分布式系统中容忍最终数据一致性的方法。正如 InfoQ 之前的一篇新闻 里所讨论的：系统架构师角色关键的一方面就是衡量相互冲突的需求、决定解决方案，常常要牺牲一个方面来换取另一个方面。Werner Vogels 发布的新 帖子 讨论了这些基本需求如何应用于基础设施服务，为构建 Internet 范围的计算平台提供资源。鉴于这些系统分布在世界范围内，我们处处利用复制技术来保证稳定的性能和高可用性。尽管复制技术使我们达到部分目的，但它的实现并不是完全透明的；在许多情况下，在服务内部使用复制技术都会给服务的客户带来后果。后果之一体现为对数据一致性的限制，特别是在底层分布式系统提供了一种最终一致的数据复制模型的时候。在亚马逊设计这些大型系统时，我们凭借一套有关大规模数据复制的指导原则和抽象，把注意力集中于高可用性和数据一致性之间的权衡选择。一致性的两种视角按照 Werner 所说，考虑一致性有两种方式：一种是从开发者 / 客户端的角度——他们如何观察数据更新；第二种是从服务器的角度——更新如何流经整个系统，系统对更新有何保证。客户端一致性模型在定义客户端一致性模型时，应该考虑以下内容：存储系统：它在本质上是大规模且高度分布的系统，其创建目的是为了保证耐用性和可用性。进程 A：对存储系统进行读写。进程 B 和 C：这两个进程完全独立于进程 A，也读写存储系统。客户端一致性必须处理一个观察者（在此即进程 A、B 或 C）如何以及何时看到存储系统中的一个数据对象被更新。强一致性（Strong Consistency）：在更新完成后，（A、B 或 C 进行的）任何后续访问都将返回更新过的值。弱一致性（Weak Consistency）：系统不保证后续访问将返回更新过的值，在那之前要先满足若干条件。从更新到保证任一观察者看到更新值的时刻之间的这段时间被称为不一致窗口。最终一致性（Eventual Consistency）：这是弱一致性的一种特殊形式；存储系统保证如果对象没有新的更新，最终所有访问都将返回最后更新的值。如果没有发生故障，不一致窗口的最大值可以根据下列因素确定：比如通信延迟、系统负载、复制方案涉及的副本数量。客户端一致性模型的变体因果一致性（Causal Consistency）：如果进程 A 通知进程 B 它已更新了一个数据项，那么进程 B 的后续访问将返回更新后的值，且一次写入将保证取代前一次写入。与进程 A 无因果关系的进程 C 的访问遵守一般的最终一致性规则。“读己之所写”一致性（Read-your-writes Consistency）：这是一个重要的模型。当进程 A 自己更新一个数据项之后，它总是访问到更新过的值，绝不会看到旧值。这是因果一致性模型的一个特例。会话一致性（Session Consistency）：这是上一个模型的实用版本，它把访问存储系统的进程放到会话的上下文中。只要会话还存在，系统就保证“读己之所写”一致性；系统的保证也不会延续到新的会话。单调读一致性（Monotonic Read Consistency）：如果进程已经看到过数据对象的某个值，那么任何后续访问都不会返回在那个值之前的值。单调写一致性（Monotonic Write Consistency）：系统保证来自同一个进程的写操作顺序执行。要是系统不能保证这种程度的一致性，就非常难以编程了。服务器端一致性与改进服务器端的一致性水平取决于如何在数据副本之间传播更新（这是改善吞吐量、提供可伸缩性的典型方式）。只有部分数据副本参与更新操作，且/或作为读操作的一部分与其它副本进行联系时，就会出现弱/最终一致性。发生这种情况的两种常见场景分别是为读伸缩而做大量复制的情况和有复杂数据访问的情况。在大多数这样的系统中，更新以一种“懒”方式传播到副本集内的其它节点上。所有副本都完成更新前的这段时间就是不一致窗口，读取尚未接收到更新的节点是整个系统的薄弱环节。服务器提供的一致性水平可以通过客户端/服务器通信的特定实现来改进，或者由客户端自己来完成：“读己之所写”一致性、会话一致性和单调一致性是否可以达成，取决于客户端对为其执行分布式协议的服务器的“粘度”。如果每次都是同一台服务器，那么就比较容易保证“读己之所写”一致性和单调一致性。这样做会使管理负载平衡以及容错变得稍困难一些，但这是一种简单的方案…… 客户端有时会实现“读己之所写”一致性和单调读一致性。通过给写入添加版本，对那些版本早于最后版本的值来说，客户端会丢弃这些值的读出。结语每个客户端应用对服务器造成的不一致性都有自己的耐受…

Java开源建站工具
type: item
date: 2026-07-09T04:36:07+00:00
description: Java 开源建站工具美国程序员 Jon Scott Stevens 曾公布过其创业公司所使用的开发工具清单。他的技术栈基于 Java 平台，开发项目为一个尚未上线的网站，所列工具均为开源免费软件。在创业者群体中，选择 Java 作为网站开发语言的情况似乎并不多见。这并非没有原因：Java 给人的印象往往是配置繁琐、开发效率不如脚本语言便捷。但不可否认的是，Java 平台生态成熟，拥有丰富的工具包与类库，JVM 虚拟机技术亦十分先进。此外，Google App Engine 平台当时提供免费的 Java 主机服务，这使得使用 Java 建站成为一种合理的选择。笔者将他的工具清单整理如下，供日后参考。一、开发平台Google App Engine：Google 的主机服务，提供数据库支持。使用它无需自行架设服务器，并能轻松解决扩展性问题。Objectify-AppEngine：GAE 平台的数据库管理工具。GitHub：代码托管服务。二、Java 编程环境Eclipse：著名的 Java 集成开发环境（IDE）。Lombok：Eclipse 插件，用于自动生成 Java 代码，减少手工输入量。Guice：轻量级的 Java 依赖注入（Dependency Injection）框架。Apache Commons：Java 开发常用工具包。Guava：Google 发布的 Java 工具库。JRebel：允许立即查看 Java 代码修改后的执行结果，无需重启服务。Cambridge Template Engine：为 Java 应用程序提供 HTML/XML 模板引擎。RestEasy：Java 语言的 RESTful 编程框架。HtmlEasy：基于 RestEasy 的 HTML MVC 模式编程框架。三、前端工具RequireJS：对 JavaScript 进行模块化管理并按需加载的框架。JQuery：强大易用的 JavaScript 编程框架。CoffeeScript：对 JavaScript 进行改写，使其更易于开发的脚本语言。Sass Scss：CSS 代码生成工具。说明：本文整理自 2011 年左右的技术分享。文中部分链接（如 Google Code 相关项目）可能已失效或迁移，Google App Engine 对 Java 的支持策略也已发生变化。请参考时注意工具的适用版本与时效性。

低代码编程及其市场机遇剖析 | 低代码技术内幕
type: item
date: 2026-07-09T04:36:06+00:00
description: 自 2020 年来，网易数帆探索可视化低代码编程已两年有余，打造了轻舟低代码平台用于企业应用开发。然而，不少编程技术人员对这一领域还比较陌生。我们开设 《低代码技术内幕》专栏，旨在讨论低代码编程领域中的困难、问题，以及高效的解决方案。本文为第一篇，深度剖析低代码编程带来的机遇。类比早期人类语言，最初只有“听说”系统，后因国家税收之需演化出了“读写”系统。相较于“听说”，“读写”具有易于复制传播、歧义少、保存持久等优点。类似地，早期用于人机交流的程序语言只有“字符”系统，现在因特定诉求，市场上涌现出一批“可视化低代码”系统。什么是低代码？它有哪些优势？我们为什么要学习并使用它？低代码未来的市场是怎样的？ 本文重点描述低代码未来 5~10 年的广阔市场，但仍将循序渐进，从概述低代码编程的历史发展开始。（想要了解市场规模和前景的读者，可直接跳转至「低代码的市场和机遇」部分）低代码定义：发展与变迁提高生产效率是人类永恒的主题。正因此，我们认为广义的低代码编程，取其字面意思，应当是指在某个时间段内，完成项目所需的代码量（大幅）低于其他语言（平均值）的编程模式。无独有偶，我们的认知与 ITPro Today 相合 [1]：文中描述 Fortran 和 COBOL 在 1950 年代刚出现时，它们作为高级编程语言的始祖，是那个年代里不折不扣的低代码编程语言——即便现在大多数编程人员已经不这么认为。文章 [1] 还表示，1987 年苹果公司开发的 HyperCard 编程语言（尽管不为大多数人所知）是低代码发展中的一个里程碑。HyperCard 融合了一套图形化、可扩展、可编辑的接口和数据库功能，它的部分设计理念与微软的 Visual Basic 相似，但早于后者 4 年发布。图 1：HyperCard 图标。图片来源：维基百科。图 2：HyperCard 界面。图片来源：OSXDaily。1990 年代，随着第四代编程语言（SQL、MATLAB、Clipper 等）的发展与成熟，以及高效的应用程序开发工具如 Visual Studio、Delphi 等的横空出世，UML + 设计器 + MDD 红极一时。模型驱动设计、自动代码生成和可视化开发思想成为了当年低代码开发的核心 [2]。直到这时为止，低代码的核心诉求都是提高专业开发人员的开发效率。图 3：UML 设计图2010 年代，低代码的核心诉求发生剧烈变化，开始向"让业务专家将自己的专业知识和经验落地成在线应用"转移 [2]。很多公司没有经费聘用专业的开发人员，因此希望业务专家经过一定的培训也可以上手开发应用。这些应用很大一部分是用于市场营销、销售的，也比较同质化，容易从统一的模板中搭建出。由此，便有了我们所熟知的在当前时代背景下的（狭义）低代码编程。国际上最具有影响力和代表性的产品有 OutSystems、Mendix、MicroSoft Power Apps 等，这些产品具有以下特点 [3]：为让非专业编码人员易于使用，配备了完善的可视化开发框架。不仅提供可视化开发前端、UI 的能力，还提供可视化开发复杂逻辑的能力：无需记忆编程语言的语法，通过拖拽和点击即可实现业务功能。提供完整的前后端、数据库、部署、运维等解决方案，屏蔽了前端（HTML、JS、Vue / React 等）、后端（NodeJs 或 Java + SpringBoot 等）、数据库（SQL 或 MongoDB 等）、云服务等技术，无需配置，即开即用。图 4：OutSystems 可视化逻辑。图片来源：轻舟低代码团队为什么要做编程语言？图 5：轻舟低代码可视化逻辑。图片来源：轻舟低代码团队为什么要做编程语言？了解了低代码的大致历史后，我们便知道它并不是先有定义再发展起来的事物 [2]：它的定义随着时代发展而变化，以反应当前时代市场的诉求。因此，我们不妨援引西门子 Mendix 的定义来概述 21 世纪 20 年代的低代码：低代码开发是一种可视化应用开发方法。通过低代码开发，不同经验水平的开发人员能够通过图形用户界面，使用拖放式组件和模型驱动逻辑来创建 Web 和移动应用。了解了低代码的概念后，我们来看看低代码在未来 5~10 年的广阔市场。低代码的市场和机遇本章我们先讨论低代码这一新兴技术在全球的发展，再描绘其在中国特定时代背景下（更大）的前景。全球的发展在低代码领域，目前海外大约活跃着六十七家供应商，而且它的生态系统正在迅速成长。2017 年是一个分界点，在大型软件供应商中，2017 年之前只有 Salesforce 采用 Force.com 的低代码平台。随后，微软、甲骨文、IBM 和 SAP 等企业都纷纷加入了这个市场，低代码（含无代码）市场呈爆发式增长：2020 年市场规模达到 108.2 亿美元 [4]。2021…