得物热点探测技术架构设计与实践

1.概述

说到热点问题,首先我们先理解一下什么是热点?

热点通常意义来说,是指在一段时间内,被广泛关注的物品或事件,例如微博热搜,热卖商品,热点新闻,明星直播等等,所以热点产生主要包含2个条件:1.有限时间, 2流量高聚。

而在互联网领域,热点又主要分为2大类:

1.有预期的热点:比如在电商活动当中推出的爆款联名限量款的商品,又或者是秒杀的会场活动等

2.无预期的热点:比如受到了黑客的恶意攻击,网络爬虫频繁访问,又或者突发新闻带来的流量冲击等

针对于有预期的热点可以通过热点数据预热, 流量限制和异步队列进行处理。但是对于突发性无感知的热点数据流量,往往由于请求过于集中,导致访问数据流量超出的server的正常负载水位,从而出现服务过载不可用的情况,这种问题被称之为热点问题。

2.热点场景

看完关于热点问题的简单介绍,我们已经理解了热点产生的条件是短时间内被频繁访问导致流量高聚,而流量高聚就会出现一系列的热点问题。那被频繁访问的Key,就是我们通常所说的热Key。

接下来我们来看一下哪些场景会导致热点问题以及对应的热Key:

  • MySQL中被频繁访问的数据 ,如热门商品的主键Id

  • Redis缓存中被密集访问的Key,如热门商品的详情需要get goods$Id

  • 恶意攻击或机器人爬虫的请求信息,如特定标识的userId、机器IP

  • 频繁被访问的接口地址,如获取用户信息接口 /userInfo/ + userId

3.热点探测技术原理

了解完什么是热点问题和热Key出现的场景以后,我们会提出一个疑问,如何去提前感知这些热点数据?这里就需要聊到热点探测技术。

3.1 热点探测可以带来什么好处?

3.1.1 提升性能

解决热点问题通常会使用分布式缓存,但是在读取时还是需要进行网络通讯,就会有额外的时间开销。那如果能对热点数据提前进行本地缓存,即本地预热,就能大幅提升机器读取数据的性能,减轻下层缓存集群的压力。

  • 注意,本地缓存与实时数据存在不一致的风险。需要根据具体业务场景进行评估,缓存级数越多,数据不一致的风险就越大!

3.1.2 规避风险

对于无预期的热数据(即突发场景下形成的热Key),可能会对业务系统带来极大的风险,可将风险分为两个层次:

  • 对数据层的风险

正常情况下,Redis 缓存单机就可支持十万左右 QPS,并能通过集群部署提高整体负载能力。对于并发量一般的系统,用 Redis 做缓存就足够了。但是对于瞬时过高并发的请求,因为Redis单线程原因会导致正常请求排队,或者因为热点集中导致分片集群压力过载而瘫痪,从而击穿到DB引起服务器雪崩。

  • 对应用服务的风险

每个应用在单位时间所能接受和处理的请求量是有限的,如果受到恶意请求的攻击,让恶意用户独自占用了大量请求处理资源,就会导致其他人畜无害的正常用户的请求无法及时响应。

因此,需要一套动态热Key 检测机制,通过对需要检测的热Key规则进行配置,实时监听统计热Key数据,当无预期的热点数据出现时,第一时间发现他,并针对这些数据进行特殊处理。如本地缓存、拒绝恶意用户、接口限流 / 降级等。

3.2 如何进行热点探测?

首先我们要定义一下如何才能算是一个热点,我们知道热点产生的条件是2个:一个时间,一个流量。那么根据这个条件我们可以简单定义一个规则:比如 1 秒内访问 1000 次的数据算是热数据,当然这个数据需要根据具体的业务场景和过往数据进行具体评估。

对于单机应用,检测热数据很简单,直接在本地为每个Key创建一个滑动窗口计数器,统计单位时间内的访问总数(频率),并通过一个集合存放检测到的热 Key。

而对于分布式应用,对热 Key 的访问是分散在不同的机器上的,无法在本地独立地进行计算,因此,需要一个独立的、集中的热Key 计算单元。

我们可以简单理解为:分布式应用节点感知热点规则配置,将热点数据进行上报,工作节点进行热点数据统计,对于符合阈值的热点进行推送给客户端,应用收到热点信息进行本地缓存等策略这五个步骤:

1.热点规则:配置热Key的上报规则,圈出需要重点监测的Key

2.热点上报:应用服务将自己的热Key访问情况上报给集中计算单元

3.热点统计:收集各应用实例上报的信息,使用滑动窗口算法计算Key的热度

4.热点推送:当Key的热度达到设定值时,推送热Key信息至所有应用实例

5.热点缓存:各应用实例收到热Key信息后,对Key值进行本地缓存(此步骤根据具体业务策略调整)

4.Burning

理解完热点探测原理以后,我们来聊聊得物的热点探测中间件Burning。

作为潮流互联网电商平台,得物的电商业务高速发展,突发性的热点数据不断的冲击着我们的系统服务,比如大促秒杀,热点商品,恶意攻击等等。针对于这种突发性的大流量,单纯的机器扩容并不是一个有效的解决手段,我们需要一个集热点探测,热点感知,热点数据推送,热点数据预热,热点监控分析等功能于一体的热点探测中间件,因此Burning应运而生。

4.1 价值意义

Burning作为得物的热点探测中间件,提供可供业务方接入的SDK包和管理台规则配置,用于对热点数据的实时性监控,探测,操作和本地缓存等。主要解决了以下问题:

  • 实时热点感知:能实时监控热点数据,包含热Key,热数据,热接口等,秒级上报集群统一计算

  • 本地数据预热:对于特定场景可以通过动态本地缓存配置,防止流量突增导致Redis或DB数据流量压力过大导致系统雪崩

  • 周期热点统计:对热点数据进行周期性统计分析,标记出热Key规则及分布比例等,可以帮助业务方进行针对性优化治理和营销策略选择

  • 系统安全治理:可以通过热点Key探测分析,对于刷子用户,问题IP,机器人和爬虫进行标识,可实时熔断存在安全风险的请求,提高系统安全和可用性

4.2 关键指标

为满足高并发场景,热点探测中间件Burning在设计的时候,重点关注了如下指标:

1.实时性:热点问题往往具备突发性,客户端必须能够实时发现可疑热Key并推送给计算单元进行探测

2.高性能:热点探测往往需要处理大量的热点探测请求和热点计算,因此热点探测中间件的性能要求较高,才能满足巨量的并发并有效降低成本

3.准确性:热点探测需要精准的探测符合规则热Key,实时监听规则的变化,正确的进行热Key上报和热Key计算

4.一致性:热点探测需要保证应用实例的本地缓存热Key一致,当热Key变更导致value失效时,应用需要同时进行失效来保证数据一致性,不能出现数据错误

5.可扩展:热点探测需要统计和计算的Key量级很大,而且存在突发流量的情况,统一计算集群需要具备水平扩展的能力

4.3 架构设计

Burning的架构设计遵循了以上热点探测的技术原理,同时借鉴了jd-hotKey的设计思路,主要分为Burning-Admin、Burning-Worker、Burning-Config、Burning-Client四个模块:

  • Burning-Admin (热点探测管理台):与Worker节点Netty长链接通信,提供不同维度的应用管理和热点规则配置,提供查询热点数据统计,规则和热点数据监控大盘,提供工作集群信息查询及客户端节点信息查询,提供本地缓存动态配置及热点信息实时通知

  • Burning-Worker(热点集中计算单元):无状态server端,与管理台和客户端进行Netty长链接通信,获取规则,滑动窗口计算热点,将热点记录推送到管理台展示和客户端处理

  • Burning-Config(热点配置中心):作为热点、规则配置中心和注册中心,将规则配置下发到Worker节点和客户端,通过Raft算法进行系统高可用一致性保证

  • Burning-Client(热点客户端SDK):与Worker节点建立Netty长链接通信,监听配置中心配置变化定时推送热Key数据,获取热Key推送本地内缓存设置,与Redis-client无缝集成及其他ORM框架无缝集成

4.4 链路流程

热点探测主要包含以下几个主要流程:

1.用户在管理后台(Burning-Admin)进行热点规则配置并进行热点数据实时监控

2.管理后台(Burning-Admin)将规则配置信息上传给配置中心(Burning-Config)

3.配置中心(Burning-Config)将热点规则下发给客户端(Buring-Client)和工作节点(Burning-Worker)

4.客户端(Burning-Client)获取到规则, 将指定规则的热Key定时上报给工作节点(Burning-Worker)

5.工作节点(Burning-Worker)获取到上报的热Key后进行滑动时间窗口计算,对于满足阈值的热点推送给客户端(Burning-Client)

6.客户端(Burning-Client)拿到热点数据后,进行对应的本地缓存配置

4.5 核心代码

  • 客户端启动器ClientStarter,启动配置中心和注册中心,Worker建连,注册事件监听,设置app_name、port、caffeine缓存大小、cache配置、监控配置等

public synchronized static void startPipeline(BurningCommonProperties burningCommonProperties) {

    if (STARTED.get() == Boolean.FALSE) {
        DwLogger.info("start pipeline");
        // 设置参数上下文
        setToContext(burningCommonProperties);
        // 配置中心启动
        EtcdConfigFactory.buildConfigCenter(burningCommonProperties.getConfigServer());
        ConfigStarter starter = EtcdConfigStarter.getInstance();
        starter.start();
        // 注册中心启动
        RegisterFactory.buildRegisterCenter(burningCommonProperties);
        RegisterStarter registerStarter = RegisterStarter.getInstance();
        registerStarter.start();
        // 热点探测启动
        DetectFactory.startDetect(burningCommonProperties.getPushPeriod());
        // 开启worker重连器
        WorkerRetryConnector.retryConnectWorkers();
        // 注册事件监听
        registEventBus();
        // 开启监控
        MetricsFactory.startMetrics();
        STARTED.set(Boolean.TRUE);
    }

}
  • 客户端进行热Key判断,如果符合规则就上报给Worker节点计算,同时进行统计计数
public static Object dynamicGetValue(String key, KeyType keyType) {
    try {
        //如果没有为该key配置规则,就不用上报key
        Boolean dynamicRule = dynamicRule(key);
        if (dynamicRule == null) {
            return null;
        }
        Object userValue = null;

        ValueModel value = getValueSimple(key);

        if (value == null) {
            HotKeyPusher.push(key, keyType);
        } else {
            //临近过期了,也发
            if (isNearExpire(value)) {
                HotKeyPusher.push(key, keyType);
            }
            Object object = value.getValue();
            //如果是默认值,也返回null
            if (object instanceof Integer && Constant.MAGIC_NUMBER == (int) object) {
                userValue = null;
            } else if (Boolean.FALSE.equals(dynamicRule)) {
                userValue = null;
            } else {
                userValue = object;
            }
        }

        //统计计数
        MetricsFactory.metrics(new KeyHotModel(key, value != null));

        return userValue;
    } catch (Exception e) {
        DwLogger.error(DwHotKeyStore.class, "get value error");
        return null;
    }
}
  • Worker节点启动nettyServer,用于各个业务服务实例进行长连接,接收客户端上报数据
public void startNettyServer(int port) throws Exception {
    //boss单线程
    EventLoopGroup bossGroup = new NioEventLoopGroup(1);
    //worker节点组
    EventLoopGroup WorkerGroup = new NioEventLoopGroup(CpuNum.WorkerCount());
    try {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, WorkerGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler(LogLevel.INFO))
                .option(ChannelOption.SO_BACKLOG, 1024)
                //保持长连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                //出来网络io事件,如记录日志、对消息编解码等
                .childHandler(new ChildChannelHandler());
        //绑定端口,同步等待成功
        ChannelFuture future = bootstrap.bind(port).sync();
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            bossGroup.shutdownGracefully (1000, 3000, TimeUnit.MILLISECONDS);
            WorkerGroup.shutdownGracefully (1000, 3000, TimeUnit.MILLISECONDS);
        }));
        //等待服务器监听端口关闭
        future.channel().closeFuture().sync();
    } catch (Exception e) {
        DwLogger.error("netty server start error.", e);
    } finally {
        //优雅退出,释放线程池资源
        bossGroup.shutdownGracefully();
        WorkerGroup.shutdownGracefully();
    }
}
  • Worker节点通过监听客户端上报,异步消费队列Client消息
public void beginConsume() {
    while (true) {
        try {
            HotKeyModel model = QUEUE.take();
            if (model.isRemove()) {
                iKeyListener.removeKey(model, KeyEventOriginal.CLIENT);
            } else {
                iKeyListener.newKey(model, KeyEventOriginal.CLIENT);
            }
            //处理完毕,将数量加1
            totalDealCount.increment();
        } catch (Exception e) {
            DwLogger.error("consumer error.", e);
        }
    }
}
  • 如果是新增一个Key,就生成滑动窗口,基于时间窗口数据判断是否热Key
@Override
public void newKey(HotKeyModel hotKeyModel, KeyEventOriginal original) {
    //cache里的key
    String key = buildKey(hotKeyModel);
    String name = StringUtils.isBlank(hotKeyModel.getGroup()) ? hotKeyModel.getAppName() : hotKeyModel.getGroup();

    //判断是不是刚热不久
    Object o = hotCache.getIfPresent(key);
    if (o != null) {
        return;
    }
    SlidingWindow slidingWindow = checkWindow(hotKeyModel, key, name);
    //看看hot没
    boolean hot = slidingWindow.addCount(hotKeyModel.getCount());

    if (!hot) {
        //如果没hot,重新put,cache会自动刷新过期时间
        CaffeineCacheHolder.getCache(name).put(key, slidingWindow);
    } else {
        hotCache.put(key, 1);

        //删掉该key
        CaffeineCacheHolder.getCache(name).invalidate(key);

        //开启推送
        hotKeyModel.setCreateTime(SystemClock.now());

        //当开关打开时,打印日志。大促时关闭日志,就不打印了
        if (ConfigStarter.LOGGER_ON) {
            DwLogger.info(NEW_KEY_EVENT + hotKeyModel.getKey());
        }

        //分别推送到各client和etcd
        for (IPusher pusher : iPushers) {
            pusher.push(hotKeyModel);
        }

    }

}
  • 如果是删除一个Key,这里删除包含客户端发消息删除,本地线程扫描过期Key和管理台删除
@Override
public void removeKey(HotKeyModel hotKeyModel, KeyEventOriginal original) {
    //cache里的key
    String key = buildKey(hotKeyModel);
    String name = StringUtils.isBlank(hotKeyModel.getGroup()) ? hotKeyModel.getAppName() : hotKeyModel.getGroup();
    hotCache.invalidate(key);
    CaffeineCacheHolder.getCache(name).invalidate(key);

    //推送所有client删除
    hotKeyModel.setCreateTime(SystemClock.now());
    DwLogger.info(DELETE_KEY_EVENT + hotKeyModel.getKey());

    for (IPusher pusher : iPushers) {
        pusher.remove(hotKeyModel);
    }

}
  • Worker计算完成后将结果异步推送给Client,通过app进行分组批量推送
@PostConstruct
public void batchPushToClient() {
    AsyncPool.asyncDo(() -> {
        while (true) {
            try {
                List<HotKeyModel> tempModels = new ArrayList<>();
                //每10ms推送一次
                Queues.drain(hotKeyStoreQueue, tempModels, 10, 10, TimeUnit.MILLISECONDS);
                if (CollectionUtil.isEmpty(tempModels)) {
                    continue;
                }

                Map<String, List<HotKeyModel>> allAppHotKeyModels = Maps.newHashMap();
                Map<String, List<HotKeyModel>> allGroupHotKeyModels = Maps.newHashMap();

                //拆分出每个app的热key集合,按app分堆
                for (HotKeyModel hotKeyModel : tempModels) {
                    if (StringUtils.isNotBlank(hotKeyModel.getGroup())) {
                        List<HotKeyModel> groupModels = allGroupHotKeyModels.computeIfAbsent(hotKeyModel.getGroup(), (key) -> new ArrayList<>());
                        groupModels.add(hotKeyModel);
                    } else {
                        List<HotKeyModel> oneAppModels = allAppHotKeyModels.computeIfAbsent(hotKeyModel.getAppName(), (key) -> new ArrayList<>());
                        oneAppModels.add(hotKeyModel);
                    }
                }

                CustomizedMetricsProcessor processor = CustomizedMetricsProcessor.builder(MetricsConstant.BURNING_NETTY_OUT).build();

                // group hot key push
                pushGroup(processor, allGroupHotKeyModels);

                // app hot key push
                pushApp(processor, allAppHotKeyModels);

            } catch (Exception e) {
                DwLogger.error("push to client error.", e);
            }
        }
    });
}

4.6 最佳实践

Burning提供了2种使用方式,一是通过原生方法调用,二是通过声明式注解@EnableBurning , 以下对使用注解进行热点探测的部分场景提供最佳实践:

1.进行热点判断,用于热点拦截和自定义处理实现

@Component
public class Cache {
    @EnableBurning(prefix = "hot_Key_", cache = false, hitHandler = ExceptionHitHandler.class)
    public String getResult2(String Key) {
        return "这是一个测试结果" + Key;
    }
}

2.命中热点规则处理类,可进行自定义实现hitHandler接口(注意cache=false)

public class ExceptionHitHandler implements HitHandler {
   @Override
   public Object handle(String Key, ProceedingJoinPoint joinPoint) {
       //此处可自定义实现
      throw new RuntimeException("对不起,您没有权限访问: " + Key);
   }
}

3.用于Redis缓存热点探测

@Component
public class Cache {
​
    @Resource
    private RedisTemplate<String, String> RedisTemplate;
​
    @EnableBurning
    public String getResult(String Key) {
        return RedisTemplate.opsForValue().get(Key);
    }
}

4.用于MySQL热数据缓存

@Repository
public class SmsSignRepo {
​
   @Autowired
   private SmsSignMapper smsSignMapper;
​
   @EnableBurning(prefix = "SMS_SIGN", dynamic = false, KeyType = DATABASE_Key)
   public List<SmsSign> getAll() {
      Example example = new Example(SmsSign.class);
      Example.Criteria criteria = example.createCriteria();
      criteria.andEqualTo("status", 1);
      return smsSignMapper.selectByExample(example);
   }
}

4.7 性能表现

4.7.1 Worker节点性能压测

上游40个测试调用实例共同调用的场景下,并发数800,递进压测

压测结果:1个4C8G工作节点每秒可平稳处理约15W个key的热点探测,成功率大于99.999%,worker节点CPU平均占用为80%,内存占用60%

4.7.2 Client业务应用性能压测

  • DB场景压测

Client配置为4C8G,120个并发请求,压测时长10min

1.原生未接入Burning的DB操作接口场景

压测结果:未接入burning,处理总请求数约112万,平均TPS约1500,平均RT约63MS。CPU在压测满载情况下100%,内存平均使用48%

2.接入Burning的DB操作接口场景

压测结果:接入burning后,处理总请求数457万(对比未接入Burning增加345万),平均TPS约5800(对比未接入Burning增加4300),平均RT约8MS(对比未接入Burning下降55MS)。CPU在压测满载情况下100%,内存平均使用50%(对比未接入上升2%,本地缓存消耗)

  • Redis场景压测

Client配置为4C8G,120个并发请求,压测时长10min

1.原生未接入Burning的Redis操作接口场景

压测结果:未接入burning,处理总请求数约298万,平均TPS约3800,平均RT约14MS。CPU在压测满载情况下100%,内存平均使用48%

2.已接入Burning的Redis操作接口场景

压测结果:已接入burning,处理总请求数约443万(对比未接入增加145万),平均TPS约5700(对比未接入上升1900),平均RT约8MS(对比未接入下降6ms)。CPU在压测满载情况下100%,内存平均使用48%,基本持平

4.7.3 压测报告

  • Burning工作节点单机每秒处理15万个key的探测请求,CPU稳定在80%左右,基本无任何异常

  • 客户端应用接入burning后,对应用实例本身CPU负载基本无影响,内存占用上升主要取决于指定的本地缓存大小,接入后接口性能提升明显,QPS明显上升,RT明显下降

5.总结

热点问题在互联网场景中屡屡出现,特别是电商业务的需求场景,例如对于大促期间或者活动抢购期间的某个爆品,可能会出现在几秒时间内流入大量的流量,由于商品数据在Redis cluster场景下会按照hash规则被存放在某个Redis分片上,那么这个瞬间流量也有可能出现打挂Redis分片,导致系统雪崩。所以我们要善于利用热点探测中间件进行热Key探测,通过预置本地缓存解决突发流量导致的系统瓶颈,也能通过热点数据监控分析进行针对性的系统调优。

得物热点探测组件Burning上线至今,支持了数十个交易核心链路服务,在满足基础热点探测的前提下,Burning还支持本地缓存压测标/染色标识别能力,客户端本地Ecache/Caffeine缓存模式选择,热点规则Group聚合统计等扩展能力。应用服务接入Burning后对于热点数据探测及数据获取性能显著提高,通过预热&实时本地缓存,极大的降低了下层缓存集群和数据库的负载压力,为业务服务的健康运作保驾护航。

文/Leo

相关推荐

压测AI Agent 治理与评测调优实践|得物技术

本文介绍智能分析Agent在压测调试中上线后的治理闭环建设:通过Langfuse记录完整执行链路,结合用户反馈与Trace还原问题根因;利用CLI Mock固化证据数据集,实现相同场景下的回测验证。基于固定案例与五档评分机制,持续评估方案质量、延迟与成本,确保修复有效且无新问题引入,推动Agent能力迭代优化。

SmartCodeTech的博客 286

从中心调度到自驱协作多 Agent 架构的三次反转|得物技术

本文探讨多Agent系统中的控制权分配问题,提出三大协作架构:Master Agent(中心调度)、任务看板(共享状态)与Advisor(轻量咨询)。通过划清上下文边界与模型边界,强调应以信息相关性而非职业标签划分Agent。三种模式分别将决策权集中于中心、下放至共享状态、再下沉至执行者,形成控制权逐步下沉的演进路径。案例显示,合理设计可提升复杂任务的并行性、弹性与可维护性。

SmartCodeTech的博客 416

Jev 实战:为AI工作流引入轻量决策层 x10倍提速|得物技术

完成这三个场景后,我对适用边界有了更明确的认识:它们都可以先定义答案范围,再根据判断结果驱动下一步操作。接入时,我会优先明确输入、选项、采纳条件和兜底路径,再评估Jev是否适合承担这一环节。结合这些实践,我更容易理解Jev(TypeSafe System One)作为专用结构化决策模型不生成自然语言,而是返回带概率的判断结果。后续接入时,我会继续从脚本中边界明确的判断任务开始,分别验证准确性、耗时和费用,再决定是否扩大使用范围。下面整理了相关能力、限制和接入要点,便于查阅。

SmartCodeTech的博客 345

国产算力·昇腾 910C 大模型推理优化(下):源码修改与算子优化,提速30%|得物技术

本文延续上篇,深入vllm-ascend源码优化:通过多流重叠实现MoE共享专家并行计算,消除冗余事件开销,并解除与FUSED_MC2的互斥限制,实现c=1下TPOT从8.2ms降至8.0ms;优化decode阶段host侧开销,引入状态跟踪跳过冗余拷贝;设计Block Table CPU快路径,规避小batch下NPU kernel启动延迟;针对GDN层融合L2Norm至recurrent kernel,减少算子调用与内存往返。综合优化后推理性能显著提升,形成可复用的昇腾910C大模型推理优化方法论。

SmartCodeTech的博客 243

国产算力·昇腾 910C 大模型推理优化(上):镜像更新与参数调优,提速 40%|得物技术

文中详细给出每一项优化的动机、实现(含具体源码改动路径与关键代码片段)、验证数据与踩坑记录(包括十余项实测无效或负向的尝试),希望为同样在国产算力上做推理优化的团队提供一份可直接复用的工程参考。

SmartCodeTech的博客 223

动态规则的 Agent 实践:用确定性工程驾驭 LLM 的资产智能验收

面对财务验收中规则多变、材料非结构化、核对复杂等痛点,传统规则引擎难以应对。系统采用“规则即配置”思路,由大语言模型(LLM)负责理解合同、扫描件等非结构化材料并执行语义比对,工程系统则保障流程编排与可追溯性。通过异步处理、幂等设计、三类流量隔离及双通道(文本/图像)处理,实现高效稳定运行。结合用户反馈构建自动标准答案,辅以试跑、回测与发布门禁机制,形成闭环质量体系。底层采用确定性工作流架构,确保行为可预期、可测试,真正实现灵活规则的快速迭代与安全上线。

SmartCodeTech的博客 344

发一张图,它居然“跃“出屏幕了?一文读懂得物 3D 空间图片技术实践

3D 空间图片功能的落地,涉及模型生成、内容分发、客户端渲染之间的一系列取舍。本文重点分享如何生产出高质量、小体积的模型,以及如何在手机上流畅运行。

SmartCodeTech的博客 555

别再只卷向量检索了,得物交易搜索如何用“生成式”实现召回范式跃迁?

你搜"af1",它得给你"空军一号"。这一年,得物交易搜索把召回从"做选择题"改成了"写答案"——不再从商品池里"找"最像的,而是让模型自己"生成"你真正想要的。从 LLM 语义索引到 HLLM、语义 ID,搜索是怎么从"检索"走向"生成"的?

SmartCodeTech的博客 593

指标平台:从语义底座到智能消费的实践路径|得物技术

这篇文章想做的,不是在本体化的宏大叙事上再叠加一层理论,而是把我们在真实落地中验证过的路径讲清楚:语义底座怎么从零建立起来、怎么保证质量不失控、怎么支撑 Text2SQL 和 AI Coding 两条消费主线,以及沿着这条路径往前走,下一步该往哪个方向发力。

SmartCodeTech的博客 316

企业级 MultiAgent 落地:Plan 模式与主子 Agent 协作|得物技术

基于 AgentScope Java 的企业级 MultiAgent 平台,为研发、数据分析和知识问答等场景提供统一的模型调用、工具接入、任务编排、流式输出与运行追踪能力。

SmartCodeTech的博客 302

得物小摊 AI Native 演进实录:用 Harness 构建可控 AI 交付

AI Coding 一个人用很顺手,进了团队就漏:指令没人审、经验难沉淀、过程看不见、链路不闭环。作者团队基于 Multica 做了 EP-Harness,把 Agent 当成员管,给它套一层可执行、可观察、可治理的 Harness,并让反馈闭环。成果:可追溯决策、多 Agent 协作,高频异常从每 4 小时 2400 多条降到个位数,对得物技术补上团队级 AI 协作关键一环。

SmartCodeTech的博客 542

企业级 MultiAgent 的记忆系统:短期上下文与四层记忆架构实现|得物技术

在 MultiAgent 平台中,Agent 的"记忆"能力是实现智能对话和个性化服务的核心资产。本文深入剖析 Agent 记忆系统的设计理念与实现细节,重点解析长期记忆架构的写入与加载流程,涵盖 LLM 智能判断、语义检索、Token 预算控制、冲突处理等关键技术,为开发者提供完整的技术实现参考。

SmartCodeTech的博客 502

EP-Harness:从个人 AI Coding 到团队级 Agent 工作流|得物技术

AI Coding 个人用得爽,一到团队就崩。EP-Harness 把 Agent 从聊天工具变成团队协作成员——可管理、可追溯、可闭环。落地后高频异常从 2400+/4h 收敛到个位数。

SmartCodeTech的博客 693

得物知识问答:复合检索 Agent 的系统设计实践

从"搜到什么用什么"到"搜→筛→挖→验"自主决策闭环——我们造了一个有判断力的 RAG Agent,不是套壳。

SmartCodeTech的博客 734

实战从零开始构建一个Coding Agent:Violin |得物技术

理解了 coding agent 的构建原理,也就掌握了理解其他 agent 的一把钥匙。笔者对每天都在使用的 agent 原理很感兴趣,于是决定自己写一个:violin。

SmartCodeTech的博客 926

AI Native 交易核心系统的研发范式|得物技术

如何改造旧研发流程适配 AI 编码?本文提出五道标准化关口治理思路,依托 Claude Code Spec-Driven 插件打通需求澄清、方案设计、TDD 落地、门禁管控与埋点监控,构建带人工确认门控的完整工作流,以五层自底向上架构实现 AI 编码规范化落地。

SmartCodeTech的博客 975

推荐系统体验的数字化突破:得物自动化评测平台的技术实践|AICon 文章整理

「得物推荐 AI Harness 工程化实践系列」的末篇内容,本系列共三篇连载。本篇(末篇)详解得物推荐评测平台的完整技术体系:从主观体验量化到大模型自动化评测流水线,涵盖多维度指标设计、人机协作提示词校验闭环、分布式任务调度与成本精控等核心工程实现,以及单周百万级审计需求下实现 91% 资源成本优化的工业级落地实战细节。

SmartCodeTech的博客 1493

RAG 核心概念与原理:Chunking、Embedding、相似度、HNSW 与多路召回|得物技术

决定 RAG 效果的关键不在大模型,而是文本切块、查询改写、多路召回与精排。合理切块存好知识库内容,向量匹配抓语义、BM25 匹配关键词互补。先优化用户提问,快速召回一批相关文档,再用精排模型精细筛选,整套检索流程配合到位,问答准确度才会明显提升。

SmartCodeTech的博客 1079

从“机械应答“到“服务伙伴“:得物高可控智能客服的 Agent 工程实践|AICon 演讲整理

本次分享围绕以下核心技术展开:客服 Agent 挑战与架构设计(Single-Agent→Multi-Agent→Harness);高可控性数据飞轮(PE 自动化 + DPO 训练);RL 策略训练和人工经验对齐;多轮半双工消息流控制。

SmartCodeTech的博客 749

得物推荐系统诊断 Agent:从 “调接口” 到 “会思考”|AICon 演讲整理

本文是得物技术专家在 AICon 上海演讲整理的技术实录。AICon上海2026_全球人工智能开发与应用大会暨大模型应用生态展_InfoQ技术大会「得物推荐 AI Harness 工程化实践系列」的中篇内容,本系列共三篇连载。本篇(中篇)进一步详解得物推荐复杂业务场景下,AI代码从生成、防护校验到安全上线的完整技术体系、自研AI Harness整体架构框架、全流程安全防护机制、混合智能体核心算法实现,以及工业级工程落地的实战细节。

SmartCodeTech的博客 1364

得物 OceanBase 落地实践

得物选型OceanBase多模数据库应对业务挑战,通过验证其高可用架构、存储压缩技术及混合负载处理能力。测试显示OceanBase在复杂查询场景性能较MySQL提升130-200倍,在高并发TP/AP混合场景表现优异,存储成本降低40%+。通过DBA内部报表业务试点验证其稳定性后,逐步推广至核心业务场景,优化数据库技术栈,实现性能与成本的双重收益。

SmartCodeTech的博客 1381

AI UITester:AI Native 的 UI 自动化测试新范式|得物技术

ai_uitester 代表了 AI Native 的 UI 自动化测试新范式:这不仅是工具的升级,而是测试范式的转变 ------ 从 "代码驱动" 转向 "视觉驱动",从 "人工调试" 转向 "AI 自愈",从 "三端分离" 转向 "统一抽象"。

SmartCodeTech的博客 778

从狂野代码到按目标生产:得物推荐 AI Harness 的工程化实践|AICon 演讲整理

本文是得物技术专家在 AICon 上海演讲整理的技术实录。「得物推荐 AI Harness 工程化实践系列」的开篇内容,本系列共三篇连载。将系统拆解得物推荐复杂业务场景下,AI 代码从生成、防护校验到安全上线的完整技术体系,逐一详解自研 AI Harness 整体架构框架、全流程安全防护机制、混合智能体核心算法实现,以及工业级工程落地的实战细节。本篇(上篇):将整体介绍团队自研的 AI Harness 体系,包括建设思路、全生命周期防护机制、混合智能体架构及落地效果。

SmartCodeTech的博客 1080

从表单到 Agent:得物社区活动搭建的 AI 实践之路

一场营销活动从策划到上线,运营要在三个系统间跳转 10 + 次、填写 40 + 个字段。我们用 AI 重新设计了这条链路 —— 从 “AI 帮你填表单” 到 “两阶段 Agent + 聚合工作台”。这篇文章记录的不是技术细节,而是这条路上的选择和反思。

SmartCodeTech的博客 742

从埋点需求到规则资产:Hermes Agent 重构得物数仓工作流

埋点和指标需求中,消耗数据承接方的不是生成答案,而是补齐证据链、对齐历史口径、识别下游影响,并在生产写入前留下可追溯的确认记录。本文数据承接方指承接业务需求的数据同学或业务合作伙伴;后文讨论内部研发、元数据、查询和门禁能力在流程中的角色。

SmartCodeTech的博客 656

让 Claude Code 拥有自我进化和记忆系统|得物技术

本文记录了为 Claude Code 构建的一套持久化记忆与自我学习系统的设计思路与实现细节。这套系统让 AI 助手能够跨越会话边界记住用户习惯,并在每次对话结束后自动提炼行为规律和系统信息,通过向量检索快速提取关键信息,下一次对话时主动应用,逐步进化为更懂你的编程伙伴。

SmartCodeTech的博客 994

用 LLM Agent 重构告警排查流程|得物技术

告警排查需频繁切换日志、APM、链路追踪等多个平台,耗时 10~30 分钟,且高度依赖个人经验。我们做了 Troubleshooter——用 LLM Agent 自动完成数据采集、根因分析和处置建议生成。上线后中位数排查耗时从 20 分钟降到 4.4 分钟,覆盖 11 个服务和 10+ 种告警类型。

SmartCodeTech的博客 1007

HorizonVault 技术深潜:如何在 HDD 上做出 100GB/s+ 级大吞吐分布式存储|得物技术

HorizonVault是一款面向Kafka远程存储的高吞吐分布式存储引擎,通过分布式并行写入和状态感知调度解决冷数据存储的三大核心问题:吞吐瓶颈、性能抖动和恢复能力。系统采用分层架构,Meta负责全局资源调度,Broker处理请求路由,Store实现本地磁盘管理,形成完整的写入治理链路。通过将HDD磁盘提升为一等资源,实现顺序追加写入、多盘并行和慢盘隔离,在保证高吞吐的同时控制延迟。存储结构采用DiskStore组织磁盘资源,LogSegment顺序写入数据,IndexSegment定位读取,Change

SmartCodeTech的博客 890

Claude Code Harness 工程:数仓侧落地方案|得物技术

Harness 工程通过职责分层实现研发流水线可靠性提升。Claude 负责需求理解与代码生成等语义层工作;hooks 负责规范检查等确定性执行;Subagents 隔离血缘查询、自测等高 token 操作;Memory 承载跨会话状态持久化。四层协同使数仓 AI 开发从"对话式辅助"转变为"规则驱动的自动化流程"。

SmartCodeTech的博客 1099

BP Claw 破解 AI 编码输入难题 ——FlinkSpec 需求智能化实践|得物技术

本文为 FlinkSpec 系列之开篇,亦是这场工程化变革的序章。BP Claw 所立之处,不过链路之源。FlinkSpec 所图,乃以 AI 之力,将实时数仓从需求落地至验收上线的全程工序,熔铸为一套精密自洽、生生不息的智能工程体系。宏图未竟,后续系列将逐章揭幕,敬请期待!

SmartCodeTech的博客 1037
上一篇: 今年很火的AI绘画怎么玩
下一篇: 得物容器SRE探索与实践
得物技术
得物技术 得物技术官方账号 得物技术官方账号
博客等级 码龄6年 2492粉丝 408原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值