【发布时间】:2018-10-17 01:29:39
【问题描述】:
我正在尝试实现 http 服务器:
- 使用一些逻辑计算更远的重定向
- 重定向用户
- 记录用户数据
目标是实现最大吞吐量(至少 15k rps)。为了做到这一点,我想异步保存日志。我使用 kafka 作为日志系统,并将代码的日志块分离到单独的 goroutine 中。当前实现的总体示例:
package main
import (
"github.com/confluentinc/confluent-kafka-go/kafka"
"net/http"
"time"
"encoding/json"
)
type log struct {
RuntimeParam string `json:"runtime_param"`
AsyncParam string `json:"async_param"`
RemoteAddress string `json:"remote_address"`
}
var (
producer, _ = kafka.NewProducer(&kafka.ConfigMap{
"bootstrap.servers": "localhost:9092,localhost:9093",
"queue.buffering.max.ms": 1 * 1000,
"go.delivery.reports": false,
"client.id": 1,
})
topicName = "log"
)
func main() {
siteMux := http.NewServeMux()
siteMux.HandleFunc("/", httpHandler)
srv := &http.Server{
Addr: ":8080",
Handler: siteMux,
ReadTimeout: 2 * time.Second,
WriteTimeout: 5 * time.Second,
IdleTimeout: 10 * time.Second,
}
if err := srv.ListenAndServe(); err != nil {
panic(err)
}
}
func httpHandler(w http.ResponseWriter, r *http.Request) {
handlerLog := new(log)
handlerLog.RuntimeParam = "runtimeDataString"
http.Redirect(w, r, "http://google.com", 301)
go func(goroutineLog *log, request *http.Request) {
goroutineLog.AsyncParam = "asyncDataString"
goroutineLog.RemoteAddress = r.RemoteAddr
jsonLog, err := json.Marshal(goroutineLog)
if err == nil {
producer.ProduceChannel() <- &kafka.Message{
TopicPartition: kafka.TopicPartition{Topic: &topicName, Partition: kafka.PartitionAny},
Value: jsonLog,
}
}
}(handlerLog, r)
}
问题是:
- 使用单独的 goroutine 来实现异步日志记录是否正确/有效,或者我应该使用不同的方法? (例如工人和渠道)
- 也许有一种方法可以进一步提高服务器的性能,但我错过了?
【问题讨论】:
-
使用 goroutine 记录并没有本质上的错误——这实际上是对 goroutine 的一种很好的使用。你只需要小心数据竞争——确保你的
log和r变量不会同时更新。从您显示的代码中无法判断这里是否存在问题。您应该使用竞赛检测器运行测试以帮助发现此类问题。 -
不过,在进行设计时请考虑this。
-
感谢您的回复。这两个变量都只在它们的 gouroutines 中使用(从
r读取,写入log)并且它们没有外部变化。如果我理解正确 - 不应该有比赛条件?-race标志显示没有错误。 -
好吧,
r绝对不仅仅在那个 goroutine 中使用。该变量是从 http 服务器传入的。但除非您使用中间件或其他处理程序来延长该请求并对其进行修改,否则它应该是安全的。 -
-race显示没有错误是好的。但这并不是万无一失的。并不是所有的比赛都会在测试条件下触发,尤其是取决于你的测试是如何编写的。将-race视为至关重要的第一步,但不是最终决定。
标签: http asynchronous go apache-kafka goroutine