很多数据竞争的网络应用程序

huangapple go评论76阅读模式
英文:

A lot of data race web application

问题

根据你提供的信息,中间件可能是导致数据竞争的原因之一。数据竞争通常发生在多个goroutine同时访问和修改共享数据时。在你的代码中,不同的中间件在处理请求时可能会同时访问和修改响应的Header。这可能导致数据竞争。

为了解决这个问题,你可以考虑使用互斥锁(Mutex)或其他同步机制来保护共享数据,确保在同一时间只有一个goroutine可以访问和修改它。另外,你还可以检查中间件的实现,确保它们在处理请求时没有产生竞争条件。

此外,你还可以使用Go语言的竞争检测工具(如go run -race或go test -race)来帮助你发现和解决数据竞争问题。这些工具可以在运行时检测到潜在的竞争条件,并提供相关的报告和调试信息。

总之,中间件可能是导致数据竞争的原因之一。你可以通过使用同步机制和竞争检测工具来解决这个问题。

英文:

I am writing a web application. Incoming requests will pass through middlewares first. At the moment, I've added two middlwares session and security.
After walked through middlwares, it will execute the handler for the request.
Session and security middlwares will execute in their own goroutine.

When I am testing I've got a lot of data race, specially in middlware section

WARNING: DATA RACE
Write by goroutine 18:
  runtime.mapassign1()
      c:/go/src/runtime/hashmap.go:383 +0x0
  net/textproto.MIMEHeader.Set()
      c:/go/src/net/textproto/header.go:22 +0xf4
  net/http.Header.Set()
      c:/go/src/net/http/header.go:31 +0x64
  project/middlewares/session.(*ctrl).setHttpHeader()
      D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x9d
  project/middlewares/session.(*ctrl).evaluateJwt()
      D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
  project/middlewares/session.(*ctrl).serveHttp()
      D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
  project/middlewares/session.func┬À006()
      D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x

Previous write by goroutine 17:
  runtime.mapassign1()
      c:/go/src/runtime/hashmap.go:383 +0x0
  net/textproto.MIMEHeader.Add()
      c:/go/src/net/textproto/header.go:15 +0x212
  net/http.Header.Add()
      c:/go/src/net/http/header.go:24 +0x64
  github.com/unrolled/secure.(*Secure).Process()
      D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe5b
  project/middlewares/security.func┬À001()
      D:/gocode/src/project/middlewares/security/serve_http.go:33 +0

Goroutine 18 (running) created at:
  project/middlewares/session.ServeHttp()
      D:/gocode/src/project/middlewares/session/serve_http.go:29 +0x
  project/middlewares.New()
      D:/gocode/src/project/middlewares/ctrl.go:12 +0x99
  github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Static).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Logger).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
  net/http/httptest.(*waitGroupHandler).ServeHTTP()
      c:/go/src/net/http/httptest/server.go:200 +0xfe
  net/http.serverHandler.ServeHTTP()
      c:/go/src/net/http/server.go:1703 +0x1fd
  net/http.(*conn).serve()
      c:/go/src/net/http/server.go:1204 +0x108e

Goroutine 17 (finished) created at:
  project/middlewares/security.ServeHttp()
      D:/gocode/src/project/middlewares/security/serve_http.go:37 +0
  project/middlewares.New()
      D:/gocode/src/project/middlewares/ctrl.go:12 +0x64
  github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Static).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Logger).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
  github.com/codegangsta/negroni.middleware.ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
      D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
  net/http/httptest.(*waitGroupHandler).ServeHTTP()
      c:/go/src/net/http/httptest/server.go:200 +0xfe
  net/http.serverHandler.ServeHTTP()
      c:/go/src/net/http/server.go:1703 +0x1fd
  net/http.(*conn).serve()
      c:/go/src/net/http/server.go:1204 +0x108e
==================
2015/02/03 15:05:31 ctrl.go:17: End of process middlewares
2015/02/03 15:05:31 funcs.go:10: Create new user
2015/02/03 15:05:31 validate.go:14: Validate email thompson@example.com
2015/02/03 15:05:31 validate.go:100: Validate password Test!1234
2015/02/03 15:05:31 validate.go:52: Validate name:  ValidName
2015/02/03 15:05:31 create.go:120: Done
[negroni] Completed 0  in 197ms
PASS
ok      project/testing/account_test 0.664s
PS D:\gocode\src\project\testing\account_test> go test -race
2015/02/03 15:08:10 vs.go:50: Connect to neo4j db.
[negroni] Started POST /user
==================
WARNING: DATA RACE
Write by goroutine 18:
  net/http.(*response).Header()
      c:/go/src/net/http/server.go:615 +0x11a
  github.com/codegangsta/negroni.(*responseWriter).Header()
      <autogenerated>:42 +0x78
  project/middlewares/session.(*ctrl).setHttpHeader()
      D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x68
  project/middlewares/session.(*ctrl).evaluateJwt()
      D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
  project/middlewares/session.(*ctrl).serveHttp()
      D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
  project/middlewares/session.func┬À006()
      D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x

Previous write by goroutine 17:
  net/http.(*response).Header()
      c:/go/src/net/http/server.go:615 +0x11a
  github.com/codegangsta/negroni.(*responseWriter).Header()
      <autogenerated>:42 +0x78
  github.com/unrolled/secure.(*Secure).Process()
      D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe24
  project/middlewares/security.func┬À001()
      D:/gocode/src/project/middlewares/security/serve_http.go:33 +0

I use negroni to process middlwares works.

The way, how I process middlwares

func New(res http.ResponseWriter, req *http.Request, next http.HandlerFunc) {

	if err := process(security.ServeHttp(res, req), session.ServeHttp(res, req)); err != nil {
		res.WriteHeader(http.StatusInternalServerError)
		return
	}

	log.Println("End of process middlewares")
	next(res, req)

}

// Process all middlewares
func process(chErrs ...<-chan error) error {

	for _, chErr := range chErrs {

		// Will abort the loop, when error occurs
		if err := <-chErr; err != nil {
			return err
		}

	}
	return nil
}

As you can see, every middlware have they own channel. The for statement will loop until the error channel is closed or error send.

The server configuration

func Config() *negroni.Negroni {
	n := negroni.Classic()
	n.Use(negroni.HandlerFunc(middlewares.New))
	n.UseHandler(routes.Set())
	return n

}

My question is, are the middlewares the reason, why I've got the data race?

答案1

得分: 1

你在goroutine中运行中间件是问题的原因。

如果你想并行运行你的中间件,你需要在任何在goroutine中执行的中间件写入的内存周围设置一个互斥锁(mutex)。

在你的特定情况下,你既写入又读取ResponseWriterHeader

英文:

It's the fact that you're running the middleware within a goroutine that is the problem.

If you want to run your middleware in parallel you will have to set up a mutex around the memory that is written to by any middleware executed within a goroutine.

In your particular case you are both writing and reading from the ResponseWriter's Header

huangapple
  • 本文由 发表于 2015年2月3日 22:32:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/28301402.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定