1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
| <?php
namespace App\Support;
use Monolog\Logger;
class RateMonitor { const KEY_NAME = 'rate_monitor'; const KEY_ALERT_COUNT = 'rate_alert'; const IN_SECOND = '1s'; const IN_MINUTE = '1m'; const IN_MINUTE_TEN = '10m'; const IN_HOUR = '1h'; const IN_DAY = '1d'; const DING_ROBOT = 'https://oapi.dingtalk.com/robot/send?access_token=5187cd15497ab1f440cb92c49eaf29e6477ec8786251ab00133d8a89b0ee7450';
const HASH_KEYS_EXPIRE = [ self::IN_SECOND => 1, self::IN_MINUTE => 60, self::IN_HOUR => 3600, self::IN_DAY => 86400, ];
protected $redis;
protected $logger;
public function __construct() { $this->logger = LogTool::getLogger('monitor', Logger::INFO, 'rate-monitor.log'); $this->redis = RedisTool::getInstance(); }
public function access(string $name, string $item, array $limit, callable $on_overflow = null) { $value = []; if (empty($item)) { $item = 'call'; }
foreach (self::HASH_KEYS_EXPIRE as $key => $expire) { $hash_key = self::KEY_NAME . "/$name/$item/$key"; $value[$key] = $this->redis->incr($hash_key); if (1 == $value[$key]) { $this->redis->expire($hash_key, $expire); } if (array_key_exists($key, $limit) && $limit[$key] < $value[$key]) { $this->logger->warn("$hash_key $value[$key] > $limit[$key]"); $alert_count = $this->redis->incr(self::KEY_ALERT_COUNT); if (1 == $alert_count) { $this->redis->expire(self::KEY_ALERT_COUNT, 600); } if ($alert_count % 20 == 1 && $alert_count > 1) { DingRobot::textMessage(self::DING_ROBOT, "10分钟内已经超频调用 $alert_count 次。"); } if ($on_overflow) { $on_overflow($value); } else { $this->responseAndExit(); } } } }
private function responseAndExit() { $msg = array( 'err' => 4000, 'msg' => '数据请求过于频繁, 请稍后再试', 'dat' => null, ); echo json_encode($msg); exit; }
public static function getInstance() { static $instance = null; if (null == $instance) { $instance = new static(); } return $instance; } }
|