> 데이터 베이스 > Redis > Redis 실제 전투 제한 작동 빈도

Redis 실제 전투 제한 작동 빈도

步履不停
풀어 주다: 2019-06-26 17:00:16
원래의
2780명이 탐색했습니다.

Redis 실제 전투 제한 작동 빈도

저는 최근 비즈니스 개발에 푹 빠져 한동안 블로그를 업데이트하지 않았습니다. 이전 블로그 게시물에서는 비즈니스 시나리오의 실용적인 솔루션이나 더 나은 디자인 아이디어를 공유할 계획입니다. 한 주제에 초점을 맞춘 글이라 관련 내용을 정리하는 데 시간이 많이 걸립니다(큰 트릭을 억제함). 후속 기사의 내용은 그다지 풍부하지 않을 수 있지만, 이에 대한 좀 더 자세하고 심층적인 분석을 시도해보세요. 원포인트, 지속적인 공유와 자체 검토를 통해 경험을 축적하고 블로그 공유 빈도를 높여보세요

Scenario

시나리오 1

留言功能限制,30秒 内只能评论 10次,超出次数不让能再评论,并提示:过于频繁
로그인 후 복사

시나리오 2

点赞功能限制,10秒 内只能点赞 10次,超出次数后不能再点赞,并禁止操作 1个小时,提示:过于频繁,被禁止操作1小时
로그인 후 복사

시나리오 3

上传记录功能,限制一天只能上传 100次,超出次数不让能再上传,并提示:超出今日上线
로그인 후 복사

본질을 분리

하는 과정에서 비즈니스 개발에 지속적으로 참여합니다. 다양한 비즈니스 시나리오에 대한 솔루션을 설계할 때 매우 유사한 시나리오에 직면하기 쉬운 경우가 많지만 실제로 이러한 요구 사항의 본질은 동일한 문제에 직면할 때 발생합니다. 그러한 시나리오에서는 자신의 경험을 바탕으로 수요의 본질적인 문제를 분석하고 추출하고, 보편적인 솔루션을 구현하고, 솔루션을 더욱 가치있게 만들어야 합니다. 이것이 영혼을 가진 엔지니어인지 아니면 영혼을 가진 엔지니어인지의 차이일 수 있습니다. 최강 CP(복사 붙여넣기) 왕.

위의 세 가지 비즈니스 시나리오를 분석하면 유사한 문제라고 부르는 유사한 논리가 있음을 알 수 있습니다. 이제 이 문제를 분리하고 일반적인 솔루션을 설계하고 동일한 논리 흐름도를 개략적으로 설명하겠습니다.

Redis 실제 전투 제한 작동 빈도

위의 수요 시나리오를 분석하여 필요한 모든 조건을 추출합니다.

제한된 개체: 사용자 제한 작업(댓글, 좋아요, 기록 등) 제한 작업 수가 X초 범위 내에서 Y회를 초과합니다. 금지된 작업 시간 Z(초/특정 시간)을 초과한 후에는 더 이상 작업이 허용되지 않으며 프롬프트

Redis 실제 전투 제한 작동 빈도

(最小时间单位用秒:天/小时/分钟都可换算成秒,用秒可以解决更多的场景)
로그인 후 복사

함수를 일반 함수로 추출하면 아마도 다음과 같을 것입니다.

<?php/**
 * 频率限制
 * @param string $action 操作动作
 * @param int $userId 发起操作的用户ID
 * @param int $time 时间范围X秒内
 * @param int $number 限制操作数Y次
 * @param array $expire 超出封印时间Z [&#39;type&#39;=>1,&#39;ttl&#39;=>过期时间/秒] [&#39;type&#39;=>2,&#39;ttl&#39;=>具体过期时间戳] 二选一
 * @return bool
 * @throws \Exception
 */public static function frequencyLimit(string $action, int $userId, int $time, int $number, $expire = []){    // todo 根据用户操作动作时间范围,进行频率的控制和失效释放}
로그인 후 복사

The 솔루션이 구현되었습니다

기능 사용자가 시작한 작업과 시간은 물론 누적 횟수도 저장해야 하며, 이때 저장을 mysql에 의존한다면 상당히 고통스럽습니다. 생각해 보세요. 여기서 주인공은 redis 기능, incr의 원자적 작동 및 키 지원 만료 메커니즘을 기반으로 하는 redis가 마침내 등장했으며, 메모리 저장의 효율성 이점을 통해 상대적으로 간단하고 유연하며 효율적으로 목적을 달성할 수 있다는 것입니다.

다음은 단순히 공통 기능을 구현하는 코드입니다.

<?php/**
 * 频率限制
 * @param string $action 操作动作
 * @param int $userId 发起操作的用户ID
 * @param int $time 时间范围X秒内
 * @param int $number 限制操作数Y次
 * @param array $expire  超出封印时间Z [&#39;type&#39;=>1,&#39;ttl&#39;=>过期时间/秒] [&#39;type&#39;=>2,&#39;ttl&#39;=>具体过期时间戳] 二选一
 * @return bool
 * @throws \Exception
 */public function frequencyLimit(string $action, int $userId, int $time, int $number, $expire = []){    if (empty($action) || $userId <= 0 || $time <= 0 || $number <= 0) {        throw new \Exception(&#39;非法参数&#39;);
    }
    $key = &#39;act:limit:&#39; . $action . &#39;:&#39; . $userId;
    $r = RedisClient::connect();    //获取当前累计次数
    $current = intval($r->get($key));    if ($current >= $number) return false;    //累计并返回最新值
    $current = $r->incr($key);    //第一次累加,设置控制操作频率的有效时间
    if ($current === 1) $r->expire($key, $time);    //未超出限制次数先放过
    if ($current < $number) return true;    //超出后根据需要重新设置过期失效时间 $current === $number 判断保证只重新设置一次
    $type = empty($expire[&#39;type&#39;]) ? 0 : intval($expire[&#39;type&#39;]);
    $ttl = empty($expire[&#39;ttl&#39;]) ? 0 : intval($expire[&#39;ttl&#39;]);    if ($current === $number && $ttl > 0 && in_array($type, [1, 2])) {        if ($type === 1) $r->expire($key, $ttl);        if ($type === 2) $r->expireAt($key, $ttl);
    }    return false;
}//场景1/**
 * 评论限制
 * @param int $userId
 * @return bool|string
 */public function doComment(int $userId){    try {
        $pass = FrequencyLimit::doHandle(&#39;comment&#39;, $userId, 30, 10);        if (!$pass) return &#39;过于频繁&#39;;        // todo 评论逻辑
        return true;
    } catch (\Exception $e) {        return $e->getMessage();
    }
}//场景2/**
 * 点赞限制
 * @param int $userId
 * @return bool|string
 */public function doLike(int $userId){    try {
        $pass = FrequencyLimit::doHandle(&#39;like&#39;, $userId, 10, 10, [&#39;type&#39; => 1, &#39;ttl&#39; => 1 * 60 * 60]);        if (!$pass) return &#39;过于频繁,被禁止操作1小时&#39;;        // todo 点赞逻辑
        return true;
    } catch (\Exception $e) {        return $e->getMessage();
    }
}//场景3/**
 * 上传限制
 * @param int $userId
 * @return bool|string
 */public function doUpload(int $userId){    try {
        $expire = strtotime(date(&#39;Y-m-d&#39;, strtotime(+1 . &#39;days&#39;)));
        $pass = FrequencyLimit::doHandle(&#39;upload&#39;, $userId, 1 * 24 * 60 * 60, 100, [&#39;type&#39; => 2, &#39;ttl&#39; => $expire]);        if (!$pass) return &#39;超出今日上线&#39;;        // todo 上传逻辑
        return true;
    } catch (\Exception $e) {        return $e->getMessage();
    }
}//场景N
로그인 후 복사
编码上可以根据你设计这个通用方案的复杂度进行进一步抽象,如抽象成频率限制的功能类等
로그인 후 복사

요약

유사한 비즈니스 시나리오를 분석하고, 필수적인 문제를 발견하고, 일반적인 솔루션을 설계하세요.

솔루션의 가치를 높이고 영혼을 갖춘 개발자가 되세요.

에 능숙하세요. redis를 사용하여 기능과 장점을 최대한 활용해 보세요

더 많은 Redis 관련 기술 기사를 보려면 Redis Tutorial 칼럼을 방문하여 알아보세요!

위 내용은 Redis 실제 전투 제한 작동 빈도의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿