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

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

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

  1. WARNING: DATA RACE
  2. Write by goroutine 18:
  3. runtime.mapassign1()
  4. c:/go/src/runtime/hashmap.go:383 +0x0
  5. net/textproto.MIMEHeader.Set()
  6. c:/go/src/net/textproto/header.go:22 +0xf4
  7. net/http.Header.Set()
  8. c:/go/src/net/http/header.go:31 +0x64
  9. project/middlewares/session.(*ctrl).setHttpHeader()
  10. D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x9d
  11. project/middlewares/session.(*ctrl).evaluateJwt()
  12. D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
  13. project/middlewares/session.(*ctrl).serveHttp()
  14. D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
  15. project/middlewares/session.func┬À006()
  16. D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x
  17. Previous write by goroutine 17:
  18. runtime.mapassign1()
  19. c:/go/src/runtime/hashmap.go:383 +0x0
  20. net/textproto.MIMEHeader.Add()
  21. c:/go/src/net/textproto/header.go:15 +0x212
  22. net/http.Header.Add()
  23. c:/go/src/net/http/header.go:24 +0x64
  24. github.com/unrolled/secure.(*Secure).Process()
  25. D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe5b
  26. project/middlewares/security.func┬À001()
  27. D:/gocode/src/project/middlewares/security/serve_http.go:33 +0
  28. Goroutine 18 (running) created at:
  29. project/middlewares/session.ServeHttp()
  30. D:/gocode/src/project/middlewares/session/serve_http.go:29 +0x
  31. project/middlewares.New()
  32. D:/gocode/src/project/middlewares/ctrl.go:12 +0x99
  33. github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
  34. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
  35. github.com/codegangsta/negroni.middleware.ServeHTTP()
  36. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  37. github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
  38. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  39. github.com/codegangsta/negroni.(*Static).ServeHTTP()
  40. D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
  41. github.com/codegangsta/negroni.middleware.ServeHTTP()
  42. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  43. github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
  44. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  45. github.com/codegangsta/negroni.(*Logger).ServeHTTP()
  46. D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
  47. github.com/codegangsta/negroni.middleware.ServeHTTP()
  48. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  49. github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
  50. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  51. github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
  52. D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
  53. github.com/codegangsta/negroni.middleware.ServeHTTP()
  54. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  55. github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
  56. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
  57. net/http/httptest.(*waitGroupHandler).ServeHTTP()
  58. c:/go/src/net/http/httptest/server.go:200 +0xfe
  59. net/http.serverHandler.ServeHTTP()
  60. c:/go/src/net/http/server.go:1703 +0x1fd
  61. net/http.(*conn).serve()
  62. c:/go/src/net/http/server.go:1204 +0x108e
  63. Goroutine 17 (finished) created at:
  64. project/middlewares/security.ServeHttp()
  65. D:/gocode/src/project/middlewares/security/serve_http.go:37 +0
  66. project/middlewares.New()
  67. D:/gocode/src/project/middlewares/ctrl.go:12 +0x64
  68. github.com/codegangsta/negroni.HandlerFunc.ServeHTTP()
  69. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:24 +0x5f
  70. github.com/codegangsta/negroni.middleware.ServeHTTP()
  71. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  72. github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
  73. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  74. github.com/codegangsta/negroni.(*Static).ServeHTTP()
  75. D:/gocode/src/github.com/codegangsta/negroni/static.go:30 +0xb71
  76. github.com/codegangsta/negroni.middleware.ServeHTTP()
  77. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  78. github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
  79. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  80. github.com/codegangsta/negroni.(*Logger).ServeHTTP()
  81. D:/gocode/src/github.com/codegangsta/negroni/logger.go:25 +0x249
  82. github.com/codegangsta/negroni.middleware.ServeHTTP()
  83. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  84. github.com/codegangsta/negroni.middleware.ServeHTTP┬Àfm()
  85. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x84
  86. github.com/codegangsta/negroni.(*Recovery).ServeHTTP()
  87. D:/gocode/src/github.com/codegangsta/negroni/recovery.go:45 +0xd9
  88. github.com/codegangsta/negroni.middleware.ServeHTTP()
  89. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:33 +0x114
  90. github.com/codegangsta/negroni.(*Negroni).ServeHTTP()
  91. D:/gocode/src/github.com/codegangsta/negroni/negroni.go:73 +0x1c7
  92. net/http/httptest.(*waitGroupHandler).ServeHTTP()
  93. c:/go/src/net/http/httptest/server.go:200 +0xfe
  94. net/http.serverHandler.ServeHTTP()
  95. c:/go/src/net/http/server.go:1703 +0x1fd
  96. net/http.(*conn).serve()
  97. c:/go/src/net/http/server.go:1204 +0x108e
  98. ==================
  99. 2015/02/03 15:05:31 ctrl.go:17: End of process middlewares
  100. 2015/02/03 15:05:31 funcs.go:10: Create new user
  101. 2015/02/03 15:05:31 validate.go:14: Validate email thompson@example.com
  102. 2015/02/03 15:05:31 validate.go:100: Validate password Test!1234
  103. 2015/02/03 15:05:31 validate.go:52: Validate name: ValidName
  104. 2015/02/03 15:05:31 create.go:120: Done
  105. [negroni] Completed 0 in 197ms
  106. PASS
  107. ok project/testing/account_test 0.664s
  108. PS D:\gocode\src\project\testing\account_test> go test -race
  109. 2015/02/03 15:08:10 vs.go:50: Connect to neo4j db.
  110. [negroni] Started POST /user
  111. ==================
  112. WARNING: DATA RACE
  113. Write by goroutine 18:
  114. net/http.(*response).Header()
  115. c:/go/src/net/http/server.go:615 +0x11a
  116. github.com/codegangsta/negroni.(*responseWriter).Header()
  117. <autogenerated>:42 +0x78
  118. project/middlewares/session.(*ctrl).setHttpHeader()
  119. D:/gocode/src/project/middlewares/session/ctrl.go:76 +0x68
  120. project/middlewares/session.(*ctrl).evaluateJwt()
  121. D:/gocode/src/project/middlewares/session/ctrl.go:56 +0x31a
  122. project/middlewares/session.(*ctrl).serveHttp()
  123. D:/gocode/src/project/middlewares/session/ctrl.go:94 +0x8a
  124. project/middlewares/session.func┬À006()
  125. D:/gocode/src/project/middlewares/session/serve_http.go:23 +0x
  126. Previous write by goroutine 17:
  127. net/http.(*response).Header()
  128. c:/go/src/net/http/server.go:615 +0x11a
  129. github.com/codegangsta/negroni.(*responseWriter).Header()
  130. <autogenerated>:42 +0x78
  131. github.com/unrolled/secure.(*Secure).Process()
  132. D:/gocode/src/github.com/unrolled/secure/secure.go:177 +0xe24
  133. project/middlewares/security.func┬À001()
  134. D:/gocode/src/project/middlewares/security/serve_http.go:33 +0

I use negroni to process middlwares works.

The way, how I process middlwares

  1. func New(res http.ResponseWriter, req *http.Request, next http.HandlerFunc) {
  2. if err := process(security.ServeHttp(res, req), session.ServeHttp(res, req)); err != nil {
  3. res.WriteHeader(http.StatusInternalServerError)
  4. return
  5. }
  6. log.Println("End of process middlewares")
  7. next(res, req)
  8. }
  9. // Process all middlewares
  10. func process(chErrs ...<-chan error) error {
  11. for _, chErr := range chErrs {
  12. // Will abort the loop, when error occurs
  13. if err := <-chErr; err != nil {
  14. return err
  15. }
  16. }
  17. return nil
  18. }

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

  1. func Config() *negroni.Negroni {
  2. n := negroni.Classic()
  3. n.Use(negroni.HandlerFunc(middlewares.New))
  4. n.UseHandler(routes.Set())
  5. return n
  6. }

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:

确定