main.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package main
  2. import (
  3. "flag"
  4. "fmt"
  5. "github.com/go-kit/kit/log"
  6. "github.com/hashicorp/consul/api"
  7. "github.com/openzipkin/zipkin-go"
  8. zipkinhttpsvr "github.com/openzipkin/zipkin-go/middleware/http"
  9. zipkinhttp "github.com/openzipkin/zipkin-go/reporter/http"
  10. "math/rand"
  11. "net/http"
  12. "net/http/httputil"
  13. "os"
  14. "os/signal"
  15. "strings"
  16. "syscall"
  17. )
  18. func main() {
  19. // 创建环境变量
  20. var (
  21. consulHost = flag.String("consul.host", "114.67.98.210", "consul server ip address")
  22. consulPort = flag.String("consul.port", "8500", "consul server port")
  23. zipkinURL = flag.String("zipkin.url", "http://114.67.98.210:9411/api/v2/spans", "Zipkin server url")
  24. )
  25. flag.Parse()
  26. //创建日志组件
  27. var logger log.Logger
  28. {
  29. logger = log.NewLogfmtLogger(os.Stderr)
  30. logger = log.With(logger, "ts", log.DefaultTimestampUTC)
  31. logger = log.With(logger, "caller", log.DefaultCaller)
  32. }
  33. var zipkinTracer *zipkin.Tracer
  34. {
  35. var (
  36. err error
  37. hostPort = "localhost:9090"
  38. serviceName = "gateway-service"
  39. useNoopTracer = (*zipkinURL == "")
  40. reporter = zipkinhttp.NewReporter(*zipkinURL)
  41. )
  42. defer reporter.Close()
  43. zEP, _ := zipkin.NewEndpoint(serviceName, hostPort)
  44. zipkinTracer, err = zipkin.NewTracer(
  45. reporter, zipkin.WithLocalEndpoint(zEP), zipkin.WithNoopTracer(useNoopTracer),
  46. )
  47. if err != nil {
  48. logger.Log("err", err)
  49. os.Exit(1)
  50. }
  51. if !useNoopTracer {
  52. logger.Log("tracer", "Zipkin", "type", "Native", "URL", *zipkinURL)
  53. }
  54. }
  55. // 创建consul api客户端
  56. consulConfig := api.DefaultConfig()
  57. consulConfig.Address = "http://" + *consulHost + ":" + *consulPort
  58. consulClient, err := api.NewClient(consulConfig)
  59. if err != nil {
  60. logger.Log("err", err)
  61. os.Exit(1)
  62. }
  63. //创建反向代理
  64. proxy := NewReverseProxy(consulClient, zipkinTracer, logger)
  65. tags := map[string]string{
  66. "component": "gateway_server",
  67. }
  68. handler := zipkinhttpsvr.NewServerMiddleware(
  69. zipkinTracer,
  70. zipkinhttpsvr.SpanName("gateway"),
  71. zipkinhttpsvr.TagResponseSize(true),
  72. zipkinhttpsvr.ServerTags(tags),
  73. )(proxy)
  74. errc := make(chan error)
  75. go func() {
  76. c := make(chan os.Signal)
  77. signal.Notify(c, syscall.SIGINT, syscall.SIGTERM)
  78. errc <- fmt.Errorf("%s", <-c)
  79. }()
  80. //开始监听
  81. go func() {
  82. logger.Log("transport", "HTTP", "addr", "9090")
  83. errc <- http.ListenAndServe(":9090", handler)
  84. }()
  85. // 开始运行,等待结束
  86. logger.Log("exit", <-errc)
  87. }
  88. // NewReverseProxy 创建反向代理处理方法
  89. func NewReverseProxy(client *api.Client, zikkinTracer *zipkin.Tracer, logger log.Logger) *httputil.ReverseProxy {
  90. //创建Director
  91. director := func(req *http.Request) {
  92. //查询原始请求路径,如:/string-service/op/10/5
  93. reqPath := req.URL.Path
  94. if reqPath == "" {
  95. return
  96. }
  97. //按照分隔符'/'对路径进行分解,获取服务名称serviceName
  98. pathArray := strings.Split(reqPath, "/")
  99. serviceName := pathArray[1]
  100. //调用consul api查询serviceName的服务实例列表
  101. result, _, err := client.Catalog().Service(serviceName, "", nil)
  102. if err != nil {
  103. logger.Log("ReverseProxy failed", "query service instace error", err.Error())
  104. return
  105. }
  106. if len(result) == 0 {
  107. logger.Log("ReverseProxy failed", "no such service instance", serviceName)
  108. return
  109. }
  110. //重新组织请求路径,去掉服务名称部分
  111. destPath := strings.Join(pathArray[2:], "/")
  112. //随机选择一个服务实例
  113. tgt := result[rand.Int()%len(result)]
  114. logger.Log("service id", tgt.ServiceID)
  115. //设置代理服务地址信息
  116. req.URL.Scheme = "http"
  117. req.URL.Host = fmt.Sprintf("%s:%d", tgt.ServiceAddress, tgt.ServicePort)
  118. req.URL.Path = "/" + destPath
  119. }
  120. // 为反向代理增加追踪逻辑,使用如下RoundTrip代替默认Transport
  121. roundTrip, _ := zipkinhttpsvr.NewTransport(zikkinTracer, zipkinhttpsvr.TransportTrace(true))
  122. return &httputil.ReverseProxy{
  123. Director: director,
  124. Transport: roundTrip,
  125. }
  126. }