Pembelajaran yang disyorkan: Tutorial video Redis
Kami di sini Apabila menggunakan kunci diedarkan Redis, semua orang tahu bahawa ia bergantung pada arahan setnx Semasa operasi CAS (Banding dan tukar), amalan tamat tempoh (tamat tempoh) ditetapkan untuk kunci yang ditentukan benarkan hanya N bilangan permintaan untuk mengakses program kod saya dalam masa unit. Jadi bergantung pada setnx boleh mencapai fungsi ini dengan mudah.
Sebagai contoh, jika kita perlu mengehadkan 20 permintaan dalam masa 10 saat, maka kita boleh menetapkan masa tamat tempoh kepada 10 semasa setnx Apabila bilangan setnx yang diminta mencapai 20, kesan pengehadan semasa akan dicapai. Kod ini agak mudah dan tidak akan ditunjukkan.
Sudah tentu, terdapat banyak kelemahan untuk pendekatan ini, contohnya, apabila mengira 1-10 saat, adalah mustahil untuk mengira 2-11 saat. Jika anda perlu mengira permintaan M dalam masa N saat Redis Perlu mengekalkan kunci N dan isu lain.
Dalam pelaksanaan khusus, anda boleh mempertimbangkan untuk menggunakan pemintas HandlerInterceptor:
public class RequestCountInterceptor implements HandlerInterceptor { private LimitPolicy limitPolicy; public RequestCountInterceptor(LimitPolicy limitPolicy) { this.limitPolicy = limitPolicy; } @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (!limitPolicy.canDo()) { return false; } return true; } }
Pada masa yang sama, tambahkan konfigurasi LimitConfiguration:
@Configuration public class LimitConfiguration implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RequestCountInterceptor(new RedisLimit1())).addPathPatterns("/my/increase"); } }
Dengan cara ini setiap kali dalam /my/ Sebelum permintaan peningkatan mencapai Pengawal, arus dihadkan mengikut dasar RedisLimit1 Kod asal dalam Pengawal tidak perlu diubah suai:
@RestController @RequestMapping("my") public class MyController { int i = 0; @RequestMapping("/increase") public int increase() { return i++; } }
Kod logik pengehad arus tertentu. berada dalam kelas RedisLimit1:
/** * 方法一:基于Redis的setnx的操作 */ public class RedisLimit1 extends LimitPolicy { static { setNxExpire(); } private static boolean setNxExpire() { SetParams setParams = new SetParams(); setParams.nx(); setParams.px(TIME); String result = jedis.set(KEY, COUNT + "", setParams); if (SUCCESS.equals(result)) { return true; } return false; } @Override public boolean canDo() { if (setNxExpire()) { //设置成功,说明原先不存在,成功设置为COUNT return true; } else { //设置失败,说明已经存在,直接减1,并且返回 return jedis.decrBy(KEY, 1) > 0; } } } public abstract class LimitPolicy { public static final int COUNT = 10; //10 request public static final int TIME= 10*1000 ; // 10s public static final String SUCCESS = "OK"; static Jedis jedis = new Jedis(); abstract boolean canDo(); }
Satu kesan yang dicapai dengan cara ini ialah meminta sehingga 10 kali sesaat.
Malah, perkara paling penting yang terlibat dalam pengehadan semasa ialah tetingkap gelongsor Ia juga disebut di atas bagaimana 1-10 menjadi 2-11 . Malah, nilai permulaan dan nilai akhir adalah kedua-duanya 1.
Jika kami menggunakan struktur data senarai Redis, kami boleh melaksanakan fungsi ini dengan mudah
Kami boleh mencipta permintaan ke dalam tatasusunan zset Apabila setiap permintaan masuk, nilainya kekal unik dan boleh dijana menggunakan UUID, dan skor Ia boleh diwakili oleh cap masa semasa, kerana skor boleh digunakan untuk mengira bilangan permintaan dalam cap masa semasa. Struktur data zset juga menyediakan kaedah zrange supaya kita boleh mendapatkan bilangan permintaan dengan mudah dalam 2 cap masa
/** * 方法二:基于Redis的数据结构zset */ public class RedisLimit2 extends LimitPolicy { public static final String KEY2 = "LIMIT2"; @Override public boolean canDo() { Long currentTime = new Date().getTime(); System.out.println(currentTime); if (jedis.zcard(KEY2) > 0) { // 这里不能用get判断,会报错:WRONGTYPE Operation against a key holding the wrong kind of value Integer count = jedis.zrangeByScore(KEY2, currentTime - TIME, currentTime).size(); // 注意这里使用zrangeByScore,以时间作为score。zrange key start stop 命令的start和stop是序号。 System.out.println(count); if (count != null && count > COUNT) { return false; } } jedis.zadd(KEY2, Double.valueOf(currentTime), UUID.randomUUID().toString()); return true; } }
Kod di atas boleh mencapai kesan tetingkap gelongsor dan memastikan setiap N Terdapat paling banyak. M permintaan sesaat Kelemahannya ialah struktur data zset akan menjadi lebih besar dan lebih besar. Kaedah pelaksanaannya agak mudah.
Mengenai pengehadan semasa, kita perlu menyebut algoritma baldi token. Algoritma baldi token menyebut kadar input dan kadar keluaran Apabila kadar keluaran lebih besar daripada kadar input, had trafik melebihi. Maksudnya, setiap kali kita mengakses permintaan, kita boleh mendapatkan token dari Redis Jika kita mendapat token, itu bermakna bahawa had itu tidak melebihinya.
Bergantung pada idea di atas, kami boleh melaksanakan kod tersebut dengan mudah dengan menggabungkan struktur data Senarai Redis Ia hanyalah pelaksanaan mudah yang bergantung pada Pop kiri untuk mendapatkan token.
Mula-mula konfigurasikan tugas berjadual dan masukkan token setiap saat melalui kaedah rpush senarai redis:
@Configuration //1.主要用于标记配置类,兼备Component的效果。 @EnableScheduling // 2.开启定时任务 public class SaticScheduleTask { //3.添加定时任务 @Scheduled(fixedRate = 1000) private void configureTasks() { LimitPolicy.jedis.rpush("LIMIT3", UUID.randomUUID().toString()); } }
Apabila mengehadkan, dapatkan token yang sepadan daripada redis melalui kaedah lpop bagi senarai Token, jika berjaya diperolehi, permintaan boleh dilaksanakan:
/** * 方法三:令牌桶 */ public class RedisLimit3 extends LimitPolicy { public static final String KEY3 = "LIMIT3"; @Override public boolean canDo() { Object result = jedis.lpop(KEY3); if (result == null) { return false; } return true; } }
Pembelajaran yang disyorkan: Tutorial video Redis
Atas ialah kandungan terperinci Tiga cara untuk melaksanakan pengehad semasa dalam Redis (perkongsian ringkasan). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!