이 기사는 동시 액세스의 정확성을 보장하기 위해 Redis 원자 작업에 대한 관련 지식을 제공합니다. 즉, 잠금 및 원자 작업이라는 두 가지 방법이 모든 사람에게 도움이 되기를 바랍니다.
redis 원자 연산
Redis를 사용하면 필연적으로 동시 액세스 문제가 발생합니다. 예를 들어 여러 사용자가 동시에 주문하면 Redis에 캐시된 제품 인벤토리가 동시에 업데이트됩니다. 동시 쓰기 작업이 있으면 데이터가 수정됩니다. 동시 쓰기 요청을 제어하지 않으면 데이터가 수정되어 정상적인 비즈니스 사용에 영향을 미칠 수 있습니다(예: 재고 데이터 오류로 인해 비정상적인 주문이 발생함).
동시 액세스의 정확성을 보장하기 위해 Redis는 잠금 및 원자성 작업이라는 두 가지 방법을 제공합니다.
잠금은 데이터를 읽기 전에 먼저 잠금을 획득해야 하는 일반적인 방법입니다. 그렇지 않으면 작업을 수행할 수 없습니다. 클라이언트가 잠금을 획득하면 클라이언트가 데이터 업데이트를 완료한 다음 잠금을 해제할 때까지 잠금을 유지합니다.
좋은 해결책처럼 보이지만 실제로는 두 가지 문제가 있습니다. 하나는 잠금 작업이 너무 많으면 시스템의 동시 액세스 성능이 저하된다는 것이고, 두 번째는 Redis 클라이언트를 잠가야 한다는 것입니다. 이렇게 하려면 분산 잠금을 사용해야 하며 분산 잠금 구현은 복잡하고 추가 및 잠금 해제 작업을 제공하기 위한 추가 저장 시스템이 필요합니다. 다음 강의에서 소개하겠습니다.
원자적 작업은 동시 액세스 제어를 제공하는 또 다른 방법입니다. 원자성 작업은 실행 중에 원자성을 유지하고 원자성 작업을 실행할 때 추가 잠금이 필요하지 않아 잠금 없는 작업을 달성하는 작업을 의미합니다. 이러한 방식으로 동시성 제어가 보장되고 시스템 동시성 성능에 미치는 영향을 줄일 수 있습니다.
동시 접속 시 제어해야 할 사항은 무엇인가요?
동시 액세스 제어라고 부르는 것은 Redis 인스턴스에서 실행될 때 모든 클라이언트가 보낸 작업이 상호 배타적이도록 보장하기 위해 동일한 데이터에 액세스하고 운영하는 여러 클라이언트의 프로세스를 제어하는 것을 의미합니다. 예를 들어 클라이언트 A의 액세스 작업이 실행되는 동안 클라이언트 B의 작업은 실행될 수 없으며 A의 작업이 완료될 때까지 기다려야 실행될 수 있습니다.
동시 접근 제어에 해당하는 작업은 주로 데이터 수정 작업입니다. 클라이언트가 데이터를 수정해야 하는 경우 기본 프로세스는 두 단계로 나뉩니다.
- 클라이언트는 먼저 데이터를 로컬에서 읽고 로컬에서 수정합니다.
- 클라이언트는 데이터를 수정한 후 이를 Redis에 다시 씁니다.
이 프로세스를 "읽기-수정-쓰기" 작업(읽기-수정-쓰기, RMW 작업이라고 함)이라고 부릅니다. 여러 클라이언트가 동일한 데이터에 대해 RMW 작업을 수행하는 경우 RMW 작업과 관련된 코드가 원자적으로 실행되도록 허용해야 합니다. 동일한 데이터에 액세스하는 RMW 연산 코드를 임계 섹션 코드라고 합니다.
그러나 여러 클라이언트가 임계 섹션 코드를 동시에 실행하면 몇 가지 잠재적인 문제가 있을 수 있습니다. 다음으로 여러 클라이언트가 제품 인벤토리를 업데이트하는 예를 사용하여 설명하겠습니다.
먼저 크리티컬 섹션 코드를 살펴보겠습니다. 클라이언트가 제품 재고에서 1을 차감하려고 한다고 가정합니다. 의사 코드는 다음과 같습니다.
current = GET(id) current-- SET(id, current)
클라이언트가 먼저 제품 ID(Read에 해당)를 기반으로 Redis에서 제품의 현재 재고 값을 읽는 것을 볼 수 있습니다. ) 그런 다음 클라이언트는 인벤토리 값을 1만큼 감소시키고(수정에 해당) 인벤토리 값을 Redis에 다시 씁니다(쓰기에 해당). 여러 클라이언트가 이 코드를 실행하는 경우 이는 중요한 섹션 코드입니다.
중요 섹션 코드 실행에 대한 제어 메커니즘이 없으면 데이터 업데이트 오류가 발생합니다. 지금의 예에서는 두 클라이언트 A와 B가 동시에 임계 영역 코드를 실행한다고 가정하면 아래 그림을 보면 오류가 발생합니다.
클라이언트 A가 t1에서 인벤토리 값 10을 읽고 1을 공제하는 것을 볼 수 있습니다. t2에서 클라이언트 A는 공제된 인벤토리 값 9를 아직 Redis에 기록하지 않았습니다. 이때 클라이언트 B는 의 인벤토리 값을 읽습니다. 10이고 1을 공제합니다. B가 기록한 재고 가치도 9입니다. t3일 때 A는 인벤토리 값 9를 Redis에 다시 쓰고, t4일 때 B도 인벤토리 값 9를 다시 씁니다.
올바른 로직에 따라 처리된다면 클라이언트 A와 B는 각각 재고 가치를 한 번씩 공제하며, 재고 가치는 8이 되어야 합니다. 따라서 여기의 재고 값은 분명히 잘못 업데이트되었습니다.
이 현상이 발생하는 이유는 임계 섹션 코드의 클라이언트가 데이터 읽기, 데이터 업데이트 및 데이터 다시 쓰기의 세 가지 작업을 포함하기 때문입니다. 그러나 이 세 가지 작업은 실행될 때 상호 배타적이지 않습니다. 클라이언트는 기반으로 수정합니다. 이전 클라이언트에서 수정한 값이 아닌 동일한 초기값으로
데이터 동시 수정의 정확성을 보장하기 위해 잠금을 사용하여 병렬 작업을 직렬 작업으로 전환할 수 있으며 직렬 작업은 상호 배타적입니다. 클라이언트가 잠금을 보유하고 나면 다른 클라이언트는 잠금이 해제될 때까지 기다렸다가 잠금을 가져와 수정할 수 있습니다.
다음 의사 코드는 잠금을 사용하여 중요 섹션 코드의 실행을 제어하는 방법을 보여줍니다. 살펴볼 수 있습니다.
LOCK() current = GET(id) current-- SET(id, current) UNLOCK()
虽然加锁保证了互斥性,但是加锁也会导致系统并发性能降低。
如下图所示,当客户端 A 加锁执行操作时,客户端 B、C 就需要等待。A 释放锁后,假设 B 拿到锁,那么 C 还需要继续等待,所以,t1 时段内只有 A 能访问共享数据,t2 时段内只有 B 能访问共享数据,系统的并发性能当然就下降了。
和加锁类似,原子操作也能实现并发控制,但是原子操作对系统并发性能的影响较小,接下来,我们就来了解下 Redis 中的原子操作。
Redis 的两种原子操作方法
为了实现并发控制要求的临界区代码互斥执行,Redis 的原子操作采用了两种方法:
- 把多个操作在 Redis 中实现成一个操作,也就是单命令操作;
- 把多个操作写到一个 Lua 脚本中,以原子性方式执行单个 Lua 脚本。
我们先来看下 Redis 本身的单命令操作。
Redis 是使用单线程来串行处理客户端的请求操作命令的,所以,当 Redis 执行某个命令操作时,其他命令是无法执行的,这相当于命令操作是互斥执行的。当然,Redis 的快照生成、AOF 重写这些操作,可以使用后台线程或者是子进程执行,也就是和主线程的操作并行执行。不过,这些操作只是读取数据,不会修改数据,所以,我们并不需要对它们做并发控制。
你可能也注意到了,虽然 Redis 的单个命令操作可以原子性地执行,但是在实际应用中,数据修改时可能包含多个操作,至少包括读数据、数据增减、写回数据三个操作,这显然就不是单个命令操作了,那该怎么办呢?
别担心,Redis 提供了 INCR/DECR 命令,把这三个操作转变为一个原子操作了。INCR/DECR 命令可以对数据进行增值 / 减值操作,而且它们本身就是单个命令操作,Redis 在执行它们时,本身就具有互斥性。
比如说,在刚才的库存扣减例子中,客户端可以使用下面的代码,直接完成对商品 id 的库存值减 1 操作。即使有多个客户端执行下面的代码,也不用担心出现库存值扣减错误的问题。
DECR id
所以,如果我们执行的 RMW 操作是对数据进行增减值的话,Redis 提供的原子操作 INCR 和 DECR 可以直接帮助我们进行并发控制。
但是,如果我们要执行的操作不是简单地增减数据,而是有更加复杂的判断逻辑或者是其他操作,那么,Redis 的单命令操作已经无法保证多个操作的互斥执行了。所以,这个时候,我们需要使用第二个方法,也就是 Lua 脚本。
Redis 会把整个 Lua 脚本作为一个整体执行,在执行的过程中不会被其他命令打断,从而保证了 Lua 脚本中操作的原子性。如果我们有多个操作要执行,但是又无法用 INCR/DECR 这种命令操作来实现,就可以把这些要执行的操作编写到一个 Lua 脚本中。
然后,我们可以使用 Redis 的 EVAL 命令来执行脚本。这样一来,这些操作在执行时就具有了互斥性。
再举个例子,具体解释下 Lua 的使用。
当一个业务应用的访问用户增加时,我们有时需要限制某个客户端在一定时间范围内的访问次数,比如爆款商品的购买限流、社交网络中的每分钟点赞次数限制等。
那该怎么限制呢?我们可以把客户端 IP 作为 key,把客户端的访问次数作为 value,保存到 Redis 中。客户端每访问一次后,我们就用 INCR 增加访问次数。
不过,在这种场景下,客户端限流其实同时包含了对访问次数和时间范围的限制,例如每分钟的访问次数不能超过 20。所以,我们可以在客户端第一次访问时,给对应键值对设置过期时间,例如设置为 60s 后过期。同时,在客户端每次访问时,我们读取客户端当前的访问次数,如果次数超过阈值,就报错,限制客户端再次访问。你可以看下下面的这段代码,它实现了对客户端每分钟访问次数不超过 20 次的限制。
//获取ip对应的访问次数 current = GET(ip) //如果超过访问次数超过20次,则报错 IF current != NULL AND current > 20 THEN ERROR "exceed 20 accesses per second" ELSE //如果访问次数不足20次,增加一次访问计数 value = INCR(ip) //如果是第一次访问,将键值对的过期时间设置为60s后 IF value == 1 THEN EXPIRE(ip,60) END //执行其他操作 DO THINGS END
可以看到,在这个例子中,我们已经使用了 INCR 来原子性地增加计数。但是,客户端限流的逻辑不只有计数,还包括访问次数判断和过期时间设置。
对于这些操作,我们同样需要保证它们的原子性。否则,如果客户端使用多线程访问,访问次数初始值为 0,第一个线程执行了 INCR(ip) 操作后,第二个线程紧接着也执行了 INCR(ip),此时,ip 对应的访问次数就被增加到了 2,我们就无法再对这个 ip 设置过期时间了。这样就会导致,这个 ip 对应的客户端访问次数达到 20 次之后,就无法再进行访问了。即使过了 60s,也不能再继续访问,显然不符合业务要求。
所以,这个例子中的操作无法用 Redis 单个命令来实现,此时,我们就可以使用 Lua 脚本来保证并发控制。我们可以把访问次数加 1、判断访问次数是否为 1,以及设置过期时间这三个操作写入一个 Lua 脚本,如下所示:
local current current = redis.call("incr",KEYS[1]) if tonumber(current) == 1 then redis.call("expire",KEYS[1],60) end
假设我们编写的脚本名称为 lua.script,我们接着就可以使用 Redis 客户端,带上 eval 选项,来执行该脚本。脚本所需的参数将通过以下命令中的 keys 和 args 进行传递。
redis-cli --eval lua.script keys , args
这样一来,访问次数加 1、判断访问次数是否为 1,以及设置过期时间这三个操作就可以原子性地执行了。即使客户端有多个线程同时执行这个脚本,Redis 也会依次串行执行脚本代码,避免了并发操作带来的数据错误。
推荐学习:《Redis视频教程》、《2022最新redis面试题大全及答案》
위 내용은 10분 만에 Redis 원자적 작업 이해의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

Redis의 데이터 모델 및 구조에는 5 가지 주요 유형이 포함됩니다. 1. 문자열 : 텍스트 또는 이진 데이터를 저장하는 데 사용되며 원자 연산을 지원합니다. 2. 목록 : 정렬 된 요소 컬렉션, 대기열 및 스택에 적합합니다. 세트 : 세트 작동을 지원하는 비 순차 고유 요소 세트. 4. 순서 세트 (SortedSet) : 순위에 적합한 점수가있는 고유 한 요소 세트. 5. 해시 테이블 (HASH) : 객체를 저장하는 데 적합한 키 값 쌍 모음.

Redis의 데이터베이스 방법에는 메모리 인 데이터베이스 및 키 값 저장소가 포함됩니다. 1) Redis는 메모리에 데이터를 저장하고 빠르게 읽고 쓰고 있습니다. 2) 키 값 쌍을 사용하여 데이터를 저장하고 캐시 및 NOSQL 데이터베이스에 적합한 목록, 컬렉션, 해시 테이블 및 주문 컬렉션과 같은 복잡한 데이터 구조를 지원합니다.

Redis는 빠른 성능, 풍부한 데이터 구조, 고 가용성 및 확장 성, 지속성 기능 및 광범위한 생태계 지원을 제공하기 때문에 강력한 데이터베이스 솔루션입니다. 1) 매우 빠른 성능 : Redis의 데이터는 메모리에 저장되며 동시성이 높고 대기 시간이 낮은 응용 프로그램에 적합한 빠른 읽기 및 쓰기 속도를 가지고 있습니다. 2) 풍부한 데이터 구조 : 다양한 시나리오에 적합한 목록, 컬렉션 등과 같은 여러 데이터 유형을 지원합니다. 3) 고 가용성 및 확장 성 : 마스터 슬레이브 복제 및 클러스터 모드를 지원하여 고 가용성 및 수평 확장 성을 달성합니다. 4) 지속성 및 데이터 보안 : 데이터 지속성은 RDB 및 AOF를 통해 달성되어 데이터 무결성 및 신뢰성을 보장합니다. 5) 광범위한 생태계 및 지역 사회 지원 : 거대한 생태계와 활동적인 커뮤니티,

Redis의 주요 기능에는 속도, 유연성 및 풍부한 데이터 구조 지원이 포함됩니다. 1) 속도 : Redis는 메모리 내 데이터베이스이며, 읽기 및 쓰기 작업은 거의 순간적이며 캐시 및 세션 관리에 적합합니다. 2) 유연성 : 복잡한 데이터 처리에 적합한 문자열, 목록, 컬렉션 등과 같은 여러 데이터 구조를 지원합니다. 3) 데이터 구조 지원 : 다양한 비즈니스 요구에 적합한 문자열, 목록, 컬렉션, 해시 테이블 등을 제공합니다.

Redis의 핵심 기능은 고성능 인 메모리 데이터 저장 및 처리 시스템입니다. 1) 고속 데이터 액세스 : Redis는 메모리에 데이터를 저장하고 마이크로 초 수준 읽기 및 쓰기 속도를 제공합니다. 2) 풍부한 데이터 구조 : 문자열, 목록, 컬렉션 등을 지원하며 다양한 응용 프로그램 시나리오에 적응합니다. 3) 지속성 : RDB 및 AOF를 통해 디스크에 데이터를 지속하십시오. 4) 구독 게시 : 메시지 대기열 또는 실시간 통신 시스템에서 사용할 수 있습니다.

Redis는 다음을 포함하여 다양한 데이터 구조를 지원합니다. 1. String, 단일 값 데이터 저장에 적합합니다. 2. 큐 및 스택에 적합한 목록; 3. 비면성 데이터 저장에 사용되는 세트; 4. 순서, 순위 목록 및 우선 순위 대기열에 적합한 순서 세트; 5. 해시 테이블, 객체 또는 구조화 된 데이터를 저장하는 데 적합합니다.

Redis Counter는 Redis Key-Value Pair 스토리지를 사용하여 다음 단계를 포함하여 계산 작업을 구현하는 메커니즘입니다. 카운터 키 생성, 카운트 증가, 카운트 감소, 카운트 재설정 및 카운트 얻기. Redis 카운터의 장점에는 빠른 속도, 높은 동시성, 내구성 및 단순성 및 사용 편의성이 포함됩니다. 사용자 액세스 계산, 실시간 메트릭 추적, 게임 점수 및 순위 및 주문 처리 계산과 같은 시나리오에서 사용할 수 있습니다.

Redis Command Line 도구 (Redis-Cli)를 사용하여 다음 단계를 통해 Redis를 관리하고 작동하십시오. 서버에 연결하고 주소와 포트를 지정하십시오. 명령 이름과 매개 변수를 사용하여 서버에 명령을 보냅니다. 도움말 명령을 사용하여 특정 명령에 대한 도움말 정보를 봅니다. 종금 명령을 사용하여 명령 줄 도구를 종료하십시오.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

맨티스BT
Mantis는 제품 결함 추적을 돕기 위해 설계된 배포하기 쉬운 웹 기반 결함 추적 도구입니다. PHP, MySQL 및 웹 서버가 필요합니다. 데모 및 호스팅 서비스를 확인해 보세요.

SublimeText3 영어 버전
권장 사항: Win 버전, 코드 프롬프트 지원!

mPDF
mPDF는 UTF-8로 인코딩된 HTML에서 PDF 파일을 생성할 수 있는 PHP 라이브러리입니다. 원저자인 Ian Back은 자신의 웹 사이트에서 "즉시" PDF 파일을 출력하고 다양한 언어를 처리하기 위해 mPDF를 작성했습니다. HTML2FPDF와 같은 원본 스크립트보다 유니코드 글꼴을 사용할 때 속도가 느리고 더 큰 파일을 생성하지만 CSS 스타일 등을 지원하고 많은 개선 사항이 있습니다. RTL(아랍어, 히브리어), CJK(중국어, 일본어, 한국어)를 포함한 거의 모든 언어를 지원합니다. 중첩된 블록 수준 요소(예: P, DIV)를 지원합니다.
