面试题答案
一键面试网络延迟优化
- 超时控制:
- 使用
context.Context
来设置操作的超时时间。例如,在进行网络请求时:
package main import ( "context" "fmt" "net/http" "time" ) func main() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://example.com", nil) if err!= nil { fmt.Println("Error creating request:", err) return } resp, err := http.DefaultClient.Do(req) if err!= nil { fmt.Println("Error making request:", err) return } defer resp.Body.Close() }
- 这样如果网络请求在5秒内未完成,会自动取消,避免Goroutine无限期等待。
- 使用
- 异步I/O:
- 利用Go的
net.Conn
进行异步读写。例如,在一个简单的TCP服务器中:
package main import ( "fmt" "net" ) func handleConnection(conn net.Conn) { buffer := make([]byte, 1024) n, err := conn.Read(buffer) if err!= nil { fmt.Println("Read error:", err) return } fmt.Println("Received:", string(buffer[:n])) // 异步写回数据 go func() { _, err := conn.Write([]byte("Response from server")) if err!= nil { fmt.Println("Write error:", err) } }() } func main() { ln, err := net.Listen("tcp", ":8080") if err!= nil { fmt.Println("Listen error:", err) return } defer ln.Close() for { conn, err := ln.Accept() if err!= nil { fmt.Println("Accept error:", err) continue } go handleConnection(conn) } }
- 利用Go的
节点故障处理
- 心跳检测:
- 每个节点定期向其他节点发送心跳消息,以检测节点是否存活。例如:
package main import ( "fmt" "net" "time" ) func sendHeartbeat() { for { conn, err := net.Dial("tcp", "other - node:8081") if err!= nil { fmt.Println("Failed to send heartbeat:", err) } else { _, err := conn.Write([]byte("heartbeat")) if err!= nil { fmt.Println("Write heartbeat error:", err) } conn.Close() } time.Sleep(5 * time.Second) } } func main() { go sendHeartbeat() // 其他业务逻辑 select {} }
- 如果接收方在一定时间内未收到心跳,可判定发送方节点故障。
- 故障转移:
- 当检测到节点故障时,重新分配任务到其他节点。假设我们有一个任务分发的场景:
type Task struct { // 任务相关字段 } var taskQueue chan Task var nodes []string func distributeTask(task Task) { for _, node := range nodes { conn, err := net.Dial("tcp", node) if err == nil { // 发送任务到节点 _, err := conn.Write([]byte(task)) if err == nil { conn.Close() return } conn.Close() } } // 如果所有节点都失败,可将任务重新放入队列或采取其他策略 taskQueue <- task }
负载均衡优化
- 随机负载均衡:
- 从节点列表中随机选择一个节点来处理任务。例如:
package main import ( "fmt" "math/rand" "net" "time" ) var nodes = []string{"node1:8080", "node2:8080", "node3:8080"} func distributeTask(task string) { rand.Seed(time.Now().UnixNano()) index := rand.Intn(len(nodes)) node := nodes[index] conn, err := net.Dial("tcp", node) if err!= nil { fmt.Println("Failed to dial:", err) return } _, err = conn.Write([]byte(task)) if err!= nil { fmt.Println("Failed to send task:", err) } conn.Close() }
- 权重负载均衡:
- 根据节点的性能为每个节点分配权重,性能好的节点权重高,接收更多任务。例如:
type Node struct { address string weight int } var nodes = []Node{ {"node1:8080", 3}, {"node2:8080", 2}, {"node3:8080", 1}, } func distributeTask(task string) { totalWeight := 0 for _, node := range nodes { totalWeight += node.weight } rand.Seed(time.Now().UnixNano()) r := rand.Intn(totalWeight) sum := 0 for _, node := range nodes { sum += node.weight if r < sum { conn, err := net.Dial("tcp", node.address) if err!= nil { fmt.Println("Failed to dial:", err) return } _, err = conn.Write([]byte(task)) if err!= nil { fmt.Println("Failed to send task:", err) } conn.Close() break } } }