Post

Saveole's Tech Review, Issue 0

JDK23|SpringBoot CDS|ZGC|Go SSE|Raft

Post

  • Java

    • JDK 23 发布了!

      ​ 前不久,go 发布了 1.23 版本,Java 最近也如期发布了 JDK 23(none tls),主要更新大部分还是 preview 阶段的提案,个人印象深刻点的 一(JEP474)是 ZGC 默认使用分代模式(Generational Mode), 二(JEP471)sun.misc.Unsafe 的大部分 memory-access 相关的方法被标记 @Deprecated 了,以后会移除,类库的开发者需要额外注意下,可以用 JEP 193JEP 454 中提及的 API 替代。ps: 从 471 看,Java 的更新还是很克制的,充分考虑到老用户的兼容问题,但另一方面也可以看到 Java 的大体量对于新事物的推广还是很慢的,现在 Java 使用最多的版本还是 Java 8,我在面试候选人的时候一说起 Java 的新特性是 Lambda/Stream 流的时候就皱起了眉头 😂

      ​ 也可看看 foojay 上这篇对于 JDK 23 的解读文章。

    • Spring Boot CDS support and Project Leyden anticipation

      ​ 介绍了如何使用 Spring Boot 3.3 + CDS + Leydon + Spring Native 构建应用程序以显著减少 Spring Boot 应用的启动时间和运行时内存消耗,非常推荐看一看试一试。

    • Bending pause times to your will with Generational ZGC

      ​ Netflix 使用 JDK21 + 分代 ZGC 的实践,非常好,俺也想在生产环境试试 🐶

  • Go

    • How to implement Server-Sent Events in Go

      ​ SSE(Server-Sent Events) 是服务器向客户端不断发送 event 的单向通信协议(不同于 WebSocket 的双向通信 ),底层也是基于 HTTP,可以用于需要服务端实时生成内容的场景,如 ChatGPT 的流式相应等。

      ​ 这篇文章使用 go 的 net/http 实现了一个简单的 SSE 案例,可以看到 go 的基础类库还是很强大的,比 Java 要简洁很多。

      前不久使用 gin 框架也实现了 SSE:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      
      func ScriptRecognize(c *gin.Context) {
      	id := c.Param("id")
      	var record models.ScriptUploadRecord
      	err := models.FindOne(common.TB_SCRIPT, bson.M{"_id": bson.ObjectIdHex(id)}, nil, &record)
      	if err != nil {
      		c.JSON(http.StatusOK, helpers.Fail(err))
      		return
      	}
      	if len(record.Texts) > 0 {
      		txt := strings.Join(record.Texts, "")
      		c.Stream(func(w io.Writer) bool {
      			c.String(200, "data: %s\n\n", txt)
      			return false
      		})
      		return
      	}
      	chanStream := make(chan string, 100)
      	go recognizer.RecognizeFromUrl(record.FileUrl, chanStream)
      
      	content := make([]string, 0)
      	c.Header("Content-Type", "text/event-stream")
      	c.Header("X-Accel-Buffering", "no")
      	c.Stream(func(w io.Writer) bool {
      		if msg, ok := <-chanStream; ok {
      			fmt.Printf("转文本:%s", msg)
      			c.String(200, "data: %s\n\n", msg)
      			content = append(content, msg)
      			return true
      		}
      		go updateScript(id, "texts", content)
      		return false
      	})
      }
      

      ​ 主要注意的就是:1. header 的控制参数 2. event 发送的格式

    • Don’t defer Close() on writable files

      ​ 不要因为使用了 defer io.Closer.Close() 而忽略了后续操作系统因为 close syscall 不成功产生的 error ,建议用 return f.Close() –> os 还是不一定马上刷盘,或者 return f.Sync() –> 马上刷盘,严重影响性能。

    • Implementing Raft: Part 2 - Commands and Log Replication

      ​ 一个实现简单 raft 协议的国外教程的 Log Replication 部分,翔实的 test case 以及 log 可视化(html 表格对比形式)做的很好,要是做成动态可视化就更好了。

GitHub

Video

Book

This post is licensed under CC BY 4.0 by the author.