自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

Sam_Deep_Thinking

努力深入思考和总结

  • 博客(549)
  • 资源 (1)
  • 问答 (12)
  • 收藏
  • 关注

原创 MySQL join了十几张表,有哪些优化思路?

1.原则:OLTP(交易)与 OLAP(分析)是要分离的。复杂的统计台账不该由核心交易库去承担;2.短期(SQL级):分离筛选与抓取。使用延迟关联,先瘦身 Join 拿 ID,再回表取详情;3.中期(字段冗余):将高频的跨表筛选字段(如城市、状态)冗余到主表,消除 Join。4.长期(架构级):引入搜索引擎(ES)。将多表关系转化为文档宽表,彻底解决任意维度检索和深分页问题。你自己心里一定要有个谱,mysql这种关系型数据库,就是存在局限性的,必要的时候,的确是需要做【架构级别】的优化的。

2026-06-17 09:45:57 242

原创 手机号被运营商回收并分配给另一个人,用户会员数据如何处理?

A的积分、等级、自由卡、优惠券全部保留,B的新微信就对应了A的全套数据。B看到展示的老账号头像、昵称、历史记录,发现根本不是自己的,选这个选项。系统做两件事:把111从A的账号上解绑(A的手机号字段被清空),然后给B创建全新主账号并把111绑上去。系统拿到111去查,发现这个号码已经关联了老用户A的主账号,于是判定为「账号冲突」。A的账号不会丢失,积分、等级、资产全部还在,只是变成了一个没有绑定手机号的账号。111这个手机号码,原本是属于A的,后面号码不用了,运营商回收复用,分配给用户B了。

2026-06-15 15:06:21 272

原创 疫情期间,CTO让我三周时间上线一个子品牌所有需求

提醒」:是付费专栏,但是在知识星球里是免费的。目前星球里已更新了6个专栏:「支撑6000万会员的秒杀系统实战」、「几亿用户,百万并发的C端商品系统实战」、「DDD领域驱动设计三年落地实战」、「应付亿级用户规模的支付系统代码实战」、「应付亿级用户的会员体系代码实战」和「我的项目管理实战手记:10个真实主导项目,还原实战现场」,后续的订单,结算和购物车以及用户和营销专栏等,星球内也都是免费的。当时,公司的业务发展迅猛,CEO想用子品牌的方式,到下沉市场去试试水。

2026-06-14 20:04:24 188

原创 java中的class到底是个什么东西?

读到这里的时候,你就应该能意识到:编译之后,运行时还能保留多少。

2026-06-11 10:49:52 441

原创 程序员还是要注重代码复用的

我这边的自研系统需要对接低代码平台,日常做得最多的事情就是往低代码平台的表格里更新记录或者新增记录。看起来就两个操作,但对接低代码平台的OpenAPI,要处理的细节不少:构造请求、设置参数、调用网关、解析响应。早期做对接的时候,我把更新和新增这两个操作各封装了一个通用方法,后面不管哪个业务场景需要同步数据到低代码平台,调用方一两行代码就搞定了。这次从这两个方法出发,来聊聊代码复用这件事。

2026-06-11 09:43:30 204

原创 Spring Boot 的启动原理是什么?

Spring Boot 复杂的启动流程中,最终的目的就是为了启动一个 Spring 的。这里一定要理解好,Spring Boot底层也是基于Spring的,因此你可以简单如下理解:Spring Boot本质上只是帮你准备好一切,最终真正干活的,还是Spring Framework。最终就是想通过调用Spring中ApplicationContext的refresh方法,将Spring容器彻底激活。好,到了这里,可以用最简洁的语言来描述Spring Boot的启动流程了。构建 Environment;

2026-06-10 11:32:04 436

原创 我们当年是如何真实落地BFF的?

一听到BFF,你是不是会有一连串的疑问?下面我就说一下,我们当年具体是如何落地BFF的。在开始之前,我想说一句,任何技术架构,一定要根据自己的团队的实际情况和公司业务情况来,切记。不要说,看到网络上某些文章,头脑一热,就开始要兴致勃勃的去实践了。还美其名曰,按照标准来。

2026-06-10 11:00:21 487

原创 SpringData JPA也能写sql,为什么还要用mybatis?

因为在中大型系统里,比重要的多。MyBatis 的核心价值不是,而是它在:开发效率、SQL可控、性能底线,给了一个。我们作为程序员,日常在做技术架构设计时,也是一个寻找最佳平衡的过程,很少有绝对完美的解决方案的,选择最佳平衡最合适当前实际情况的就可以了。网络上也有部分人拿来反驳:那 JPA 不就同时拥有便利 + SQL 灵活了吗?尤其当你的系统进入“数据量大、查询复杂、DBA开始介入治理”的阶段。

2026-06-09 13:02:14 225

原创 第2篇:用户会员体系需求PRD-CEO工程来的

提醒」:是付费专栏,但是在知识星球里是免费的。目前星球里已更新了5个专栏:「支撑6000万会员的秒杀系统实战」、「几亿用户,百万并发的C端商品系统实战」、「DDD领域驱动设计三年落地实战」、「应付亿级用户规模的支付系统代码实战」和「应付亿级用户的会员体系代码实战」,后续的订单,结算和购物车以及用户和营销专栏等,星球内也都是免费的。上一篇说了专栏要讲什么,从这篇开始进入具体需求。写代码之前先搞清楚业务层面的问题:用户会员体系为什么做,覆盖哪些功能,优先级怎么排,业务规则是什么。

2026-06-09 09:46:11 953

原创 抽象类与接口的选择标准

在JAVA 8出来之后,两者的选择标准有了一些变化了。因为接口里可以定义default方法,可以去掉很多的抽象类了。这块我后面会讲到,我们还是先给出两者的选择标准吧:接口定义「能力契约」,抽象类提供「骨架实现」。两者怎么选,就看:多个实现之间需不需要共享「状态和通用逻辑」。需要,用抽象类。不需要,用接口。。另外实际工程中,两者经常配合使用,不是非此即彼的关系。JDK集合框架和Spring这类成熟框架都是这么干的。

2026-06-08 13:44:22 344

原创 第1篇:应付亿级用户的会员体系代码实战-开篇词

提醒」:是付费专栏,但是在知识星球里是免费的。目前星球里已更新了5个专栏:「支撑6000万会员的秒杀系统实战」、「几亿用户,百万并发的C端商品系统实战」、「DDD领域驱动设计三年落地实战」、「应付亿级用户规模的支付系统代码实战」和「应付亿级用户的会员体系代码实战」,后续的订单,结算和购物车以及用户和营销专栏等,星球内也都是免费的。C端产品做到一定体量,用户体系就是绕不过去的,必须应付的。不是简单的增删改查,不是一张用户表就能搞定的事。

2026-06-08 13:21:17 421

原创 结算分摊的策略模式:不同营销活动的扣点计算方案

电商平台的结算模块有一件事非做不可:搞清楚每一笔订单里,平台和商家各拿多少钱。听起来不太复杂,但是,有了营销活动后,就变得复杂起来了。一个订单如果参加了拼团活动,平台要按拼团的分摊比例和扣点来算;如果是秒杀订单,又得按秒杀的活动价和扣点来算;满减活动则只有营销扣点,没有分摊比例这回事。每种活动的结算参数来源不同、校验规则不同、计算方式也不同。如果你在结算服务里用一长串if-else来处理这些差异,每新增一种活动类型就得改这个核心方法,改一次冒一次回归风险。结算中心是怎么处理这个问题的?用策略模式。

2026-06-05 17:04:48 427

原创 基于DTS的数据库变更订阅实战:从binlog到业务事件

做电商系统的人大概都遇到过这个问题:商品价格改了,库存降了,上下架状态变了,下游的搜索引擎、推荐系统、购物车缓存怎么第一时间知道?最常见的做法是改完数据库之后,在业务代码里主动发个消息通知下游,但是有一个小的隐患:一旦某次改动忘了发消息,或者有个紧急的数据修正直接改了数据库,下游就彻底不知道发生了什么。还有一种做法是定时轮询数据库,每隔几秒查一次。小规模还行,数据量一大,轮询本身就是个负担,而且延迟也控制不好,查得太频繁拖垮数据库,查得太慢业务受不了。

2026-06-05 14:11:41 767

原创 SaaS多租户业务差异化:扩展点机制的设计与实现

SaaS系统做多租户,业务差异化是最绕不开的问题。同样一个价格计算,A租户走阶梯价,B租户走一口价,C租户要叠加会员折扣。同样一个订单校验,有的租户要校验库存,有的不需要。这类差异如果用if-else堆,代码很快就没法看了。如果用继承体系,每个租户一个子类,类的数量会随租户数线性增长,而且租户之间的差异往往不是整块替换,而是某个小环节不同,继承粒度对不上。我们可以用扩展点机制,来专门解决这类问题。我诺干年前在一个实际生产项目里用过,代码量不大,设计还是蛮精巧的,值得拿出来聊聊。

2026-06-04 19:15:26 266

原创 只能告诉你我们当年是怎么做的,但是它未必是对的

因此吃多太多次亏了,也遇到过太多次大故障了,深深的知道,系统稳定性的问题,是可以从架构设计了,进行增强的。我们的注册用户数当时是「一个亿」,每天要支付的订单平均是50万笔,你想想,多大的损失?它贵在真实,比如前不久发布的「发票中心架构设计」一文,就是当年吃够了订单开发票的苦,然后重构后得到收益了,然后才写出来的。尤其是我,因为之前都是带技术团队,负责核心业务系统的,且目前还管着整个技术部,责任重大,知道架构设计的重要性。有问题的,找知心的Sam哥,支持无限次语音一对一解决你遇到的难题。你会成长的非常快的。

2026-06-04 09:41:33 271

原创 发票中心架构设计

做技术架构之前,得先把业务和用户场景搞清楚。发票这块业务,不看用户怎么用、不看有哪些关键用例,上来就画架构图,画出来的东西大概率和业务对不上。这篇文章的写作思路是:先说清楚需求是什么、用户怎么用发票,再聊领域知识,最后才是架构设计。

2026-06-03 19:06:06 608

原创 聊聊Java中的of

of,两个字母,可能是Java生态里出现频率最高的静态工厂方法命名。从JDK到Spring到业务代码,of无处不在:Optional.of()、LocalDate.of()、Stream.of()、List.of()……翻开任何一个稍具规模的Java项目,of方法的数量可能比你想的多得多。这篇文章尝试把of这个命名的前世今生聊一聊:它从哪来、JDK里怎么用的、开源框架怎么用的、我自己写的业务代码怎么用的,以及什么时候该用of、什么时候不该用。

2026-06-02 13:13:07 297

原创 一个业务场景只需要一个ThreadLocal实例

很多人用了很久ThreadLocal,却没仔细想过一件事:同一个业务场景下,只需要声明一个ThreadLocal实例,几十上百个线程同时跑,全都共用这一个对象,没有任何线程安全问题。为啥?这个特性有点反直觉。通常我们说「多线程共享同一个对象」,第一反应是加锁、同步。但ThreadLocal完全不需要,每个线程只能看到自己的,互不干扰。为什么能做到这一点,值得看一下。

2026-06-01 16:04:33 554

原创 我84年出生,今年42了,发点感悟

然后你就会开始研究,用户需求,用户体验,流程,价值,交付,选品,售后,营销,沟通,表达,责任承担,流量,转化,搞活动呀,性价比,成本,视频,参考对比,研究优秀产品的特征,撰写好的文案等等东西。至于公司的产品,是怎么卖出去的,遇到了什么困难,当时是解决了什么问题,用户为啥会投诉和退款,可能是一无所知的或者知道的很少很少。而一旦你开始经营一个产品时,真的,你开始会懂很多很多的东西,因为你似乎会接触到社会的真实模式。因此,软启动还是蛮重要的,刚开始用副业的方式,尝试售卖产品,绝对值得一试。然后再慢慢调整策略。

2026-06-01 12:04:58 291

原创 有故障,为什么不能隐瞒

曾经有个从腾讯过来的总监,遇到我们在故障同步上慢了一些,她在群里说了一句话:「同步要快,故障隐瞒不了的。实际上,同步这件事耗时很短,而上级提前知道情况,可以帮你协调资源、准备对外口径、处理用户侧的反馈,这些都是在你埋头处理时顾不上的事。出了问题,第一反应是先处理,处理好了再说,或者干脆觉得影响不大,就不说了。分级的目的是让不同的故障触发匹配的处理机制,避免小故障走大流程浪费资源,大故障走小流程响应不够。开发者只能看到系统侧的指标,看不到用户侧的感知、业务侧的损失,更看不到管理层在外部承受的压力。

2026-05-29 11:20:44 254

原创 第2篇:应付亿级用户-支付系统需求PRD

提醒」:是付费专栏,但是在知识星球里是免费的。目前星球里已更新了「几亿用户,百万并发的C端商品系统实战」、「DDD领域驱动设计三年落地实战」和「应付亿级用户规模的支付系统代码实战」,后续的订单,支付,结算和购物车专栏,星球内也都是免费的。在写任何一行代码之前,先把需求理清楚。支付系统不像大多数人想的只是一个微信支付对接层,它要应付的是一个多终端、多渠道、多支付方式组合在一起的复杂收银体系。每个需求点如果一开始没想清楚,落到架构上就是会返工,也就影响了效率。

2026-05-24 12:36:50 844

原创 第1篇:应付亿级用户规模的支付系统代码实战-开篇词

提醒」:是付费专栏,但是在知识星球里是免费的。目前星球里已更新了「几亿用户,百万并发的C端商品系统实战」、「DDD领域驱动设计三年落地实战」和「应付亿级用户规模的支付系统代码实战」,后续的订单,支付,结算和购物车专栏,星球内也都是免费的。有一天晚上接近12点,订单系统的同事在群里发了一条消息:今天有几笔自由卡订单状态不对劲,订单上写着已支付,但支付系统里查不到对应的支付流水。排查的结果让人背后发凉。有人通过技术手段伪造自由卡支付回调的请求格式,自己构造了参数,直接调了订单系统的回调接口。

2026-05-22 20:16:29 760

原创 面试官问Bean线程安全,你该从架构角度回答

Bean线程安全这个问题,我们今天从架构职责划分的角度尝试来讲一下。

2026-05-22 11:20:47 518

原创 Java中wait为什么需要先拿到锁

线程A先拿到锁,检查条件,发现为空,调用wait。由于wait在释放锁之前不会把线程真正挂起,线程B就算想修改条件,也得先等线程A把锁释放出来。就在它准备调用wait的那一瞬间,线程B往队列里塞了一条数据,并且执行了notify。真正理解这个问题的关键,是意识到wait方法内部做的第一件事不是阻塞自己,而是释放锁。用notifyAll而不用notify,是为了避免在多个线程等待不同条件时,把错误的线程唤醒。比如一个线程从队列里取数据,发现队列空了,于是调用wait,等别的线程往队列里放了数据再唤醒它。

2026-05-21 10:02:33 574

原创 连锁餐饮外卖配送调度系统的架构设计

连锁餐饮做外卖,要考虑的一个问题是,哪个平台的骑手可以帮忙送。美团、饿了么这类平台自带运力,用它们的单子就用它们的骑手。但自营渠道(自研小程序、APP)的外卖单就没有现成的骑手,自研的系统得自己对接第三方配送平台。几十家店还好说,配置一个平台应付过去。上千家门店分布在十几个城市,问题就来了:顺丰在深圳覆盖好,但去了广州就不一定;达达在部分城市有运力,京东众包在另一些城市可能更好。另外还有一个很核心的问题:价格。不是每次城市都需要用那么贵的配送方的。因此不太可能在所有城市都只用一家。

2026-05-21 00:25:55 453

原创 连锁门店的外卖订单平台对接

这篇文章简单讨论一下连锁门店的外卖平台订单接入方案。美团、抖音、京东到家这些平台的订单,统一由service-take-away来接收,验签、解析、入库、同步主订单,都在这个服务里完成。把这个服务独立出来,而不是写进订单模块,原因很简单。每个平台的回调字段、签名算法、状态定义都不一样,它们的SDK升级、API变更、协议调整,都不受你控制。每次外部变化都改订单主服务,风险太高。订单主域只和内部接口打交道,外部变化由service-take-away隔离在外面。

2026-05-20 09:25:27 553

原创 支付中心设计

部分团队在做支付系统时,会把所有支付渠道塞进一个微服务里。微信、支付宝、钱包,全部用if-else或策略模式在同一个进程内切换。这在业务初期没什么问题,但当你的业务跨了国家、跨了币种、对接了七八个支付品牌时,这种做法的代价会越来越大。一个渠道的SDK升级,可能影响到所有渠道的稳定性。一个渠道的流量激增,会拖慢整个支付服务的响应。。整个支付中心由9个微服务组成,覆盖国内的微信、支付宝,海外多个地区的聚合支付平台,以及内部的钱包账户体系和自由卡支付。

2026-05-18 20:26:41 548

原创 第15篇:百万并发商品系统-完结篇

14篇写完,整个专栏到这里结束。从需求背景到技术设计,从数据迁移到缓存体系,从上线保障到大促隔离,一个完整的C端商品系统就是这样搭起来的。

2026-05-17 20:56:43 272

原创 营销系统pms架构设计实战

这样保证分摊总额严格等于优惠总额,误差集中在最后一件商品上(通常只差1分钱,业务可接受)。这个做法看起来简单,但如果一开始没考虑到,上线后发现对账差了几分钱,排查起来非常痛苦。

2026-05-15 12:37:07 694

原创 拼单功能的设计实战

今天我们说一下拼单功能的设计实现。支付模型采用发起人统一支付,支付完成后通过群收款向参与者收取各自的费用。

2026-05-14 11:51:18 733

原创 DDD领域驱动设计三年落地实战-开篇词

提醒」:是付费专栏,但是在知识星球里是免费的。目前星球里已更新了「几亿用户,百万并发的C端商品系统实战」和「DDD领域驱动设计三年落地实战」,后续的订单,支付,结算和购物车专栏,星球内也都是免费的。

2026-05-12 13:31:09 799

原创 千万级用户购物车系统的架构设计

我们当时搞的购物车服务,其实还是有点庞大的,看似是一个简单的CRUD,但是当你真正去实现一个购物车的时候,发现压根不是那回事。当商品类型从单一SKU扩展到普通商品、套餐组合、活动商品,拼单等混合的时候,一次加购操作从校验库存、加载促销规则、计算包装费、调用结算中心到最后持久化,涉及十几个步骤,有的能并行有的必须串行,有的允许失败有的必须成功。把这些逻辑全堆在一个Service方法里,维护性不好。

2026-05-12 10:22:45 639

原创 写代码不考虑前后兼容,迟早要还的

上周组里一个同事刚上线一个合同审批系统的改动,OA流程里签署方式的下拉框从原来的两个选项改成了三个。代码跟着做了调整,只处理新选项的值。上线当天下午,几个审批单全部处理失败,日志里都是枚举匹配不上的异常。排查了一下就定位原因了:那些审批单是上线之前提交的,走的还是旧流程,表单里填的还是旧选项值。新代码只认识新值,旧值到了代码里直接走进了异常分支。问题不在于写错了逻辑,而在于写代码的时候脑子里只有一个假设:用户提交的一定是新值。这个假设在代码上线的那一刻就不成立,因为系统里已经有一批旧数据正在流转中。

2026-05-11 13:49:47 360

原创 你认为从0-1开发一个项目最难的地方是什么?

你千万不要急着动手撸代码,想到一个写一个,这种从0到1的项目,系统和模块划分是最重要的,不然效率无从谈起。但凡快到关键节点了,就去问团队的同事的进度情况,有问题的,赶紧给与指导。如果公司有产品经理和懂业务的人,一定要多去沟通,沟通的东西就一样:核心流程如何流转,会经过什么节点。有问题的,找知心的Sam哥,支持无限次语音一对一解决你遇到的难题。你只有一开始这么做,才能来谈所谓的效率,你都没有拆分清楚,大家就都跟一头雾水一样的。注意,你不能花太多时间在项目管理这块的,毕竟你自己也是有很多的代码开发工作要做的。

2026-05-11 09:24:57 371

原创 所有的框架源码,最怕的就是被debug

知乎上有个问题:学编程是理解就行呢还是全部背?我的观点是:我是建议用debug的思维去做这个事情,并且写一些小的demo验证它。我之前在知乎写过一篇回答,redis 为什么是单线程的?我才不管的它是C语言,D语言,xxx语言写的。我想搞清楚它,那我就debug它,直接把整个redis在我的window11上运行起来。所有的问题,最怕的就是被debug。我就是想知道redis单线程是怎么回事,就算它是C语言实现的,照样debug。

2026-05-10 11:26:30 224

原创 为什么选微服务而不是动态扩容单体

动态扩容单体能不能做?能。单体应用部署成集群,前面挂个负载均衡,流量大了加机器。问题在于:选微服务的驱动力从来不是吞吐量。如果你面临的问题只是「流量扛不住了」,代码性能又不错,加机器就行,根本不需要微服务。选微服务是因为有些问题,你把单体复制100份也解决不了。

2026-05-09 11:21:41 457

原创 别人写的代码看不懂,到底是谁的水平有问题

你突然看到某段代码用了工厂模式,第一反应可能是:有必要吗?直接new一个对象不行吗?干嘛「故意」增加阅读难度?其实不是这样的,当你接触过的高手多了后,你会自然而然的认为:高手的代码,确实不太容易看懂,尤其你水平还不够的时候。我不是说你菜,只是每个人都会经历过这个阶段的。关键在于,你得分清楚一件事:到底是代码本身写得烂,还是你的知识面暂时还覆盖不到这里。

2026-05-09 10:07:34 592

原创 RocketMQ消息可靠性的三道关卡

RocketMQ的可靠性设计覆盖了消息流转的每个环节,但不是说用了RocketMQ消息就不会丢。它提供了机制,能不能用好取决于你怎么配、怎么写代码。任何一道关卡出问题,消息就可能丢。接下来分别看看RocketMQ在每道关卡上做了什么设计。

2026-05-08 14:01:57 574

原创 完结篇:28篇,一套完整的秒杀系统交付给你了

提醒」:是付费专栏,但是在知识星球里是免费的。写到这里,这个专栏正式完结了。整个项目一共写了从开篇词到全链路压测,28篇文章,前后持续了几周。写的过程比我预想的累很多。不是技术本身难,而是要把一套真实的生产系统拆开来,用文字讲清楚每一个设计决策背后的原因,同时还要保证前后28篇的技术细节完全一致、互相对得上,这个工作量远超写代码本身。有些章节反复改了三四遍。不是因为技术方案有问题,而是写出来之后发现读者如果没看过前面的某一篇,这段话就会看不懂。

2026-05-08 09:41:03 487

原创 批评下属不如当场展示解决方案

不一定是拥抱这么戏剧化的动作,但至少在后续的团队场合里,公开肯定她做得好的地方或者在群里说也行,让所有人知道你对她的认可没有变。有人问了这么一个问题:因为工作不到位,在部门全员会议上批评了下属,下属从此甩脸子不搭理,三个月过去了,组长职责也不履行了,部门内工作不好安排,念及感情和现实情况不知道如何处理。年轻人被说两句可能转头就忘了,但一个在团队里待了好几年、被你亲手提拔起来的人,她会觉得这是全盘否定,她会一直记着这个事的。对方承认了错误,回到工位上,她知道自己错了,但她不知道对的应该是什么样的。

2026-05-07 14:19:46 219

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除