聊聊我在字节基础架构组搞技术探索的一些野路子实践

胡秀珍☆
2026-07-29 00:24
阅读 656

去年双11刚过,组里开复盘会,leader 说了一句"明年我们要在基础架构层面做一些技术探索,鼓励大家多折腾"。我当时心里就想,得,又要卷了。不过说实话,作为一个在字节基础架构组搬了快五年砖的后端老兵,我对这种"技术探索"其实是有执念的。毕竟天天写 CRUD 是会让人废掉的。

先交代下背景吧。我坐标杭州,来字节之前面过阿里和网易,最后阴差阳错来了字节。说实话杭州这边互联网氛围确实好,跳槽机会也多,但我这人比较懒,习惯了字节的节奏也就不想动了。平时写代码是个重度 Vim 党,IDE 基本不用,同事经常吐槽我"都什么年代了还在用 Vim",我就回一句"你懂个锤子,Vim 才是男人的浪漫"。

好了废话不多说,今天想跟大家聊两个我最近折腾的东西——一个是 DALL-E 在内部工具链上的集成实践,另一个是区块链技术在内部权限审计上的探索。你可能会问,这俩玩意儿跟基础架构有毛关系?别急,听我慢慢道来。

先聊 DALL-E:当 AI 画图遇上内部工单系统

事情是这样的。我们组负责维护一套内部的运维工单系统,每天各个业务线提上来的工单少说也有大几百个。其中有一类是"资源申请"类的工单,经常需要附上一些架构图、拓扑图来说明申请理由。但说实话,大部分研发画的图那叫一个惨不忍睹,我见过用画图板画的"架构图",线条歪歪扭扭的,跟小孩涂鸦似的。

上个月有个同事提了个工单,申请一批 GPU 资源,附的图是用 PPT 画的,我看了差点没把饭喷出来。当时我就想,能不能用 AI 来辅助生成一些示意图?正好那阵子 DALL-E 的 API 开放了,我就动了心思。

技术选型上的纠结

刚开始我想的是直接调 OpenAI 的 API,但咱们毕竟是字节,数据安全这根弦得绷紧了。直接把内部架构信息传给外部 API,安全合规那边肯定过不去。所以我花了一周时间调研,最后决定走一条折中路线:

方案 优点 缺点
直接调 OpenAI API 简单粗暴,效果最好 数据安全风险大,合规过不了
自建 DALL-E 模型 数据完全可控 算力成本太高,模型微调周期长
本地部署开源替代 + DALL-E 风格微调 数据可控,成本适中 效果有折扣,需要调参

最后选了第三种方案。我们用 Stable Diffusion 作为底座,结合一些内部积累的架构图数据做了 LoRA 微调,尽量让生成的图接近 DALL-E 那种风格。虽然效果比不上原版 DALL-E,但至少能用了。

踩坑实录

集成过程中踩了不少坑,说几个印象深的:

第一个坑是 prompt 工程。我们发现直接让研发输入自然语言描述,生成的图经常牛头不对马嘴。比如有人输入"一个微服务架构",AI 给你画出来一个长着很多触手的章鱼。后来我们做了一层 prompt 模板化,把常见的架构模式抽象成模板,研发只需要填参数就行。

# prompt 模板化处理示例
ARCH_PROMPT_TEMPLATE = """
Technical architecture diagram, clean and professional style, 
white background, blue and gray color scheme:
{component_list}
Connection style: {connection_type}
Layout: {layout_type}
"""

def generate_arch_prompt(components, conn_type="arrow", layout="layered"):
    component_desc = ", ".join([
        f"{c['name']} ({c['type']})" for c in components
    ])
    return ARCH_PROMPT_TEMPLATE.format(
        component_list=component_desc,
        connection_type=conn_type,
        layout=layout
    )

第二个坑是生成速度。一张图在 A100 上跑大概要 15-20 秒,但工单系统对响应时间是有要求的。我们做了个异步队列,用 Redis 做任务分发,生成完了通过 WebSocket 推给前端。这块倒是轻车熟路,毕竟基础架构组天天跟这些中间件打交道。

// 异步任务分发,Go 写的,毕竟字节内部 Go 是主力
type ImageGenTask struct {
    TaskID    string `json:"task_id"`
    Prompt    string `json:"prompt"`
    Callback  string `json:"callback_url"`
    Priority  int    `json:"priority"`
    CreatedAt int64  `json:"created_at"`
}

func (s *ImageGenService) SubmitTask(ctx context.Context, task *ImageGenTask) error {
    // 优先级队列,高优工单先处理
    data, _ := json.Marshal(task)
    return s.redisClient.ZAdd(ctx, "image_gen:queue", 
        &redis.Z{Score: float64(task.Priority), Member: string(data)}).Err()
}

第三个坑说出来你可能不信——是 Vim 的锅。我调试 prompt 的时候习惯用 Vim 编辑 JSON 配置文件,结果有一次手滑把模板里的转义字符搞乱了,导致生成的图全是乱码。排查了两个小时才发现,当时真的想砸键盘。后来老老实实写了个 JSON schema 校验,提交前自动检查格式。

上线效果

折腾了大概三周,这个功能上线了。效果嘛,说实话没有想象中那么惊艳,但确实帮了不少忙。据统计,工单中附带架构图的比例从 30% 提升到了 72%,而且图的质量肉眼可见地提升了。运维那边的兄弟反馈说审核工单的时候舒服多了,不用再对着灵魂画作猜意图了。

不过也有翻车的时候。有一次某个同事用这个工具生成了一张"分布式缓存架构"的图,结果 AI 给他画了一堆罐子(cache 嘛,罐子),底下还写着"Redis"。发到群里被大家笑了半天,那哥们儿尴尬得不行。后来我们在 prompt 里加了更强的约束,这种情况就少多了。

再聊区块链:内部权限审计的"链"上实践

第二个探索方向就更野了——区块链。别笑,我知道一提到区块链很多人就觉得是割韭菜的,但我这次做的跟币一点关系都没有。

起因是一次线上事故

今年年初,我们内部权限系统出了一次事故。有个已经离职的同事的账号,因为某个同步任务的 bug,权限没有被及时回收。结果这个账号被利用了大概 4 个小时,虽然最后没造成什么严重后果,但安全团队那边炸了锅,要求我们做整改。

复盘的时候我们发现一个核心问题:权限变更记录的审计链路不够可靠。虽然我们有操作日志,但日志是可以被篡改的,而且在多节点部署的情况下,日志的一致性也难以保证。当时安全团队提了个需求:能不能做一套不可篡改的权限变更审计系统?

我当时脑子里就蹦出来一个词——区块链。

为什么是区块链?

我知道这听起来有点杀鸡用牛刀,但你仔细想想区块链的核心特性:

  • 不可篡改:数据一旦写入就无法修改,天然满足审计需求
  • 可追溯:每一笔变更都有完整的时间线和因果关系
  • 分布式共识:多节点验证,单点故障不影响数据完整性

这不就是为审计场景量身定做的吗?当然,我们不会去搞什么公链,用的是联盟链的思路,内部几个核心节点做共识就够了。

架构设计

整体架构其实不复杂,我画个文字版的:

┌─────────────────────────────────────────────────┐
│                  权限管理系统                      │
│  ┌──────────┐  ┌──────────┐  ┌──────────┐      │
│  │ 权限分配  │  │ 权限回收  │  │ 权限变更  │      │
│  └────┬─────┘  └────┬─────┘  └────┬─────┘      │
│       │              │              │             │
│       └──────────────┼──────────────┘             │
│                      ▼                            │
│            ┌─────────────────┐                   │
│            │  审计事件总线    │                    │
│            └────────┬────────┘                   │
└─────────────────────┼───────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────┐
│              联盟链审计网络                        │
│  ┌────────┐  ┌────────┐  ┌────────┐  ┌────────┐ │
│  │ Node-1 │  │ Node-2 │  │ Node-3 │  │ Node-4 │ │
│  │(基础架构)│  │(安全团队)│  │(合规部门)│  │(业务SRE)│ │
│  └────────┘  └────────┘  └────────┘  └────────┘ │
│                                                  │
│  共识算法: PBFT (实用拜占庭容错)                   │
│  存储: LevelDB + MySQL(索引)                      │
└─────────────────────────────────────────────────┘

技术栈选型上,我们没有从零造轮子,而是基于 FISCO BCOS(微众银行开源的联盟链平台)做了二次开发。选它的原因很简单:国产开源、文档齐全、社区活跃,而且已经在金融领域验证过了,安全合规那边好交代。

核心代码片段

权限变更事件上链的核心逻辑,我用 Go 简单示意一下:

// 权限变更事件结构
type PermissionChangeEvent struct {
    EventID     string    `json:"event_id"`
    Timestamp   int64     `json:"timestamp"`
    Operator    string    `json:"operator"`     // 操作人
    TargetUser  string    `json:"target_user"`  // 被操作人
    ChangeType  string    `json:"change_type"`  // grant/revoke/modify
    Resource    string    `json:"resource"`     // 权限资源
    PrevState   string    `json:"prev_state"`   // 变更前状态
    NewState    string    `json:"new_state"`    // 变更后状态
    ApprovalID  string    `json:"approval_id"`  // 审批单号
    Signature   string    `json:"signature"`    // 操作签名
}

// 上链服务
type AuditChainService struct {
    chainClient *fiscobcos.Client
    eventBus    *EventBus
}

func (s *AuditChainService) RecordPermissionChange(
    ctx context.Context, event *PermissionChangeEvent,
) error {
    // 1. 生成事件摘要(用于链上存储,节省空间)
    eventHash := sha256.Sum256(mustMarshal(event))
    
    // 2. 构造链上交易
    tx := &fiscobcos.Transaction{
        Contract: "PermissionAudit",
        Method:   "recordChange",
        Params: []interface{}{
            event.EventID,
            event.Timestamp,
            event.Operator,
            hex.EncodeToString(eventHash[:]),
            event.Signature,
        },
    }
    
    // 3. 提交交易,等待共识确认
    receipt, err := s.chainClient.SendTransaction(ctx, tx)
    if err != nil {
        return fmt.Errorf("上链失败: %w", err)
    }
    
    // 4. 记录区块高度,用于后续溯源
    log.WithFields(log.Fields{
        "event_id":      event.EventID,
        "block_number":  receipt.BlockNumber,
        "tx_hash":       receipt.TxHash,
    }).Info("权限变更事件已上链")
    
    return nil
}

踩过的坑和教训

坑一:性能问题。 刚开始我们把所有权限变更都上链,结果发现 TPS 上不去。联盟链嘛,共识过程本身就慢,PBFT 的 TPS 大概在 1000-2000 左右。但权限变更的高峰期(比如每天早上的批量授权)一秒能来好几千个事件。

解决方案是做了一层缓冲:高频的变更先在本地做 Merkle Tree 聚合,每隔 5 秒把一批事件的根哈希打包上链。这样 TPS 压力一下就降下来了,而且单个事件的不可篡改性通过 Merkle Proof 依然可以验证。

坑二:存储膨胀。 虽然链上只存哈希,但完整的审计数据还是要存的。我们用了 MySQL 做详细数据的存储,链上哈希做校验。但半年下来,数据量增长很快,查询也变慢了。后来加了 Elasticsearch 做索引,查询性能才上来。

坑三:同事的不理解。 这个坑其实最大。我刚开始在组里提这个方案的时候,好几个同事觉得我在搞噱头,"用个数据库不就行了,搞什么区块链"。我花了两周时间做 POC,拿着数据去给他们演示"你看,数据库日志确实被改过,但链上的数据改不了",这才说服了他们。

所以说,技术选型这件事,技术本身往往不是最难的,最难的是让团队理解和接受。

实际效果

上线半年了,效果还是可以的。几个关键数据:

指标 改造前 改造后
审计数据完整性 依赖日志系统,有丢失风险 链上存证,不可篡改
权限变更追溯时间 平均 2 小时(需要翻多个日志源) 5 分钟内(链上直接查询)
安全审计通过率 偶尔有不合规项 100% 通过
系统额外延迟 P99 < 50ms(异步上链)

安全团队那边很满意,还专门发了封感谢邮件。虽然邮件里说"感谢基础架构组的大力支持"这种套话,但好歹是被认可了,开心。

一些心得体会

折腾了这两个项目,有一些感悟想分享给大家:

第一,技术探索不要怕"不务正业"。 DALL-E 和区块链,看起来跟基础架构都不搭边,但只要你找到合适的切入点,就能产生实际价值。关键是你要主动去想、去试,而不是等着 leader 给你派活。

第二,不要迷信技术,也不要排斥技术。 区块链在很多人眼里是忽悠,但在特定场景下它确实能解决问题。DALL-E 看起来很酷,但落地的时候一堆坑。技术没有好坏,只有适不适合。

第三,性能优化永远是个话题。 不管是图片生成的异步队列,还是联盟链的聚合上链,本质上都是在做性能优化。我这个人别的爱好没有,就喜欢抠性能,看到 P99 从 200ms 降到 50ms 能开心一整天。可能这就是程序员的快乐吧,简单且枯燥。

第四,Vim 党永不为奴。 最后夹带个私货,这两个项目的所有配置文件、代码调试,我全是在 Vim 里完成的。同事问我效率怎么样,我说你不懂,当你的手指形成肌肉记忆之后,写代码就像弹钢琴一样。好吧其实有时候也会按错键删掉半小时的工作,但这个不重要。

好了,今天就聊到这里。如果你也在做类似的技术探索,欢迎来杭州找我面基,我请你喝奶茶。毕竟在字节搬砖这么多年,也就这点爱好了。

对了,如果你在杭州想找后端岗位,阿里和网易确实机会不少,但字节的待遇和技术氛围也不差的,可以考虑考虑(手动安利)。

我们下期再见,我去修 bug 了,线上又报警了,烦死。

评论 0

最热最新
暂无评论
胡秀珍☆Lv.1
0
影响力
0
文章
0
粉丝