1. GitHub 中的每个分支代码都是可以跑起来的,我本人亲测过了。出现这个问题,可能是因为有的同学只使用 go run main.go。go run main.go 只会运行编译运行的指定文件,而一旦当前目录下有其他文件,就不会运行到了,所以比如在 geekbang/02 或者 geekbang/03 分支中,根目录下有其他文件,就不能运行了。你需要使用 go build 先编译,然后使用./coredemo 来运行。
    2. 一般最多由两个点组成,其中 1 叫做 major version,主版本,非常大的改动的时候才会升级这个版本。而 2 叫做 minor version,表示有一些接口级别的增加,但是会保证向后兼容,才会升级这个版本。而 3 叫做 patch version,顾名思义,一些不影响接口,但是打了一些补丁和修复的版本。而最后的 pre 叫做 pre-release suffix。可以理解是和 beta 版本一样的概念,在 release 版本出现之前,预先投放在市场的试用版本。所以 go mod 中的格式只能允许 major version 和 minor version。它认为,使用者关注这两个版本号就行,这样能保证使用者在使用 golang 标准库的时候,源码接口并没有增加和修改,不管你使用什么 patch version,你的业务代码都能跑起来。
    3. 思维导图怎么画?

      我提供一个思路,在使用思维导图的时候,对于比较复杂的逻辑,我们要在头脑中模拟一下,要实现这个逻辑,哪些是关键步骤,然后用寻找这些关键步骤的方法来去源码中阅读。比如 FileServer,是用来实现静态文件服务器的,首先我们先在头脑中有个模拟,我要先对接上 ServerHTTP 方法,然后要把判断请求路径,要是请求的是文件,那么我就把文件内容拷贝到请求输出中不就行了么。

    4. http.Server 源码为什么是两层循环?go c.serve(connCtx) 里面为什么还有一个循环?c 指的是一个 connection,我理解不是每个连接处理一次就好了吗,为啥还有一个 for 循环呢?

    HTTP 的 keep-alive 机制。HTTP 层有个 keep-alive,它主要是用于客户端告诉服务端,这个连接我还会继续使用,在使用完之后不要关闭。性能,服务器 TIME_WAIT 的时间
    它判断如果服务端的 disableKeepAlives 不是 0,则设置了关闭 keep-alive,就不进行 for 循环了。
    // 判断是否开启keep-alivefunc (s *Server) doKeepAlives() bool { // 如果没开keep-alive,或者在shutdown过程中,就返回false return atomic.LoadInt32(&s.disableKeepAlives) == 0 && !s.shuttingDown()}

    1. 为什么 context 作为函数的第一个参数?

    链路通用内容传递。链路统一设置超时。

    1. 服务雪崩 case 有哪些?

    超时设置不合理(服务雪崩最常见的就是下游服务没设置超时,导致上游服务不可用,也是我们设置 Context 的原因)。
    重试加大流量(我们在下游调用的时候,经常会使用重试机制来防止网络抖动问题,但是重试机制一旦使用不合理,也有可能导致下游服务的不可用)。
    缓存雪崩(缓存雪崩顾名思义就是,原本应该打在缓存中的请求全部绕开缓存,打到了 DB,从而导致 DB 不可用,而 DB 作为一个下游服务节点,不可用会导致上游都出现雪崩效应)。

    1. 缓存雪崩?

    被攻击在平时写代码中我们日常使用这样的逻辑:“根据请求中的某个值建立 key 去缓存中获取,获取不到就去数据库中获取”。但是这种逻辑其实很容易被攻击者利用,攻击者只需要建立大量非合理的 key,就可以打穿缓存进入数据库进行请求。请求量只要足够大,就可以导致绕过缓存,让数据库不可用。
    2. 缓存瞬时失效“通过第一个请求建立缓存,建立之后一段时间后失效”。这也是一个经常出现瞬时缓存雪崩的原因。因为有可能在第一次批量建立了缓存后,进行业务逻辑,而后续并没有更新缓存时长,那就可能导致批量在统一时间内缓存失效。缓存失效后大批量的请求会涌入后端数据库,导致数据库不可用。
    3. 缓存热 key还有一种情况是缓存中的某个 key 突然有大批量的请求涌入,而缓存的分布式一般是按照 key 进行节点分布的。这样会导致某个缓存服务节点流量过于集中,不可用。而缓存节点不可用又会导致大批量的请求穿透缓存进入数据库,导致数据库不可用。