网易首页 > 网易号 > 正文 申请入驻

Golang后台服务性能优化,实用Tips梳理大全

0
分享至


作者:rossixiao

性能优化是一个经久不衰的课题了,我们都常做。本文列举了很多常用的tips,基本都是我日常开发中遇到的问题,我将这些问题和方法梳理了下来。
GC原理

这一节会较为详细介绍go的内存管理机制,也即GC。之所以要重点介绍是因为:

  1. GC是很多服务的性能瓶颈,在性能优化问题上是举足轻重的。

  2. 许多常见的优化手段都是围绕着内存管理进行的,只有了解了原理处理起来才游刃有余。另外go自身的内存管理方案也一直在迭代优化,了解后我们可能会发现自己遇到的性能问题是因为go版本太低了。

  3. go这一套内存自动管理方案本身很有借鉴意义,如果学习到,碰到相似的业务可以效仿其设计方案。如一些复杂的调度系统。

标记-清除(Stop-the-world)

STW是指暂停所有goroutine,标记可达和不可达的对象,最后清除不可达对象,完成垃圾回收的过程。 在go1.3之前垃圾回收就是依赖的全局STW,因此性能很低,一次STW带来的停顿时间可达数百毫秒。

三色标记法+写屏障三色标记法

  1. 初始时所有的对象节点都被标记成白色

  1. 第一次扫描从根节点出发,把能遍历到的对象从白色集合放到灰色集合

  1. 重复扫描灰色集合,将灰色对象引用的对象从白色集合放到灰色集合,然后把此灰色对象放到黑色集合

  1. 直到灰色集合清空,内存中只有黑白两种颜色。此时可以回收所有白色对象

很多人把三色标记法称为三色并发标记法,因为它存储了对象的中间状态,不需要一次性遍历完。但实际上和程序并发运行时,对象之间的引用关系会发生更改(写操作),而染色会读引用关系,也即发生了读写冲突。这种冲突可能导致白色对象断开和灰色对象的链接,挂在一个黑色对象上,而黑色对象是不会作为扫描的根节点的,因此白色对象被误删除,如图中的对象3。因此内存回收的一个很关键的操作就是把白色对象保护起来,可以延时删除,但不能误删除。


触发三色标记法不安全的必要条件


  1. 白色对象被黑色对象引用

  2. 且白色对象断开了所有灰色对象与它之间的可达关系

其实只要破坏了这两个必要条件之一,就能避免白色对象被误删除。后面的优化都是围绕着这个规则来的。

加入写屏障,保护白色节点

  1. 插入屏障:将B节点挂在A的下游时,B节点会被标记为灰色。 保障了白色节点不会被挂在黑色节点下。

  2. 删除屏障:对删除的对象,如果自身为白色,会被标记为灰色。保障了被删除的白色节点有灰色节点与之链接(对,自己给自己撑腰)。

go1.5就升级到了三色标记法+写屏障的策略,保证了扫描和程序可以并发执行,无需停顿。但由于栈写操作频繁且要保障运行效率,写屏障只运用到了堆上,如果白色节点被挂在黑色节点上,为了保障安全性,栈还是要进行一次STW扫描,以修正状态。这一STW停顿一般在10~100ms。

混合写屏障

go1.8引入了混合写屏障,避免了对栈的重复扫描,极大减少了STW的时间。和写屏障对比,加了以下两个操作:

  1. GC开始时会将栈上的所有可达对象标记为黑色

  2. gc期间,栈上新创建的对象会被初始化为黑色

这样做的道理在,栈的可达对象全标黑了,受颜色保护。而也不会出现白色(不可达)对象被挂在黑色对象的情况,因为它,不可达。


引入混合写之后,以及几乎不需要STW了。

gc优化GC瓶颈分析症结在GC扫描

已知go已经把STW压缩到极致了,所以这并非是大多数系统的问题所在,真正消耗性能的是gc扫描的计算过程。和GC回收相比也是扫描过程更消耗cpu。

扫描的时机:

  1. 堆内存达到阈值时触发。下次GC阈值 = 上次GC后存活对象大小 × (1 + GOGC/100),默认 GOGC=100(内存翻倍时触发),可通过环境变量调整。

  2. 定时触发。若持续 2 分钟未触发 GC,强制启动扫描(避免长期未回收的内存泄漏)。

  3. 手动触发。调用 runtime.GC() 强制启动扫描,常用于调试或内存敏感操作后。

  4. 内存分配时触发 。申请大对象(>32KB)或小对象时本地缓存不足(mcache 耗尽),可能触发扫描。

内存回收的时机:

  1. 标记终止后立即启动 。标记阶段完成后,清除阶段回收所有白色(未标记)对象,此阶段与用户代码并发执行。

  2. 内存分配时触发辅助回收 。若程序在 GC 过程中分配新内存,可能被要求协助执行部分回收任务。一般来讲,gc扫描是更加消耗性能的那一步,但我们一般不分开说,统称一次gc。

如何定位GC问题

利用火焰图,可以看到gcBgMarkWorker占用cpu的百分比,一般超过10%就需要优化了。 需要留意的是mallocgc属于内存分配带来的瓶颈,并非gc扫描问题。


减少堆对象分配

gc优化的方向之一是减少堆对象的分配,这是因为和栈相比,堆对象要gc扫描的时候要递归扫描所有对象,且栈对象会随着生命周期的结束而被释放,而堆对象全部需要gc扫描来回收。

小对象使用结构体而非指针

func createUser() *User {     return &User{ID: 1, Name: "Alice"} // 逃逸到堆 }

改成下面的写法编成栈分配,随着生命周期被自动回收:

func createUser() User {     return User{ID: 1, Name: "Alice"} // 栈分配,函数结束后自动回收 }
通过参数传递替代闭包捕获

func main() {     x := 42     go func() {         fmt.Println(x) // x 逃逸到堆     }() } func main() {     x := 42     go func(val int) {         fmt.Println(val) // val 通过值传递,保留在栈上     }(x) }
利用bigcache存储大对象(GB级别)

bigcache利用[]byte数组存储对象,会被当成是一个整体只会扫描一次,完全规避了gc扫描问题。但需要自己做内存管理,且使用的时候要加一次编解码操作。

内存池减少对象分配

var pool = sync.Pool{     New: func() interface{} { return make([]byte, 1024) }, } func processRequest() {     buf := pool.Get().([]byte) // 从池中获取(可能复用)     defer pool.Put(buf)        // 放回池中     // 使用 buf... }
减少gc扫描次数调整GOGC大小

默认是增加一倍触发GC回收,可以适当调大

import "runtime/debug" func main() {     debug.SetGCPercent(200)  // 堆增长 200% 即触发 GC }
抬高堆大小基数

初始化的时候分配一个比较大的对象,提高触发GC的基数

func main() {     ballast := make([]byte, 10<<30) // 10GB 虚拟内存(实际 RSS 不增加)     runtime.KeepAlive(ballast)     // 阻止回收     // 主逻辑... }
预分配内存

// 未优化:多次扩容 var data []int for i := 0; i < 1000; i++ {     data = append(data, i)  // 可能触发多次堆分配 }

预分配内存,可以避免中途多次触发GC扫描,且也减少了数据迁移带来的开销

// 优化:单次预分配 data := make([]int, 0, 1000)  // 一次性分配底层数组 for i := 0; i < 1000; i++ {     data = append(data, i)     }
为什么不能手动回收,减少gc压力呢?

go不支持

善用缓存

缓存在我们这的使用场景还是挺多的,我们需要合理设计缓存,使得对外接口的平均耗时在100ms以下。我们曾经有因为没加缓存,在for循环中拉游戏详情,导致大部分线程都阻塞在I/O等待中,导致接口耗时高,系统吞吐量低。

for appid := range appids {  detail := GetDetailInfo(appid) // rpc调用     ... }

但加缓存并非是无脑加的,缓存本身也可能会到来性能问题。如:

  1. 商城首页因异步更新缓存的时候频繁分配内存,导致cpu利用率出现周期性尖刺。这种也是会浪费cpu的,可以适当打散,减小尖刺。

  1. 使用了bigcache,但设置的内存清理时间太长,导致期间内内存打满引起OOM,机器频繁重启。

善用并发非关键路径异步化处理

对于耗时很高的非关键路径,要异步化处理,防止阻塞主流程。如一些非关键上报异步处理,再如畅玩好友在玩耗时较高,前端采用了异步加载的方式。

尽量减少锁竞争或者无锁化

如果资源竞争激烈,很可能会导致锁等待时间太长,和增加调度压力而浪费cpu。

减少锁的范围

func main() {    lock()    defer Unlock()    newA,newB := get() // 复杂的赋值操作    cache.A = newA    cache.B = newB } func main() {    newA,newB := get()     newCache.A = newA    newCache.B = newB // 先赋值,再直接替换,只需要锁住替换这一步    Lock()    cache = newCache    Unlock() }
选用读写锁/乐观锁来优化锁方案选用原子操作替代锁

func main() {  var counter int32 = 0  // 模拟10个goroutine并发自增  for i := 0; i < 10; i++ {   go func() {    atomic.AddInt32(&counter, 1) // 原子加1   }()  } }
使用协程池防止OOM

尽管go的协程已经非常轻量了,在一些场景还是要控制协程的数目,防止协程无节制得扩增,导致资源耗尽或者调度压力大。

一些高性能编程的好习惯避免大日志

在一次压测中,一个2核2G的服务,日志200k字节,吞吐量只能到80tps,后排查到瓶颈在于日志打太多了,减少日志输出后性能提升了几十倍。


可以看到当前主要性能消耗在字符串编解码这里。

避免深度拷贝

我们应该尽量减少深度拷贝的使用,在商城首页这里,由于过度使用了clone,导致了gc性能瓶颈。去掉clone,只对部分数据赋值后,性能提升了50%


避免反射

由于每个qgame的配置项是不同的结构体,为了通用化,qgameclient最开始利用反射来获取配置

type configItem struct {  attr *qgame.ConfigAttr // 公共属性  item reflect.Value     // 配置项 } // GetConfig 拉取配置 func GetConfig(ctx context.Context,  qryReq *QueryReq,  attrs map[string]*qgame.ConfigAttr,  confs interface{}) error {  itemType := reflect.TypeOf(confs).Elem().Elem() // 堆分配 // 获取配置  c, err := getConfWithCache(ctx, itemType, qryReq) if err != nil { return err  } // 解析并填充attrs和confs  d := reflect.New(itemType)  // 堆分配  reflectMap := reflect.ValueOf(confs) // 堆分配 for k, v := range c { if d.Type() != v.item.Type() {    return errs.Newf(ErrParams, "data type unmatch:%v,%v", d.Type(), v.item.Type())   }   attrs[k] = v.attr   reflectMap.SetMapIndex(reflect.ValueOf(k), v.item) // 堆分配  } returnnil }

后续遇到了性能瓶颈,反射需要在运行时动态检查数据类型和创建临时对象(每次reflect.ValueOf()或reflect.TypeOf()调用至少产生1次堆分配)。引入泛型,泛型在编译时期会生成对应类型的代码,运行时无需校验类型和分配临时对象。

type ConfigItem[T any] struct {  Attr   *qgame.ConfigAttr // 公共属性  Config *T                // config 配置map,key为配置id } func (c *QgameCli[T]) GetConfig(ctx context.Context, req *QueryReq) *QueryRsp[T] {  rsp := &QueryRsp[T]{   Items: map[string]*ConfigItem[T]{},   Env:   cache.env,  }     items := cache.getCachedConfig(req) for key, item := range items {   rsp.Items[key] = item  } return rsp }

最后性能上:泛型>强制类型转换/断言>反射

任务打散

当某个机器性能跟不上任务的计算复杂度时,可以考虑把计算任务打散到不同机器执行。我们用生产消费者模式执行任务的时候,消费者经常利用北极星的负载均衡能力,把任务平均分配到每个机器执行。

// StartConsume 开始消费 func StartConsume() {  for i := 0; i < 100; i++ {   util.GoWithRecover(func() {    for item := range ch {     item := item     consumeRpc(item) // 走rpc调用,打散消费任务    }   })  } }
编解码选型

目前比较常用的编解码类型有pb、json、yaml和sonic,编解码性能还是相差很大的, 之前gameinfoclient序列化从json改成pb时,获取游戏详情的耗时从100ms优化到了20ms。vtproto是司内大神提供的pb编解码优化版本,去掉了pb官方编码中的反射过程。实践发现trpc-proxy利用了vtproto,性能提高了20%。

性能对比

这是ai给出的通识结论:


我自己实测了发现单编码json的编码性能居然高于pb(sonic > json > vtproto > proto > yaml),这不是一个结论别记忆,后面会解释:

BenchmarkProtoMarshal-16         1000000              1074 ns/op BenchmarkVtProtoMarshal-16       1157985               903.8 ns/op BenchmarkJsonMarshal-16          1743318               688.7 ns/op BenchmarkSonicMarshal-16         3684892               335.9 ns/op BenchmarkYamlMarshal-16           154058              7499 ns/op 测试对象: TestData := &pb.TestStruct{   A: 1,   B: []string{    "test",   },   C: map[int32]string{    1: "test",   }, }

实际上是因为对于小对象而言json的反射机制开销较小,且go1.22版本优化了json反射机制,性能有所提升,所以表现为小对象 json的编码性能高于proto。 我尝试换成大对象,印证了这一点(sonic > vtproto > pb > json > yaml)

BenchmarkProtoMarshal-16             912           1325582 ns/op BenchmarkVtProtoMarshal-16           908           1316555 ns/op BenchmarkJsonMarshal-16              666           1792485 ns/op BenchmarkSonicMarshal-16            4705            252298 ns/op BenchmarkYamlMarshal-16               79          13914111 ns/op 测试对象: a := int32(12345) b := make([]string, 0, 5000) for i := 0; i < 5000; i++ {  b = append(b, fmt.Sprintf("str-%d-abcdefghijklmnopqrstuvwxyz", i)) } c := make(map[int32]string, 3000) for i := int32(0); i < 3000; i++ {  c[i] = fmt.Sprintf("value-%d-0123456789ABCDEF", i)  } TestData = &TestDataStruct{  A: a,  B: b,  C: c, }

最后,一般编码和解码是对称使用的,这里也测了一下对称使用编解码的性能:

小对象: BenchmarkProto-16                 560961              2082 ns/op BenchmarkVtProto-16               559299              2011 ns/op BenchmarkJson-16                  375512              3248 ns/op BenchmarkSonic-16                1224876               974.7 ns/op BenchmarkYaml-16                   62400             18995 ns/op   大对象: BenchmarkProto-16                    369           3260424 ns/op BenchmarkVtProto-16                  364           3349230 ns/op BenchmarkJson-16                     201           5934529 ns/op BenchmarkSonic-16                   1483            798178 ns/op BenchmarkYaml-16                      42          28831239 ns/op

至此我的结论是: sonic性能最卓越,如果对压缩大小、平台不敏感,能使用sonic尽量使用sonic;如果对可读性要求比较高用json/yaml;跨端通信用pb,对性能敏感可升级用vtproto。

字符串拼接

  1. strings.Builder性能最高,底层是[]byte,可动态扩容

  2. strings.Join底层是strings.Builder,一次性计算分配内存,性能差不多

  3. +运算符。需要不断创建新的临时对象

  4. fmt.Sprintf()。性能很差,涉及到反射。性能敏感场景避免使用。

利用工具排查性能问题pprof

也即火焰图,伽利略已经集成了火焰图插件,可直接使用。下面一个例子是分析game_switch服务的性能瓶颈:

  1. 查看cpu time。发现SsoGetShareTails 、编解码、 GcBgMarkWorker占用了大部分cpu时间。

继续往下看,分析出SsoGetShareTails主要消耗在Sprintf函数上。


到这里已经可以猜测出:

  1. 编解码占大部分推测出可能回包包体很大,影响了性能。

  2. gcBgMarkWorker表示gc扫描消耗的性能,可能频繁分配内存,或者内存占用比较高。

  3. SsoGetShareTails中的Sprintf前面已经提到过是一个性能很低的字符串拼接方案,可以直接优化掉。

  4. 继续查看堆内存大小,包含gc回收的。可以定位到大头在接口、序列化和压缩上。

代码定位如下图。序列化和压缩是框架自带的,符合前面的推断---回包太大导致的。


最后看看还存活的堆内存大小。发现是游戏详情的缓存,符合预期。虽然在存活的堆内存里它算大头,但和总的堆内存大小对比还是挺小的,不是目前主要优化点,可降低优先级后续优化。


trace

对于一般的程序,pprof已经够用了。如果要更精细得定位问题,可以使用trace,和pprof不同的是,pprof是基于统计维度的,原理是定期采样生成cpu和内存的快照,而trace直接追踪到整个程序的运行,能提供时间线上的事件流。像这样:


上面提供是一段有死锁的代码:

func main() { // 创建trace文件  f, err := os.Create("deadlock_trace.out") if err != nil {   log.Fatal(err)  } defer f.Close() // 启动trace  err = trace.Start(f) if err != nil {   log.Fatal(err)  } defer trace.Stop() // 创建两个互斥锁 var mutex1, mutex2 sync.Mutex // goroutine1 先锁mutex1,再尝试锁mutex2  f1 := func() {   mutex1.Lock()   log.Println("goroutine1 获得 mutex1")   time.Sleep(1 * time.Second) // 确保死锁发生   mutex2.Lock()   log.Println("goroutine1 获得 mutex2")   mutex2.Unlock()   mutex1.Unlock()  } go f1() // goroutine2 先锁mutex2,再尝试锁mutex1 gofunc() {   mutex2.Lock()   log.Println("goroutine2 获得 mutex2")   time.Sleep(1 * time.Second) // 确保死锁发生   mutex1.Lock()   log.Println("goroutine2 获得 mutex1")   mutex1.Unlock()   mutex2.Unlock()  }() for i := 0; i < 10; i++ { gofunc() {    time.Sleep(5 * time.Second)   }()  } // 等待足够时间让死锁发生 for {  } }

通过 Goroutine analysis,可以看到func1对应的协程编号是23,且大部分时间都处于阻塞中:


点击查看协程23具体的事件流,func1最后一次执行停留在sleep这,虽然很疑惑为什么不在Lock()这里,但也印证了后续的流程被阻塞了



需求阶段

最近被问到:“如果下游接口就是很慢,你要怎么办?”。最近畅玩就遇到了类似的问题,畅玩要接入ams广告,但一个广告接口却有接近800ms的耗时,明显对体验是有损的,使得我们不得不推动下游做性能优化。除此之外也提醒了我不应该仅限于需求开发,而应该从用户的角度出发,思考需求是否合理、是否可优化,协同产品一起保障体验。

体验要稳定做好兜底

  1. 异常兜底。

  2. 如算法侧挂了,要展示兜底素材;游戏封面缺失,过滤不展示或者展示兜底封面。边界兜底。

如帖子浏览完了的文案兜底;完善错误码机制,提示用户当前状态。稳定排序

有时候产品会忘记提供排序策略,除了被指定的随机资源位,其他应该协调一个排序方案,避免每次刷新都展示不同的内容。

数据源一致性

如前段时间遇到的不同页面展示的可领取礼包数不一致,实际是一个页面展示的所有礼包,一个页面没展示贵族礼包,这要求我们开发前和产品沟通数据和哪个需求的页面保持一致。

画面要流畅数据分页/分屏

如果一次请求的数据量太多,不仅会给后台带来性能问题,也可能引起前端前端渲染卡顿了,所以必要时需要沟通设计分页或者分屏(如设计列表页和二级页)。

隐藏高耗时的数据

延迟加载非首屏内容,优先保障核心功能可快速操作。

资源大小控制

如资料小卡的游戏段位图,一开始误给了一个10241024的高清图,会导致UI加载很慢,后续改成了120120的就能满足清晰度要求。

数据实时性分级

区分强实时性和弱实时性。如对于礼包数量、游戏在玩人数等允许有一段时间的延时,以减少对db的压力。

用户操作限频

如已经预约后按钮置灰、限制点击次数等,可以减少接口调用量,也能提高系统用户吞吐量。

成本沟通

如周报tips,产品要求每个人都生成特有的图片,已知图像处理会带来很多额外的开销,应该提醒产品并切换其他方案。

回包大小控制

回包太大不仅会影响服务性能,也会加大网络传输耗时和前端加载耗时。


特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
大连发生一起道路交通事故导致5人死亡

大连发生一起道路交通事故导致5人死亡

界面新闻
2026-02-03 17:25:48
零跑汽车员工吐槽“年会拉胯”,董事长朱江明回应,年会奖品和晚餐菜单曝光

零跑汽车员工吐槽“年会拉胯”,董事长朱江明回应,年会奖品和晚餐菜单曝光

红星新闻
2026-02-03 17:19:16
梅德韦杰夫核言论遭俄著名宣传员怒怼:天天核平这个,核平那个

梅德韦杰夫核言论遭俄著名宣传员怒怼:天天核平这个,核平那个

史政先锋
2026-02-03 14:05:55
夫妻网购娃娃菜中毒大反转!是丈夫投毒,对妻子灭口,商家被坑惨

夫妻网购娃娃菜中毒大反转!是丈夫投毒,对妻子灭口,商家被坑惨

离离言几许
2026-02-03 15:12:39
1-3到5-3!吴宜泽开门红,张安达爆冷世界冠军,丁俊晖破百救赛点

1-3到5-3!吴宜泽开门红,张安达爆冷世界冠军,丁俊晖破百救赛点

刘姚尧的文字城堡
2026-02-03 22:30:13
德国人爱喝酒、爱吃肉、爱甜食,为何民众更长寿?可能是5个原因

德国人爱喝酒、爱吃肉、爱甜食,为何民众更长寿?可能是5个原因

健康之光
2026-02-02 22:19:14
霹雳17性能过于强大,美媒苦思冥想,终于找出一个“致命缺点”

霹雳17性能过于强大,美媒苦思冥想,终于找出一个“致命缺点”

空天力量
2026-02-03 13:06:22
钱再多有什么用?52岁刘强东身家上千亿,儿子却成为他一生的遗憾

钱再多有什么用?52岁刘强东身家上千亿,儿子却成为他一生的遗憾

青橘罐头
2026-01-31 21:39:14
负债百万、露宿街头、装疯卖傻,星光大道的草根歌手现状太落魄

负债百万、露宿街头、装疯卖傻,星光大道的草根歌手现状太落魄

冷紫葉
2026-02-02 17:07:15
2026春晚第三次联排落幕,小品演员大换血,赵本山的担心恐成真

2026春晚第三次联排落幕,小品演员大换血,赵本山的担心恐成真

素衣读史
2026-02-02 19:24:56
绝密档案继续曝光!西方精英底裤被撕烂,特朗普迎来致命一击!

绝密档案继续曝光!西方精英底裤被撕烂,特朗普迎来致命一击!

派大星纪录片
2026-02-03 16:47:34
15万亿瞬间蒸发!特朗普终于动手:这是一场针对中国的金融屠杀?

15万亿瞬间蒸发!特朗普终于动手:这是一场针对中国的金融屠杀?

快看张同学
2026-02-03 09:36:38
孙宇晨与谷爱凌的大瓜:自称以“咖位不同”被分手前女友再爆猛料

孙宇晨与谷爱凌的大瓜:自称以“咖位不同”被分手前女友再爆猛料

穿透
2026-02-03 21:45:13
中国男篮21人集训名单:赵睿胡金秋领衔 周琦落选杨瀚森未进名单

中国男篮21人集训名单:赵睿胡金秋领衔 周琦落选杨瀚森未进名单

醉卧浮生
2026-02-03 22:31:15
投资圈大佬去世!年仅40岁,坊间流传死因或与黄金白银暴跌有关

投资圈大佬去世!年仅40岁,坊间流传死因或与黄金白银暴跌有关

火山诗话
2026-02-03 09:11:09
“爱泼斯坦案”诡异录像曝光 女孩穿水手服跪地

“爱泼斯坦案”诡异录像曝光 女孩穿水手服跪地

看看新闻Knews
2026-02-03 20:15:03
刘虎涉诬告罪非法经营罪法律分析:结果掌握在“解释权”里!

刘虎涉诬告罪非法经营罪法律分析:结果掌握在“解释权”里!

兵叔评说
2026-02-03 01:23:07
萝莉岛大雷出现!比想象中炸裂,牵扯多国总统,难怪爱泼斯坦必死

萝莉岛大雷出现!比想象中炸裂,牵扯多国总统,难怪爱泼斯坦必死

北纬的咖啡豆
2026-02-02 22:46:22
成都个别领导的风险,比刘虎的要大得多

成都个别领导的风险,比刘虎的要大得多

不主流讲话
2026-02-03 15:18:01
62分钟速胜过关!王欣瑜送蛋横扫晋级,澳网后首秀迎开门红

62分钟速胜过关!王欣瑜送蛋横扫晋级,澳网后首秀迎开门红

全景体育V
2026-02-03 21:14:02
2026-02-04 00:43:00
腾讯技术工程
腾讯技术工程
不止于技术
1363文章数 600关注度
往期回顾 全部

科技要闻

1.25万亿美元!xAI员工赢麻了

头条要闻

挪威王储妃给爱泼斯坦发暧昧邮件:你让我兴奋

头条要闻

挪威王储妃给爱泼斯坦发暧昧邮件:你让我兴奋

体育要闻

“也许我的一小步,会成为中国足球的一大步”

娱乐要闻

大S逝世一周年 S家没通知大S子女惹争议

财经要闻

中央一号文件:扎实推进乡村全面振兴

汽车要闻

上汽决定不再等那个“正确答案”了

态度原创

旅游
艺术
家居
亲子
手机

旅游要闻

南京江宁推出近百场文旅活动迎新春

艺术要闻

成都在建第一高楼冲刺300米!

家居要闻

极简木艺术 典雅自在

亲子要闻

如果他长大以后看到这条视频,希望他不会怪我们全营的人合起伙来骗他 杨雪呀

手机要闻

vivo X300 Ultra入网,大量爆料已出现

无障碍浏览 进入关怀版