系统设计

转转运营系统之商品标签平台

高并发下秒杀系统的设计

  • 压力分摊。利用 分桶策略压力分摊,往往受到很多人的青睐。具体而言,面对单品库存,巧妙地拆分为多组,大大缓解抢购高峰的压力。但这背后藏着诸多棘手难题,如何精准地将库存均匀分配至各桶,杜绝分配不均;怎样有效处理拆分产生的库存碎片,避免少卖;分桶间的调度规则如何制定,确保协同高效;还有,业务量起伏不定,又该如何实现分桶动态扩容以灵活适配。
  • Redis + MQ
  • Inventory Hint。AliSQL 提供 Inventory Hint,帮助您快速提交/回滚事务,配合 Returning 和 Statement Queue,能有效提高业务吞吐能力。
  • 压力分摊 + Redis + MQ

Redis+MQ 的具体逻辑:

  • Redis 部分,通过 Lua 脚本进行数据处理。这里还进行了流水的记录。
  • MQ 部分,使用 RocketMQ 的事务机制。首先先向 RocketMQ 中发送 half 消息,然后检查本地事务执行情况(Redis 执行是否成功) 来判断是 commit 或者 rollback。同时配置 RocketMQ 反查机制,避免收不到本地事务执行结果,反查机制则是查询 Redis 中有没有流水的记录。后续就是 MySQL 消费消息了。
  • 记录流水的原因:为了保证下单和库存的一致性,我们可以用定时对账机制来核对库存流水和订单表中数据是否一致。当然也有其他一致性保证方案,比如 SeataTCC 等,可以根据具体的业务场景选择。

转转数仓评估体系实践

亿级高性能通知系统实践

消息通知系统设计:

服务划分|600

系统设计

请求发送:RPC 无需考虑消息丢失;MQ 异步解耦。

消息发送请求

首次消息发送|440

消息的幂等性处理:消息量大的情况下 + 重复消息只在短时间内发生,采用 Redis 判断。

问题服务动态发现器:异常服务的动态发现,是借助于 sentinel 的 API 在各自节点 JVM 内实现的,针对设置的 时间窗口请求的总次数失败的总次数 进行统计。统计后,采用类似“熔断”的机制来处理服务的可访问情况。

sentinel 滑动窗口的实现原理(环形数组):假设统计 1s 请求量,窗口为 2 个,那么每个窗口对应的 id 就是 0、1,相应的时间范围就是 0m-500ms,500ms-1000ms。如果当前时间是 700ms,那么对应的窗口 id=(700/500)%2=0,对应的 windowStart=700-(700%500)=200,对应的起始就是 id 为 0 的窗口;如果当前时间是 1200ms,对应的窗口 id=(1200/500)%2=0;对应的 windowStart=1200-(1200%500)=1000 大于 id=0 的起始时间,重置 id 为 0 的窗口起始值,id=0 的位置不变。

动态调整的线程池:自定义一个无界的阻塞队列,核心线程数和最大线程数相等,而且用的是默认的丢弃策略。在添加任务的时候,判断队列中的任务数目是否达到了 config 的最大值,通过调整 config 值,动态调整队列长度。如果无法添加,可以配置后续处理逻辑,如 MQ 落库 + 重试任务,来避免触发拒绝策略。

重试消息发送:重试的消息机制可以利用分布式定时任务调度框架,一般为了提高重试效率,会采用分片广播这种方式,自己做好消息重复发送的控制,我们也可以利用调度线程池来实现。

ES 与 MySQL 数据同步:由于发送消息的数据量,后台在进行数据查询时主要是通过 ES 进行查询处理的,这就涉及到数据库数据与 ES 数据一致性的问题。ES 更新完成后修改数据库状态为更新完成状态,若此时通知记录表还有更新,就会将同步状态初始化,若修改数据库为init先于同步完成后的更新就会出现数据不一致的问题,所以每次同步时携带上数据库中的 update_time,大于等于db中的 update_time 才会更新完成(其实 update_time 就是一个 版本号)。

ES 按月滚动建立索引,每月新建立的索引,标签都是 hot,新增的数据都会放入 hot 节点上进行存储,到了第二月,通过定时任务将上月索引的 tag 修改为 cold,ES 集群就会自动将数据迁移到标签为 cold 节点上。

稳定性保障

  • 流量突增:两层降级。当流量缓慢增大时,线程池满了后,利用 MQ 进行流量削峰,后续定时任务处理。当流量陡增,sentinel 判断后,直接改为 MQ 落库,后续延迟消费。
  • 资源隔离:耗时长的请求和耗时短的请求放在不同线程池中处理。
  • 第三方服务:限流、降级、熔断,避免影响别人服务。
  • 中间件的容错:比如需要考虑到 MQ 扩容时,会 MQ 宕机数秒的容错。
  • 监控 + 多机房部署 + 弹性扩缩容

将查询数据性能提升100倍的计数系统实践

链接:计数系统设计 TODO

商品准时达,购物不抓瞎,快来学习转转履约时效新姿势

京东商品预计在 xxx 时候送达。在转转 APP 的商品列表页、商品详情页、确认下单页、商品筛选项等等都会有履约时效的身影,由此可见,日常获取商品的预计送达时间的 QPS 很高,大促时足以破万。

送达时间的万级 QPS 支撑

将这个链路图进行细分,如:下单 仓储出货 物流揽收 物流派送。不同阶段的时间更新时间不同,有的可能要经常更新(存 Redis),有的可能不需要经常更新(本地缓存)。

处理逻辑包括:用户地址转换、商品寻仓储、仓库信息填充、匹配揽收时间、获取预计送达时间。前几项的优化如下,最后一个通过“发件省市 ID - 收件省市 ID - 揽收时间:预计送达时间” 来存储 Redis,进行快速匹配。

查询描述优化方案说明
用户地址转换本地缓存城市名称和 code 的映射关系发放入本地缓存
商品寻仓Redis请求一次放入 Redis
仓库信息填充本地缓存仓库信息为低频变化数据,数据量少,可以放入本地缓存
匹配揽收时间Redis配置修改是次日生效,每天定时刷入 Redis
次日达、隔日达以及三日达的可行性判断
  • 在商品标记上每个商品所在的仓库站点。
  • 提供到全国任意地址支持次日达的仓站点的能力。

优化存储结构

  • 存储结构由原来的 key-list 转变为 key-zset,把所有仓的所有批次(最晚支付时间)聚合成一个 zset,最晚支付时间作为 score,仓库信息作为 value 生成倒排索引。
  • 原本的存储结构是针对某个收件区的次日达,每个仓下有哪些最晚支付时间支持;现在的存储结构是针对某个区的次日达,每个时间下有哪些仓支持。

转转客服IM系统:高效沟通背后的技术挑战和解决方案

客服 IM 系统:从客户端到服务端,再从服务端到另一个客户端,任何一个环节的故障都可能导致消息延迟、丢失、乱序或重复,从而影响用户体验。

实时性问题:长短轮询 Websocket。技术选型考虑点:浏览器支持情况、服务端负载、客户端延迟、客户端消耗、实现复杂度。

可靠性问题

  • 利用 TCP 的 ACK 机制,通过 ACK + 等待 ACK 消息列表。
  • 服务器,维护全量数据 + 当消息发出时同时发送一个延迟 mq,延迟消息被消费时对应的消息仍在等待 ACK 列表中,则表示消息未能在规定时间内被确认,需要进行重试发送。
  • 客户端重新刷新 or Websocket 重连时,重新拉取数据。
  • 避免重复消费:发送方使用发送人 id 和消息发送时间戳作为唯一的 ACK 标识,服务端基于雪花算法生成消息 ID,将 ACK 与 ID 建立映射,再将消息 ID 发送给用户、客服。

640

心跳机制:人工客服有闲,如果长期没人说话,那么就需要断开连接。客户端定时发送心跳,服务端接受心跳后,开启心跳监控的定时任务。定时扫描,如果超过一定时间,进行一定的处理,如标记离线状态 or 彻底断开连接。

消息协议:首先,消息类型有心跳 message、用户/客服 message、系统 message。其次,客户 ID、用户 ID、消息内容。消息内容:消息格式(文本、图片、视频、优惠券等)、消息文本。

转转回收持久层的架构演进

项目背景:优惠券发放门槛低,随着业务发展激增,单表难以 hold;再加上查询逻辑越来越复杂,需要优化。

  1. 分库分表的技术选型
  2. 优化服务时,若长期方案开发慢,先实现一个临时改进方案
  3. ElasticSearch 数据写入到能查到存在延迟,与 Redis 结合来满足时效性。

数据增多的解决办法 —— 分库分表,技术选型如下:

  1. 基于 JDBC 进行代理:该方案不需要运维等人员的介入,技术内部即可进行开发优化。
  2. 基于数据库进行代理:该方案需要 DBA 或者运维的介入,维护起来不方便。
  3. TiDB 数据库:支持无限的水平扩展,具备强一致性和高可用性,编码层面的使用跟 MYSQL 无异。

最终选择了基于 JDBC 进行代理,因为这种方案可以纯内部进行消化,不需要外部部门介入,对于开发成本、时间周期来讲都是比较容易弹性调整的,后续有改造也不需要外部介入。

数据多并不一定要分库分表,参考“技术选型”中,有个业务场景中选择 TiDB。

关联:MySQL 分库分表高性能-数据库:读写分离+分库分表

查询越来越复杂

  • 例子:小明查询 iPhone13 非全新机、价格满 1000 元可用、以旧换新场景下、邮寄售卖可用的优惠券。
  • 当前的方案:把配置表全部拿出来机型进行内存过滤,拿着满足条件的配置 id 去绑定关系表里进行查找。
  • 临时改进方案:将优惠券放到内存中进行缓存,内存过滤减少不必要的额外查询,降低 gc 频率。同时,借鉴了中间件同步缓存数据的方案,一方面实时广播推送保证时效性,另一方面定时去拉数据来进行兜底处理。
  • 长期方案:ElasticSearch 来支持查询,但是 ES 数据写入到查询存在一定的延迟,而场景是需要实时的场景。解决方案是,通过 Redis+ElasticSearch 联动查询来保证时效性,在写入成功之后将配置 id 同步保存到 Redis 的 zset 结构中,设置个 10s 的过期时间。

其他性能优化手段:

  1. 查询只返回需要的字段信息。
  2. 定义索引的时候使用合适的字段。
  3. 限制数据总量,根据实际场景做数据归档。
  4. 减少索引范围,强制根据 uid 进行分片路由。

转转流量录制与回放的原理及实践

其他业务场景

揭秘支付对账:确保每一分钱的安全之旅

支付对账系统:支付使用方(转转)和支付提供方(第三方支付)相互确认交易、资金的正确性,保证双方的交易、资金一致正确。

其他

Spring声明式事务源码详解

接口从4秒到200毫秒-小小的日志竟能引发如此问题

通过阿里的 Arthas 工具的 trace 命令可以分析方法的耗时,发现是 org.slf4j.Logger:info() 耗时长。

Debug 过程:日志同步打印 多线程争抢资源 探究异步打印日志的原理 测试代码进行打断点。

火焰图应该更好一些,直接分析出每个函数的处理时间。

异步日志打印的底层采用的是 Disruptor 框架,采用环形数组来存储日志,生产者消费者模式。

org.apache.logging.log4j.spi.AbstractLogger #getLocation ,用来获取内容匹配日志输出格式中的 %C、%F、%l、%L、%M。最终发现是底层执行 C++代码慢的缘故。

结论为:

  • 避免打印过多无用日志,将测试过程中需要观察的日志输出为为 DEBUG 级别。
  • 生产环境打印日志的级别设置为 INFO。
  • 如果不需要关注日志打印的位置信息,可以将日志输出格式中的 %C、%F、%l、%L、%M 去掉。

SpringBoot的脚本引擎初始化也会导致OOM?

搜广推

多任务学习在转转主搜精排的应用

转转首页推荐粗排优化实践

多任务学习在转转搜索意图理解的实践

因果推断在转转推荐场景下的实践

转转搜推排序服务的响应对象序列化优化

技术选型

Geo技术助力,让风险定位更精准

GEO 工具的选型逻辑供参考。关连 GeoHash 编码

业务背景:下单地址可能和黑中介相邻,那么这个订单可能有风险,订单机器可能拿不回来。

MySQL。优点 1:兼容性高,通用性强。优点 2:数据化长期持久化。缺点:大数据量下复杂查询性能差,百万级经纬度的地址空间计算。

Redis。优点 1:内存存储,查询延时低,GEO 内部数据存储 SortedSet,支持高效范围查询和排序。优点 2:支持集群模式,适合分布式场景。缺点 1:内存容量有限,不适合长期存储海量数据。缺点 2:不支持高级地理计算(如面积、地理围栏计算)

ElasticSearch。优点 1:分布式架构,适合海量数据和高并发场景。内部倒排索引和分片机制,优化查询性能和保证容错。优点 2:内置地址空间数据类型,支持复杂地址查询(地理围栏、距离排序、多边形查询等)。缺点 1:需维护 ES 集群,开发学习成本高。缺点 2:内存和磁盘占用高,不适合小规模场景。

结合需求的场景,首先保证性能,次要无须重量级的框架,开发成本低,同时还要能够满足地理计算的基本要求。最终选择 Redis。

Redis 支持(1)添加与查询经纬度、(2)查询两个地址的距离、(3)指定范围半径内的地址。

突破数据存储瓶颈!转转业财系统亿级数据存储优化实践

业财系统接收了上游各个业务系统(例如:订单、oms、支付、售后等系统)的数据,并将其转换为财务数据。

这里使用 TiDB。没有使用分库分表的原因在于,业财系统数据多样性+复杂性,难以定义出一个业务主键。没有使用冷热库的原因在于,现阶段还会更改和查询历史数据,时间口径不统一,边界比较模糊;后期可能还会有其他类型数据,数据格式难以统一。

MySQL

”慢SQL”治理的几点思考

服务稳定性治理”:通过错误日志、慢 SQL、接口性能等各项指标优化,进一步提升系统稳定性和可靠性。

索引不发挥作用。因为优化器可能认为查找成本过大,规避的方式是,区分度小的字段避免建立索引。

内存碎片同样需要关注。当内存碎片过大时,如果出现库表的统计信息未及时更新,也会因为优化器评估的结果与实际差距太大,从而影响实际执行效果。

通过 show table status like ‘xxx’ 可以查看数据库的内存碎片。

DELETE 逻辑会使得内存碎片增加:

  • 删除标记。InnoDB 删除时,只将对应行标识为“已删除”,物理空间并不释放,为 MVCC 和回滚保留可能性。
  • 页内空洞。删除数据较多/频繁删除,会导致页内大量空洞,页实际利用率下降(如 90% 到 50%),读取相同数据量需要访问更多的数据页,IO 增加。
  • 页合并的局限性。InnoDB 仅合并相邻空闲页,若页分散则无法合并。

强制 MySQL 引擎清理内存碎片,是可以在线处理的吗,还是停止服务的?如果前者,可以流量小的时候,合并下?

前缀索引的坑。使用了唯一索引,导致两个不同的字符串,只是前缀相同就触发重复冲突。

长事务问题。当长事务导致 Undo Log 膨胀时,容易使得扫描效率降低。同时 Buffer Pool 中缓存页因旧版本数据过多,其缓存命中率也会下降。我们可以通过 SHOW ENGINE INNODB STATUSHistory list length 值是否飙升,加以判断。

聊聊Druid连接池的内部原理及推荐配置

Java 数据库连接池 Druid 源码分析

揭秘 MyBatis-Plus 批量插入的终极优化技巧

性能瓶颈

  • 逐条插入效率低:传统的逐条插入模式效率欠佳,每次插入数据时都要与数据库进行交互,从而产生较高的网络开销以及数据库解析成本。
  • 外键关系处理复杂:题目与选项之间存在外键关联,这就需要在插入数据后获取主键 ID,无疑增加了操作的复杂程度。
  • 批量操作性能有限:使用默认的 saveBatch 方法,其性能提升并不显著,难以满足高并发、大数据量的实际需求。

优化方法

  • 将 rewriteBatchedStatements 配置为 true:以此启用 JDBC 驱动的批处理重写功能,可显著提高批量插入的性能表现。
  • 预先生成 ID:采用 zzidc 等方式预先生成主键 ID,有效解决外键关系问题,进而支持批量插入操作。
  • 使用异步方法进行多线程批量插入:运用异步方法来进行多线程批量插入,确保线程安全与事务独立,避免出现资源竞争的情况。
  • 调整数据库连接池和线程池参数:对数据库连接池和线程池的参数进行调整,以满足多线程并发操作的实际需求。
  • 监控异步任务和数据库性能:对异步任务和数据库性能进行实时监控,以便能够及时发现并解决性能瓶颈问题。

rewriteBatchedStatements=true,启用批处理重写功能后,驱动能够将多条同类型的 SQL 语句进行合并,进而发送给数据库执行。网络交互降低,引擎解析次数降低,执行效率提升,总内存消耗降低。配置方式:jdbc:mysql://localhost:3306/db_name?rewriteBatchedStatements=true

多线程并发插入的实现。在 MyBatis 中,SqlSession 在默认情况下并非线程安全的。若在多线程环境下共享同一个 SqlSession,极有可能导致数据错误或引发异常。利用 Spring 的 @Async 注解,实现异步方法调用,每个异步方法都有自己的事务和 SqlSession。具体实现见原文。

评论提到:异步注解加声明式事务并不能保证所有批次同步回滚。

MySQL怎么出现幻读啦!

例子 1:

  • 开启事务 1
  • 在事务 1 中查询用户信息 - 3 条
  • 开启事务 2
  • 在事务 2 中插入一条新数据
  • 提交事务 2
  • 在事务 1 中将 ID 为 1 的数据的用户姓名修改为 Iversen
  • 在事务 1 中再次查询用户信息 - 3 条
  • 提交事务 1

例子 2:

  • 开启事务 1
  • 在事务 1 中查询用户信息 - 3 条
  • 开启事务 2
  • 在事务 2 中插入一条新数据
  • 提交事务 2
  • 在事务 1 中将所有用户的邮箱信息的后缀更换为@gmail.com - 4 条
  • 在事务 1 中再次查询用户信息 - 4 条
  • 提交事务 1

为什么例子 2 中再次查询的时候,查到了 4 条数据,出现了幻读?

  • UPDATE 执行全表更新 → 使用当前读 → 会看到事务 2 插入的新行
  • 这个 UPDATE 操作将新行也纳入了事务的修改范围
  • 后续查询(即使是普通 SELECT)现在能看到 4 条记录,因为这个 UPDATE 操作”提升”了事务的可见性

MySQL 的”半一致读”机制 —— 在 REPEATABLE READ 隔离级别下,MySQL 有一个特殊优化:

  • 当 UPDATE 语句可能修改多行时,会先使用”半一致读”检查哪些行需要更新
  • 这个过程会看到其他事务已提交的最新数据
  • 一旦 UPDATE 操作修改了某行,该行就会对当前事务完全可见

解决办法:

  • 采用串行化的隔离级别(不建议);
  • 开发时注意考虑这种产生幻读的场景,尽量通过调整代码逻辑规避幻读问题的发生(建议);
  • 若不能通过调整代码逻辑规避,可以考虑采用当前读 select xxx for update 的方式避免(建议);

间隙锁只会在当前读操作(如 SELECT FOR UPDATEUPDATEDELETE 等)时,在 REPEATABLE READSERIALIZABLE 隔离级别下使用。

关联:行锁快照读和当前读MVCCMVCC在InnoDB中的实现

其他

ToB复杂业务状态的可复用的解决方案

解决状态多、状态流转复杂的场景 —— 状态模式 or 状态机

|200

设计模式 - 状态模式:但是如果状态太多,流转逻辑过多,会分散在各个类中,难以直观查看。

|440

有限状态机:状态机由三部分组成,状态(State) 、事件(Event) 和动作(Action)组成。其中事件也称为转移条件。

在状态较多的情况下,更适合查表法来处理。查表法,就是将整个的状态机等价为“图”,将状态之间的流转等价为“边”,通过二维数组记录“边”的形式来存储状态的流转。

通过查表法来实现,一个好处就是可以将状态流转规则在配置文件 or DB 等位置中统一维护,可以看到全部流转规则,简化状态管理。

转转对于状态机的处理逻辑是,初始化是从 DB 中读规则,并转换为 Map<String, List> fsmNodeMapkey 是事件+当前状态,value 是要执行的 FsmNode 类。

public class FsmNode {
    private Integer opType;
    private Integer role;
    private Integer sourceStatus;
    private Integer targetStatus;
    private NodeType nodeType;
    private FsmAction action;
    private HashSet<JobConfig> jobConfigs;
    private HashSet<TransactionConfig> transactionConfigs;
}

除了基础的数据结构、规则保存到 DB 外,还需注意工程上实现:

  • 通过定时任务轮训数据表,重试执行失败的 Action。
  • 无状态设计,每次状态流转无需生成状态机实例,只要根据当前状态、事件到 Map 里找到需要执行的 Action 及 job 来执行就好。
  • 支持每次状态转换的时候发送事务消息(结合数据库事务实现)

阿里 Cola 状态机。Cola 状态机是一个轻量级的开源框架,相比 Spring Statemachine 和 squirrel-foundation,它更加简单、轻量且性能极高。1)简单、轻量,仅支持状态流转的状态机,不支持嵌套、并行等高级玩法。 2)无状态设计。可以使用一个状态机实例来响应所有的请求。

Cola 状态机本质上是状态模式 + 两个 Map。

第一个 Map,Map<S, State<S, E, C>> stateMap,key 为当前状态,value 为 State 对象。

State 对象类似状态模式,内部存储了状态转移 transitions map,即第二个 Map。

第二个 Map,HashMap<E, Transition<S, E, C>> transitions,在 State 对象内部,key 是 Event 事件,value 是 Transition 对象,Transition 内有要执行的 Action、初始状态、目标状态、驱动事件(Event)等。

Spring Statemachine。Spring 官方提供的一个状态机框架,支持状态的嵌套(substate)、状态的并行(parallel, fork, join)、子状态机等高级特性。1)简单易用。2)状态机结构层次化,有助于简化状态控制的开发过程。3)功能完备。与 Cola 状态机类似,也包括状态(State)、事件(Event)、转换(Transition)、动作(Action)等要素。并提供了更丰富的状态类型配置,如 choice、join、fork、history 等。

适用场景:适用于需要将复杂逻辑拆分为较小可管理任务、状态嵌套或需要循环遍历 if-else 结构并进行异常处理的场景。

小白也能看得懂!日志审计插件从入门到实战

好用的工具:

  • git-commit-id-maven-plugin 是一个 Maven 插件,在 Maven 构建过程中,插件会生成一个名为 git-commit-id.properties 的文件。这个文件通常包含有关当前构建的 Git 提交哈希、分支名称、提交时间等信息。

  • hibernate-validator 框架,然后利用 @Validated 配套的校验注解,自定义校验规则,避免配置错误。

  • spring-boot-configuration-processor 插件,该插件在打包的时候,会生成 target/classes/META-INF/ spring-configuration-metadata.json 文件,该文件被 IDEA 读取到后,在用户配置属性的时候,会有自动提示的效果。

  • 如果想让用户 import 插件包后,能看到源码,最简单的方法就是让用户利用 IDEA 的反编译功能,反编译出代码,但是会丢失很多的注释信息,因此我们可以使用 maven-source-plugin 插件。

转转日志审计插件,设计的组件有:

组件作用
LogPluginProperties配置的实体类,配置其他组件需要的属性,如 MQ 的连接信息
PluginLogDto日志信息实体,如日志标题、服务器地址、服务器名字、URL、参数、方法等
IlogPersistenceService日志持久化服务,可以直接打印控制台 or 存储 ES 等等
ICreatedByService租户服务,获得当前请求的用户标识
IDataStreamService日志数据流服务,将日志推送到 MQ 中
ThreadPoolTaskExecutor线程池,专用于传输日志数据,与“业务”隔离,避免影响性能
Server用于获取当前“宿主”服务的状态信息,例如 IP,环境信息等
LogRelayTask封装的日志任务,提交给线程池执行
具体更详细的再看一下上面的连接了解。

Prometheus在B端门店回收系统中的应用

普罗米修斯,上报类型:

  • Counter。递增的整数型指标,用于表示累计数量。只能增加,不能减少,一般用于统计请求次数、错误次数等场景。
  • Gauge。是一个可变的数值指标,用于表示某个瞬时值。可变大变小,一般用于表示当前连接数、温度等持续变化指标。
  • Histogram。可以将事件按照不同的桶进行分组,用来观察指标在各个不同区间范围的分布情况,一般用于分析请求延迟,操作响应时间。
  • Summary。与 Histogram 类似,区别在于 Histogram 存储的是数据,Summary 直接存储的就是百分位,本质上并没有什么区别,通过 Histogram 也可以计算出百分位。

在转转中一些应用:

  • 监控回收订单的数量、创建失败次数;
  • 接口响应情况、接口异常原因(异常类型的 Gauge)
  • 不同监控指标,报警力度不同
  • RPC 的 QPS 和耗时情况
  • 基础设施的监控:Java 程序情况(GC 情况)、数据库(事务耗时、回滚次数、事务提交次数)、容器的内存/磁盘等。

转转监控面板目录。链接日志与监控 TODO

当我重构时,我在想些什么

链接:代码重构指南代码坏味道 Bad-Smell

转转游戏MQ重构:思考与心得之旅

重构影响范围大/重要服务时,参考一下上线计划 + 测试计划。

系统重构上线计划:

  • 第一期:主要针对非核心业务 MQ 逻辑进行迁移重构。非核心业务灰度上线,控制影响范围,迅速验证架构的可行性与稳定性。
  • 第二期:核心业务相关 MQ 迁移重构。灰度上线,关注对核心业务的影响。完成此步基本完成全部业务逻辑迁移。
  • 第三期:对结构进行微调,主要是对相关功能进一步拆解、重构,使功能内部更为内聚,降低耦合,令整个系统最终达成设计之初的预期效果。

测试计划:

  • 黑盒测试,校验新老流程处理后的数据是否一致。
  • 白盒测试。测试每一行代码的覆盖率,并观察新老流程数据是否一致。
  • 调用接口前数据对比。在调用更新接口之处打印日志,对比新老流程调用更新接口的传参是否一致。

针对大规模服务日志敏感信息的长效治理实践

脱敏工具类、JSON 脱敏、APT 自动脱敏。弃用方案:日志中正则匹配,存在误判率。

Java

JDK21(21.0.2_13)分代ZGC在转转商列服务中的实践

什么!服务器内存又双叒叕打满了!