dns_resolver.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package aws
  2. import (
  3. "container/list"
  4. "context"
  5. "net"
  6. "net/http"
  7. "sync"
  8. "time"
  9. )
  10. var DnsCacheTransport = &http.Transport{
  11. Proxy: http.ProxyFromEnvironment,
  12. DialContext: DnsCacheTransportDialContext(&net.Dialer{
  13. Timeout: 30 * time.Second,
  14. KeepAlive: 30 * time.Second,
  15. }, NewDnsResolver(100)),
  16. ForceAttemptHTTP2: true,
  17. MaxIdleConns: 100,
  18. IdleConnTimeout: 90 * time.Second,
  19. TLSHandshakeTimeout: 10 * time.Second,
  20. ExpectContinueTimeout: 1 * time.Second,
  21. }
  22. func DnsCacheTransportDialContext(dialer *net.Dialer, resolver *DnsResolver) func(context.Context, string, string) (net.Conn, error) {
  23. return func(ctx context.Context, network, address string) (net.Conn, error) {
  24. conn, err := dialer.DialContext(ctx, network, address)
  25. if err != nil {
  26. remoteAddr, exists := resolver.cache.Get(address)
  27. if exists {
  28. return dialer.DialContext(ctx, network, remoteAddr)
  29. }
  30. return conn, err
  31. }
  32. if conn.RemoteAddr().String() != "" {
  33. resolver.cache.Set(address, conn.RemoteAddr().String())
  34. }
  35. return conn, err
  36. }
  37. }
  38. type DnsResolver struct {
  39. cache *FIFOCache
  40. }
  41. // NewDnsResolver 创建一个新的 DNS 解析器,使用固定长度的 FIFO 缓存
  42. func NewDnsResolver(maxSize int) *DnsResolver {
  43. return &DnsResolver{
  44. cache: NewFIFOCache(maxSize),
  45. }
  46. }
  47. // FIFOCache 实现一个固定大小的并发安全FIFO(先进先出)缓存
  48. // 当缓存满时,添加新条目会自动淘汰最早插入的条目
  49. type FIFOCache struct {
  50. maxSize int // 缓存的最大容量
  51. cache map[string]string // 存储键值对的映射
  52. keys *list.List // 使用链表维护键的插入顺序(FIFO)
  53. rwMutex sync.RWMutex // 读写锁,保证并发安全
  54. }
  55. // NewFIFOCache 创建并返回一个新的FIFOCache实例
  56. // 参数:
  57. //
  58. // maxSize: 缓存的最大容量,必须大于0,否则默认为100
  59. //
  60. // 返回值:
  61. //
  62. // *FIFOCache: 新创建的缓存实例
  63. func NewFIFOCache(maxSize int) *FIFOCache {
  64. if maxSize < 1 {
  65. maxSize = 100
  66. }
  67. return &FIFOCache{
  68. maxSize: maxSize,
  69. cache: make(map[string]string),
  70. keys: list.New(),
  71. }
  72. }
  73. // Set 添加或更新一个键值对到缓存中
  74. // 如果缓存已满且键不存在,会淘汰最早插入的条目
  75. // 参数:
  76. //
  77. // key: 要添加或更新的键
  78. // value: 要添加或更新的值
  79. //
  80. // 返回值:
  81. //
  82. // string: 如果键已存在,返回被替换的旧值;否则返回空字符串
  83. // bool: 表示是否替换了现有值(true表示替换,false表示新增)
  84. func (c *FIFOCache) Set(key, value string) (string, bool) {
  85. c.rwMutex.Lock()
  86. defer c.rwMutex.Unlock()
  87. // 检查键是否已存在
  88. oldValue, exists := c.cache[key]
  89. if exists {
  90. // 更新现有键的值
  91. c.cache[key] = value
  92. return oldValue, true
  93. }
  94. // 缓存已满,淘汰最旧的条目
  95. if c.keys.Len() >= c.maxSize {
  96. oldest := c.keys.Front()
  97. if oldest != nil {
  98. oldestKey := oldest.Value.(string)
  99. delete(c.cache, oldestKey)
  100. c.keys.Remove(oldest)
  101. }
  102. }
  103. // 添加新条目
  104. c.cache[key] = value
  105. c.keys.PushBack(key)
  106. return "", false
  107. }
  108. // Get 从缓存中获取指定键对应的值
  109. // 参数:
  110. //
  111. // key: 要查找的键
  112. //
  113. // 返回值:
  114. //
  115. // string: 找到的值(如果键不存在则返回空字符串)
  116. // bool: 表示键是否存在(true表示存在,false表示不存在)
  117. func (c *FIFOCache) Get(key string) (string, bool) {
  118. c.rwMutex.RLock()
  119. defer c.rwMutex.RUnlock()
  120. value, exists := c.cache[key]
  121. return value, exists
  122. }
  123. // Size 返回缓存中当前存储的条目数量
  124. // 返回值:
  125. //
  126. // int: 当前缓存中的条目数量
  127. func (c *FIFOCache) Size() int {
  128. c.rwMutex.RLock()
  129. defer c.rwMutex.RUnlock()
  130. return len(c.cache)
  131. }
  132. // GetMaxSize 返回缓存的最大容量
  133. // 返回值:
  134. //
  135. // int: 缓存的最大容量
  136. func (c *FIFOCache) GetMaxSize() int {
  137. return c.maxSize
  138. }