실제 시스템에는 여러 번 수행해도 동일한 효과를 내거나 동일한 결과를 반환해야 하는 작업이 많이 있습니다.
예:
프런트 엔드가 선택한 데이터를 반복적으로 제출하는 경우 백그라운드는 이 데이터에 해당하는 하나의 응답 결과만 생성해야 합니다.
결제 요청 시 사용자 계정은 한 번만 차감되어야 합니다. 네트워크 재전송 또는 시스템 버그 재전송이 발생할 경우 금액은 한 번만 차감되어야 합니다.
메시지 전송도 한 번만 보내야 합니다. , 동일한 문자 메시지가 사용자에게 전송되고 사용자는
비즈니스 주문을 생성합니다. 한 번에 하나의 비즈니스 요청만 생성하면 큰 문제가 발생합니다.
및 기타 여러 중요한 상황에서 이러한 논리를 지원하려면 멱등성 기능이 필요합니다.
Idempotence(멱등성, 멱등성)은 추상대수학에서 흔히 볼 수 있는 수학 및 컴퓨터 과학 개념입니다.
프로그래밍에서 멱등성 연산의 특징은 여러 실행의 영향이 한 번의 실행의 영향과 동일하다는 것입니다. 멱등성 함수 또는 멱등성 메서드는 동일한 매개변수를 사용하여 반복적으로 실행하여 동일한 결과를 얻을 수 있는 함수입니다.
이러한 기능은 시스템 상태에 영향을 미치지 않으며 반복 실행으로 인한 시스템 변경에 대해 걱정할 필요가 없습니다. 예를 들어 "getUsername() 및 setTrue()" 함수는 멱등성 함수입니다.
더 복잡한 작업은 고유한 트랜잭션 번호(일련번호)를 사용하여 멱등성을 보장합니다.
내가 이해한 바: 멱등성은 여러 번 실행해도 반환되는 효과와 결과는 동일합니다.
1. 쿼리 작업 한 번 쿼리하거나 여러 번 쿼리하는 경우 데이터가 변경되지 않은 상태에서 쿼리 결과는 동일합니다. 선택은 자연스러운 멱등성 연산입니다
2. 삭제 연산 삭제 연산도 한 번 삭제하고 여러 번 삭제하면 데이터가 삭제됩니다. (반환되는 결과가 다를 수 있으니 주의하세요. 삭제된 데이터가 존재하지 않으므로 0이 반환됩니다. 삭제된 데이터가 여러 개인 경우 여러 개의 결과가 반환됩니다.)
3. 새로운 더티 데이터를 방지하기 위한 고유 인덱스 예: Alipay의 자본 계정, Alipay 사용자 계정도 있습니다. 각 사용자는 하나의 펀드 계정만 가질 수 있습니다. 그러면 사용자에 대해 여러 개의 펀드 계정이 생성되지 않도록 하려면 어떻게 해야 합니까? 그러면 펀드 계정 테이블의 사용자 ID에 고유 인덱스를 추가하세요. 사용자가 펀드 계좌 기록을 성공적으로 추가할 수 있도록
핵심 사항: 고유 인덱스 또는 고유 결합 인덱스를 사용하여 새 데이터의 더티 데이터를 방지합니다(테이블에 고유 인덱스가 있고 동시성 중에 새 데이터를 추가할 때 오류가 보고되는 경우). , 데이터가 이미 존재해야 하며 결과를 반환하면 됩니다.)
4. 페이지의 반복 제출을 방지하는 토큰 메커니즘
비즈니스 요구 사항:
페이지의 데이터는 한 번만 클릭하여 제출할 수 있습니다.
발생 원인: 반복적인 클릭, 네트워크 재전송 또는 nginx 재전송 등으로 인해 데이터가 반복적으로 제출됩니다
해결 방법: 클러스터 환경: 토큰 사용 redis 추가(redis는 단일 스레드, 처리는 대기열에 있어야 함) 단일 JVM 환경: 토큰과 redis 또는 토큰과 jvm 메모리 사용
처리 프로세스:
데이터를 제출하기 전에 토큰은 서비스에서 가져오고 토큰은 redis 또는 jvm 메모리에 배치되며 토큰 유효 시간
제출 후 백그라운드에서 토큰을 확인하고 동시에 토큰을 삭제하며 반환할 새 토큰을 생성합니다
토큰 기능:
적용하려면 한 번만 유효하며 현재는 제한될 수 있습니다.
참고: redis는 삭제 작업을 사용하여 토큰을 판단해야 합니다. 삭제에 성공하면 select+를 사용하는 경우 토큰 확인이 통과되었음을 의미합니다. 토큰을 확인하기 위해 삭제하면 동시성 문제가 발생하므로 사용하지 않는 것이 좋습니다.
5. 비관적 잠금 데이터 획득 시 획득을 잠급니다
select * from table_xxx where id='xxx' for update;
참고: id 필드는 기본 키 또는 유일한 인덱스여야 합니다. 그렇지 않으면 테이블이 잠겨서 사람들이 죽을 것입니다
비관적 잠금은 일반적으로 함께 사용됩니다. 트랜잭션 및 데이터 잠금 시간이 매우 길 수 있으니 실제 상황에 따라 선택하세요
6. 낙관적 잠금 낙관적 잠금은 데이터가 업데이트되는 순간에만 테이블을 잠그고 테이블을 잠그지 않습니다. 다른 경우에는 비관적 잠금보다 더 효율적입니다.
낙관적 잠금은 버전 또는 기타 상태 조건을 통해 다양한 방법으로 구현할 수 있습니다.
1. 버전 번호
update table_xxx set name=#name#,version=version+1 where version=#version#
를 통해 구현됨(인터넷에서):
2. 요구 사항 :quality-#subQuality# >=, 이 시나리오는 버전 번호가 없는 경우에 적합하며 업데이트만 데이터 보안 확인에 적합하며 인벤토리 모델, 공유 공제 및 롤백 공유, 더 높은 성능에 적합합니다
注意:乐观锁的更新操作,最好用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表,上面两个sql改成下面的两个更好
update tablexxx set name=#name#,version=version+1 where id=#id# and version=#version#update tablexxx set avaiamount=avaiamount-#subAmount# where id=#id# and avai_amount-#subAmount# >= 0
7. 分布式锁 还是拿插入数据的例子,如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定
这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁
这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。
要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供)
8. select + insert 并发不高的后台系统,或者一些任务JOB,为了支持幂等,支持重复执行,简单的处理方法是,先查询下一些关键数据,判断是否已经执行过,在进行业务处理,就可以了
注意:核心高并发流程不要用这种方法
9. 状态机幂等 在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机
상태 머신이 이미 다음 상태에 있고 이때 이전 상태로의 변경이 발생하면 이론상으로는 변경이 불가능합니다. 이 경우 유한 상태 머신의 멱등성은 보장됩니다.
참고: 주문 및 기타 문서 유형 비즈니스는 상태 흐름이 길기 때문에 상태 머신에 대한 깊은 이해가 있어야 비즈니스 시스템 설계 기능을 향상하는 데 큰 도움이 됩니다.
10. 외부 인터페이스
예를 들어 UnionPay에서 제공하는 결제 인터페이스: 결제 요청을 제출하기 위해 판매자에 액세스해야 하는 경우 소스 소스, seq 일련 번호
source+seq가 데이터베이스에 고유한 인덱스를 만듭니다. 다중 결제를 방지하기 위해(동시 요청은 하나만 처리 가능)
핵심멱등성 호출을 지원하는 외부 인터페이스를 제공하기 위해 인터페이스에는 전달해야 하는 두 개의 필드가 있는데, 하나는 소스이고, 하나는 소스이고 other는 소스 시퀀스 번호 seq입니다. 이 두 필드는 공급자 시스템에서 공동 고유 인덱스로 사용됩니다
이런 식으로 제3자가 호출하면 먼저 자체 시스템에서 처리되었는지 확인하고 반환합니다. 해당 처리 결과가 처리되지 않은 경우 해당 처리를 수행하고 결과를 반환합니다.
참고로 멱등성과 친화성을 갖추기 위해서는 먼저 비즈니스가 처리되었는지 확인해야 합니다. 쿼리하지 않고 비즈니스 시스템에 직접 입력하면 오류가 보고되지만 실제로는 처리되었습니다.
멱등성은 자격을 갖춘 프로그래머의 유전자여야 하며, 특히 알리페이, 은행, 인터넷 금융회사 등 모두 돈이 관련된 시스템에서는 가장 먼저 고려해야 할 사항입니다. 데이터도 정확해야 하므로 과도한 공제, 초과 지급 등의 문제가 발생하지 않으며, 이는 처리하기 어렵고 사용자 경험도 좋지 않습니다.
위 내용은 높은 동시성에서 인터페이스의 멱등성을 보장하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!