php - 高并发下悲观锁与乐观锁的选择问题
ringa_lee
ringa_lee 2017-05-16 13:05:01
0
4
779

说说我的看法,不对的地方请指正。

乐观锁的实现原理是cas操作,java中轻量级锁也是基于cas实现的。

悲观锁最大的问题就是阻塞问题。

在深入理解java虚拟机中提到,轻量级锁一般情况下是优于重量级锁(互斥锁)的;如果在高并发锁竞争比较激烈的情况下轻量级锁会由于长时间自旋消耗cpu 从而使得轻量级锁的性能比传统的重量级锁更慢。那么乐观锁中也有自旋和cas,所以高并发下乐观锁好像不是一种好的解决方案。

但是有些博文中提到 高并发下使用乐观锁更合适
比如这篇文章中就提到高并发数据库访问使用乐观锁
http://blog.csdn.net/amqvje/a...

问题1,高并发下如何选择?

问题2 乐观锁有什么缺点? 为什不都使用乐观锁。高并发下都是使用乐观锁,如果并发量不高,使用乐观锁感觉更不是问题

ringa_lee
ringa_lee

ringa_lee

모든 응답 (4)
刘奇

간단히 말하면, 일반적인 상황에서는 읽기만 하고 쓰지 않는 작업에는 낙관적 잠금이 적합하고, 읽기와 쓰기가 혼합된 작업에는 비관적 잠금이 적합합니다. 방문자 수를 늘리는 등 쓰기 작업이 매우 간단하고 짧은 경우 낙관적 잠금을 사용하거나 읽은 데이터가 최신인지 확인할 필요가 없는 경우에도 사용할 수 있습니다. 낙관적 잠금을 사용하는 것이 실제로 80%의 경우에 더 나은 선택입니다.

CAS는 원자 수준 작업을 구현하기 위해 하드웨어 CPU 명령 지원에 의존하므로 일반적으로 높은 동시성 조건에서 더 빠릅니다. 그러나 이 속도에는 읽기 및 쓰기가 있을 때 CPU 캐시 오류가 있다는 단점이 있습니다. 귀하의 CPU가 단일 코어(비인텔 플랫폼 내장)가 아닌 한 속도가 증가할 수 있습니다.

요컨대, 높은 동시성 성능을 향상시키기 위해서는 문제를 설명하기 위한 실제 측정 데이터가 여전히 필요합니다. 위에서 언급한 것은 모두 이론입니다. 도움이 되길 바랍니다.

    阿神

    비관적 잠금이든 낙관적 잠금이든 실제로는 동시성 제어에 대한 아이디어이며, 낙관적 잠금과 비관적 잠금의 구체적인 선택은 비즈니스 시나리오를 기반으로 합니다.
    비관적 잠금:
    일반적으로 우리가 사용하는 비관적 잠금은 데이터베이스 수준에서 배타적 잠금을 추가하는 것입니다. 잠금이 성공하면 트랜잭션 제출이 성공적으로 해제됩니다. 실패하면 데이터가 수정되고 있음을 의미합니다. mysql의 innodb를 사용하는 경우 mysql 자동 커밋 속성을 끄도록 주의하세요. 왜냐하면 mysql은 기본적으로 자동 커밋 모드를 사용하기 때문입니다. 즉, 업데이트 작업을 수행하면 MySQL이 즉시 결과를 제출하고 주의를 기울일 것입니다. 기본적으로 innodb는 행 수준 잠금을 사용하지만 행 수준 잠금은 인덱스를 기반으로 합니다. SQL이 인덱스를 사용하지 않으면 mysql은 테이블 수준 잠금을 사용하여 테이블을 잠급니다.set autocommit=0장점 및 단점:
    비관적 잠금은 "먼저 잠금을 얻은 다음 액세스"하는 보수적인 전략으로, 데이터 처리 보안을 보장합니다. 그러나 효율성 측면에서 잠금 메커니즘은 데이터베이스에 추가 오버헤드를 발생시키고 교착 상태 가능성을 높입니다. 또한 읽기 전용 트랜잭션 처리에서는 충돌이 발생하지 않으므로 잠금을 사용할 필요가 없으며 이는 시스템 부하만 증가시킵니다. 또한 트랜잭션이 특정 데이터 행을 잠그면 다른 트랜잭션은 해당 데이터 행을 처리하기 전에 트랜잭션이 처리될 때까지 기다려야 합니다.

    낙관적 잠금:

    낙관적 잠금은 실제로 데이터가 정상적인 상황에서 충돌을 일으키지 않는다고 가정하므로 업데이트를 위해 데이터가 제출되면 데이터 충돌이 공식적으로 감지되고 충돌이 발견되면 사용자가 반환됩니다. 오류 정보를 제공하고 사용자가 무엇을 할지 결정하도록 합니다.
    일반적으로 코드 논리 계층에서 직접 작성할 수 있습니다. 비관적 잠금과 비교하여 낙관적 잠금은 데이터베이스에서 제공하는 잠금 메커니즘을 사용하지 않고 일반적으로 버전 번호나 타임스탬프를 사용하여 구현됩니다. 버전 번호를 사용하는 경우 데이터를 초기화할 때 버전 번호를 지정할 수 있으며, 데이터에 대한 각 업데이트 작업은 버전 번호에 대해 +1 작업을 수행합니다. 그리고 현재 버전 번호가 데이터의 최신 버전 번호인지 확인합니다. 예:
    으아악

    장점 및 단점:

    낙관적 잠금은 데이터 경쟁 가능성이 매우 작다고 생각하므로 최대한 직접적으로 진행하고 제출할 때까지 잠금을 설정하지 않으므로 잠금 및 교착 상태가 발생하지 않습니다. 그러나 이 작업을 간단하게 수행하면 여전히 예상치 못한 결과가 발생할 수 있습니다. 예를 들어 두 트랜잭션 모두 데이터베이스의 특정 행을 읽은 다음 수정 후 데이터베이스에 다시 쓰는 경우 문제가 발생합니다.
    낙관적 잠금의 실패는 확률이 작은 이벤트이며 발생하려면 여러 조건의 협력이 필요합니다. 예:

    • 애플리케이션은 기본 키 ID를 관리하기 위해 자체 전략을 채택합니다. 예를 들어 현재 ID 필드의 최대값 + 1을 새 ID로 취하는 것이 일반적입니다.

    • 버전 번호 필드 버전의 기본값은 0입니다.

    • 사용자 A는 특정 레코드를 읽고 수정을 준비합니다. 이 레코드는 ID가 가장 큰 레코드이며 이전에 수정된 적이 없습니다. 버전은 기본값 0입니다.

    • 사용자 A가 읽기를 완료한 후 사용자 B가 우연히 기록을 삭제했습니다. 그 후 사용자 C가 새 레코드를 삽입했습니다.

    • 이때, 실수로 새로 삽입된 레코드의 ID가 사용자 A가 읽은 레코드의 ID와 일치하며, 두 버전 번호 모두 기본값이 0입니다.

    • 사용자 C가 작업을 완료한 후 사용자 A는 완료된 기록을 수정하고 저장합니다. ID와 버전이 모두 일치하므로 사용자 A는 성공적으로 저장했습니다. 그러나 사용자 C가 삽입한 레코드를 덮어썼습니다.
      현재 낙관적 잠금이 실패하는 근본적인 이유는 애플리케이션에서 사용하는 기본 키 ID 관리 전략이 낙관적 잠금과 어느 정도 호환되지 않는다는 것입니다.

      PHPzhong

      작업을 시작하기 전에도 질문자와 같은 생각이었습니다. 실제 작업에서는 둘 사이에 실제로 큰 차이가 없습니다. 실제 높은 동시성에서 시스템에서 가장 시간이 많이 걸리는 부분은 항상 네트워크 연결, 데이터베이스 쿼리 및 작업입니다. 스레드의 활성 절전 모드는 기본적으로 무시할 수 있습니다.

        我想大声告诉你

        핵심 질문은 사실이 비관적인가 아니면 낙관적인가?입니다.

        리소스 경쟁이 치열하고 공유할 수 없는 경우 낙관적 잠금은 수많은 요청에 대한 희망을 무산시킬 것입니다.

        리소스에 대한 경쟁이 없는 경우(동시성 수준과 반드시 관련이 있는 것은 아니지만 비즈니스에 더 큰 영향을 미침) 비관적 잠금은 불필요한 잠금을 의미합니다. 리소스가 원래 공유 가능한 경우(예: 리소스가 여러 읽기 전용 당사자를 지원하는 경우) 비관적 잠금은 원래 사용 가능한 시간을 잃는 것을 의미합니다.

        Java Virtual Machine에 대한 심층적인 이해에서는 일반적으로 경량 잠금이 중량 잠금(뮤텍스 잠금)보다 낫다고 언급되어 있습니다. 동시성 잠금 경쟁이 치열할 경우 경량 잠금이 오랫동안 잠길 것입니다. 시간 회전은 CPU를 소비하므로 경량 잠금의 성능은 기존의 중량 잠금보다 느려집니다. 그렇다면 낙관적 잠금에는 spin과 cas도 포함되므로 동시성이 높은 비관적 잠금은 좋은 해결책이 아닌 것 같습니다.

        저는 JVM에 대해 잘 모릅니다. 그런데 "낙관적 잠금에도 Spin과 Cas가 존재한다"는 것은 무슨 뜻일까요? cas는 스핀 잠금의 구현 방법입니다. 왜 병렬화해야 합니까? "또한"은(는) 무슨 뜻인가요? 비관적 잠금은 차단 작업이고 회전이 없으며 지속적으로 CPU를 소모하지 않습니다.

          최신 다운로드
          더>
          웹 효과
          웹사이트 소스 코드
          웹사이트 자료
          프론트엔드 템플릿
          회사 소개 부인 성명 Sitemap
          PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!