Rumah  >  Artikel  >  pembangunan bahagian belakang  >  Cara melaksanakan had harian pengguna dalam Go

Cara melaksanakan had harian pengguna dalam Go

藏色散人
藏色散人ke hadapan
2022-01-10 15:55:173210semak imbas

Artikel ini ditulis oleh ruangan tutorial golang untuk memperkenalkan cara melaksanakan had harian pengguna dalam Go. Saya harap ia dapat membantu rakan yang memerlukan.

Laksanakan had harian pengguna dalam Go (contohnya, anda hanya boleh menerima faedah tiga kali sehari)

Jika anda menulis sistem pengurusan pepijat dan menggunakan ini PeriodLimit anda hanya boleh mengehadkan setiap pepijat setiap hari. Adakah kerja lebih mudah? :P

Sebab penting mengapa seni bina perkhidmatan mikro begitu popular pada masa kini adalah untuk mengurangkan kerumitan keseluruhan sistem, mengagihkan risiko sistem secara sama rata kepada subsistem untuk memaksimumkan kestabilan sistem, dan membahagikannya kepada yang berbeza. kawasan melalui pembahagian domain Selepas subsistem dipasang, setiap subsistem boleh dibangunkan, diuji dan dikeluarkan secara bebas, dan rentak dan kecekapan P&P boleh dipertingkatkan dengan ketara.

Tetapi ia juga membawa masalah, seperti: pautan panggilan terlalu panjang, kerumitan seni bina pelaksanaan meningkat dan pelbagai perisian tengah perlu menyokong senario yang diedarkan. Untuk memastikan operasi normal perkhidmatan mikro, tadbir urus perkhidmatan adalah amat diperlukan, yang biasanya merangkumi: pengehadan semasa, penurunan taraf dan pemutus litar.

Penghadan semasa merujuk kepada mengehadkan kekerapan panggilan antara muka untuk mengelakkan melebihi had beban dan menjatuhkan sistem. Contohnya:

  • Senario jualan kilat e-dagang

  • Had semasa API untuk pedagang yang berbeza

Biasa digunakan Algoritma pengehad semasa ialah:

  • Penghadan arus tetingkap masa tetap
  • Penghadan arus tetingkap masa gelongsor
  • Penghad arus baldi bocor
  • Penstriman terhad baldi token

Artikel ini menerangkan terutamanya algoritma pengehadan semasa tetingkap masa tetap.

Prinsip Kerja

Bermula dari masa tertentu, setiap permintaan datang dengan kiraan permintaan 1. Pada masa yang sama, ia dinilai sama ada bilangan permintaan dalam tetingkap masa semasa melebihi had Jika ia melebihi had, permintaan itu kemudiannya dikosongkan apabila tetingkap masa berikutnya mula menunggu permintaan.

Cara melaksanakan had harian pengguna dalam Go

Kebaikan dan keburukan

Kelebihan

Mudah untuk melaksanakan Ia adalah cekap dan amat sesuai untuk mengehadkan senario seperti pengguna hanya boleh menghantar 10 artikel sehari, hanya boleh menghantar kod pengesahan SMS 5 kali, dan hanya boleh cuba log masuk 5 kali Senario sebegitu sangat biasa perniagaan.

Kelemahan

Kelemahan pengehadan arus tetingkap masa tetap ialah ia tidak dapat mengendalikan senario permintaan bahagian kritikal secara tiba-tiba.

Anggapkan bahawa had semasa ialah 100 permintaan setiap 1 saat, dan pengguna memulakan 200 permintaan dalam masa 1 saat bermula dari 500ms pertengahan Pada masa ini, semua 200 permintaan boleh diluluskan. Ini tidak konsisten dengan jangkaan kami untuk mengehadkan arus kepada 100 kali sesaat Puncanya ialah ketulusan had semasa adalah terlalu kasar.

Cara melaksanakan had harian pengguna dalam Go

perlaksanaan kod go-zero

core/limit/periodlimit.go

go-zero Gunakan masa tamat redis untuk mensimulasikan tetingkap masa tetap.

skrip redis lua:

-- KYES[1]:限流器key-- ARGV[1]:qos,单位时间内最多请求次数-- ARGV[2]:单位限流窗口时间-- 请求最大次数,等于p.quotalocal limit = tonumber(ARGV[1])-- 窗口即一个单位限流周期,这里用过期模拟窗口效果,等于p.permitlocal window = tonumber(ARGV[2])-- 请求次数+1,获取请求总数local current = redis.call("INCRBY",KYES[1],1)-- 如果是第一次请求,则设置过期时间并返回 成功if current == 1 then
  redis.call("expire",KYES[1],window)
  return 1-- 如果当前请求数量小于limit则返回 成功elseif current limit则返回 失败else
  return 0end

Takrifan pengehad semasa tetingkap masa tetap

type (
  // PeriodOption defines the method to customize a PeriodLimit.
  // go中常见的option参数模式
  // 如果参数非常多,推荐使用此模式来设置参数
  PeriodOption func(l *PeriodLimit)

  // A PeriodLimit is used to limit requests during a period of time.
  // 固定时间窗口限流器
  PeriodLimit struct {
    // 窗口大小,单位s
    period     int
    // 请求上限
    quota      int
    // 存储
    limitStore *redis.Redis
    // key前缀
    keyPrefix  string
    // 线性限流,开启此选项后可以实现周期性的限流
    // 比如quota=5时,quota实际值可能会是5.4.3.2.1呈现出周期性变化
    align      bool
  }
)

Beri perhatian untuk menjajarkan Parameter, apabila align=true, had atas permintaan akan berubah secara berkala.
Sebagai contoh, apabila kuota=5, kuota sebenar mungkin 5.4.3.2.1, menunjukkan perubahan berkala

Logik pengehad semasa

Malah, logik pengehad semasa berada di atas Skrip lua dilaksanakan Perlu diingat bahawa nilai pulangan

  • 0: menunjukkan ralat, seperti kegagalan redis atau beban berlebihan
  • 1: dibenarkan <.>
  • 2: dibenarkan Walau bagaimanapun, tetingkap semasa telah mencapai had atas Jika ia adalah perniagaan kelompok, anda boleh tidur dan menunggu tetingkap seterusnya (pengarang telah mempertimbangkannya dengan teliti)
  • 3: Penolakan
// Take requests a permit, it returns the permit state.
// 执行限流
// 注意一下返回值:
// 0:表示错误,比如可能是redis故障、过载
// 1:允许
// 2:允许但是当前窗口内已到达上限
// 3:拒绝
func (h *PeriodLimit) Take(key string) (int, error) {
  // 执行lua脚本
  resp, err := h.limitStore.Eval(periodScript, []string{h.keyPrefix + key}, []string{
    strconv.Itoa(h.quota),
    strconv.Itoa(h.calcExpireSeconds()),
  })

  if err != nil {
    return Unknown, err
  }

  code, ok := resp.(int64)
  if !ok {
    return Unknown, ErrUnknownCode
  }

  switch code {
  case internalOverQuota:
    return OverQuota, nil
  case internalAllowed:
    return Allowed, nil
  case internalHitQuota:
    return HitQuota, nil
  default:
    return Unknown, ErrUnknownCode
  }
}
Had semasa tetingkap tetap ini boleh digunakan untuk mengehadkan, contohnya, pengguna hanya boleh menghantar mesej teks kod pengesahan 5 kali sehari Pada masa ini, kita perlu sepadan dengan zon waktu Cina (GMT 8), dan sebenarnya, masa had semasa harus bermula dari sifar, pada masa ini Kami memerlukan penjajaran tambahan (set align to true).

// 计算过期时间也就是窗口时间大小
// 如果align==true
// 线性限流,开启此选项后可以实现周期性的限流
// 比如quota=5时,quota实际值可能会是5.4.3.2.1呈现出周期性变化
func (h *PeriodLimit) calcExpireSeconds() int {
  if h.align {
    now := time.Now()
    _, offset := now.Zone()
    unix := now.Unix() + int64(offset)
    return h.period - int(unix%int64(h.period))
  }

  return h.period
}
Alamat projek

github.com/zeromicro/go-zero

Selamat datang

dan go-zerobintang untuk menyokong kami!

Atas ialah kandungan terperinci Cara melaksanakan had harian pengguna dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:learnku.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam