[지방] 사용자 인터페이스쪽으로, 당신은 정말 높은 동시성을 견딜 수 있는가?

머리말

이 장에있는 데이터는 다시 압력을 측정 잠시. 그런 점에 똑바로 직접 문제를 설명하는 것입니다

모르는하지 않는 일부 친구들 forceTransactionTemplate이 먼저 여기 대중화 이유, 자바, 우리가 일반적으로 거래를 여는 세 가지 방법이있다

  • 트랜잭션을 열 수있는 서비스와 메소드 이름 섹션의 XML 구성 (작년의 높은 주파수로, 지금은 기본적으로 거의 사용되지 않습니다)

  • @Transactional 주석 (자주 사용) 업무를 돌렸다

  • 봄 템플릿 (방법의 스크린 샷, 사용 거의 하나)를 사용하여 트랜잭션

왜 우리가 처음 얘기에 이어 세 번째 얽힌하지 않는 事务传播机制, 우리가 당신이 지금 알고있는, 그 라인에 열린 트랜잭션의 의미는, 어떤 주제에 초점을 내가 헌신 할 때. 내가 일부러 로깅 코드 빨간색과 파란색 원을 사용 인쇄 로그하는 방법을 입력 한 다음 거래를 켠 다음, 자주 초과 근무를 측정 발견 압력의 물결 후 로그를 인쇄 할 때, 우리의 데이터는 로그는 다음을 참조하도록하지 않는 일관된 압력이다, 즉, 최대 :

우리는. 실제로 오초와 거의 오초! 왜 열린 트랜잭션 소요 된 두 개의 로그 출력 시간 간격을 발견?事出反常必有妖!

문제를 해결하기 위해 절단하는 방법

때문에 재현 더 어려워 일반적으로 높은 동시성 문제에 대한 온라인 높은 동시 발생 문제, 컴파일을 향한 그래서 일반적으로 기반으로 비료 눈, 소스 코드 정적 분석 방식에 깊이 살펴 특별히 참조 9 개 개의 얕은는 로컬 온라인, 운영하는 그것은? 붕괴 당황! 하지만 지방의 수를 고려하여 대중은 여전히 여기에 문제를 분석하기 위해,이 분석은 이러한 문제를 경험하는 일반적인 방법 중 일부를 다시 방문합니다 기술을 마스터하지 않은 팬의 새로운 포커스의 작은 부분을 가지고 방향 및 발생하지 않습니다 때 문제慌得一比!

다행히도,이 문제에 어려움이 많은 동시 명세서가 아니라,이 경우 화이트 조사, 우리는 서서히 문제를 위치 시키도록, 문제의 범위를 좁히는 것, 로컬 아날로그 의해 장면을 재생할 수 시작 적합하다.

지역 재현

첫째, 우리는 동시 도구를 준비 할 수있는이 도구 클래스, 당신은.하지 친화적 인 휴대 전화는 지역 환경 시뮬레이션 동시성 시나리오에서 코드를 볼 수 있지만, 그것은 중요하지 않습니다, 복사의 문제를 재현하는 프로젝트에 붙여 다음 코드입니다 并不是给你手机上看的으로 이 도구 때문에이 유틸리티 클래스 코드의 동시 수업 장면을 시뮬레이션 할 수 있습니다 이유 ** 全是JDK中的代码** 핵심 인 CountDownLatch클래스는, 키워드에 따라이 원칙은 당신이 당신의 마음에 드는 검색 엔진 검색의 앞 날을 제공합니다.

CountDownLatchUtil.java

public class CountDownLatchUtil {

    private CountDownLatch start;
    private CountDownLatch end;
    private int pollSize = 10;

    public CountDownLatchUtil() {
        this(10);
    }

    public CountDownLatchUtil(int pollSize) {
        this.pollSize = pollSize;
        start = new CountDownLatch(1);
        end = new CountDownLatch(pollSize);
    }

    public void latch(MyFunctionalInterface functionalInterface) throws InterruptedException {
        ExecutorService executorService = Executors.newFixedThreadPool(pollSize);
        for (int i = 0; i < pollSize; i++) {
            Runnable run = new Runnable() {
                @Override
                public void run() {
                    try {
                        start.await();
                        functionalInterface.run();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        end.countDown();
                    }
                }
            };
            executorService.submit(run);
        }

        start.countDown();
        end.await();
        executorService.shutdown();
    }

    @FunctionalInterface
    public interface MyFunctionalInterface {
        void run();
    }
}
复制代码

HelloService.java

public interface HelloService {

    void sayHello(long timeMillis);

}
复制代码

HelloServiceImpl.java

@Service
public class HelloServiceImpl implements HelloService {

    private final Logger log = LoggerFactory.getLogger(HelloServiceImpl.class);

    @Transactional
    @Override
    public void sayHello(long timeMillis) {
        long time = System.currentTimeMillis() - timeMillis;
        if (time > 5000) {
            //超过5秒的打印日志输出
            log.warn("time : {}", time);
        }
        try {
            //模拟业务执行时间为1s
            Thread.sleep(1000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
复制代码

HelloServiceTest.java

@RunWith(SpringRunner.class)
@SpringBootTest
public class HelloServiceTest {

    @Autowired
    private HelloService helloService;

    @Test
    public void testSayHello() throws Exception {
        long currentTimeMillis = System.currentTimeMillis();
        //模拟1000个线程并发
        CountDownLatchUtil countDownLatchUtil = new CountDownLatchUtil(1000);
        countDownLatchUtil.latch(() -> {
            helloService.sayHello(currentTimeMillis);
        });
    }

}
复制代码

우리는 지역의 로그, 우리는 5 초 인터페이스보다 훨씬 더 발견 디버깅, 모두를위한 프레임 특히 비료 사용 다른 색상의 프레임에 대한 몇 가지 규칙이있다

왜이 시간, 그룹, 데이터의 각 그룹의 모든 다섯 초 그 정도의 차이는?

진실

@Transactional다음과 같이 핵심 코드는 (내가 특별히 소스 코드의이 부분의 후속 분석, 지방 함량을 향한 관심의 핵심을 놓치지 않도록 일련의 것입니다). 여기에 단순히되는 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);방법은 데이터베이스 연결을 얻을하는 것입니다.

if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
	// Standard transaction demarcation with getTransaction and commit/rollback calls.
	TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
	Object retVal = null;
	try {
		// This is an around advice: Invoke the next interceptor in the chain.
		// This will normally result in a target object being invoked.
		retVal = invocation.proceedWithInvocation();
	}
	catch (Throwable ex) {
		// target invocation exception
		completeTransactionAfterThrowing(txInfo, ex);
		throw ex;
	}
	finally {
		cleanupTransactionInfo(txInfo);
	}
	commitTransactionAfterReturning(txInfo);
	return retVal;
}
复制代码

매개 변수는 다음 더 나은 문제, 데이터베이스 연결 풀을 증명하기 위해 지방 (Benpian 드루이드를 사용)으로 다음과 같은 설정을 만든

//初始连接数
spring.datasource.initialSize=1
//最大连接数
spring.datasource.maxActive=5
复制代码

최대 연결 수는 5이므로 1000 개 동시 스레드에 왔을 때 그래서, 당신은 줄, 전면 다섯, 연결 얻을 천명의 팀이 상상할 수있는, 비즈니스 시간의 실행. 그리고 팀의 왼쪽 1 초 995 개인에서 그냥 밖에서 기다려. 이것과 다른 다섯 완료되면 실행. 오 개 연결, 다섯 사람이 다시 와서 일초 비즈니스 작업을 수행 할 차례를 발표했다. 초등학교 간단한 수학에 의해입니다 (5) 마지막으로 실행을 계산할 수 있습니다 얼마나 오래.이 분석에 의해, 당신이 알고, 왜 위의 로그 출력, 5 초 집합과 1과의 간격마다.

해결 방법

실제 팬들이 알고으로, 지방 소스를 읽기에 문제가 걸려있는 사람, 집단 괴롭힘을 향해 결코 지방, 적절한 주어질 것이다 其中一种솔루션을. 물론 프로그램의没有最优只有更优!

예를 들어, 연결의 최대 수를 설정, 어떤 사람들은 말할 수 있습니다, 여기 ** 참조 就像平时赞赏肥朝的金额一样小크고, 자연적으로 아무 문제가 없을 것입니다 경우 **. 물론 우리는 문제의 편의를 위해 여기 보여, 우리는 연결의 최대 수입니다 설정 비즈니스 특성과 일정한 압력 시험을 기반으로 적절한 값을 얻기 위해 생산 연결의 정상적인 수는 물론, 지방으로도 회사의 시스템 구성하는 시장보다 더 큰 일부 학생들 만 배웠습니다千元手机!!!

그러나 사실, 데이터베이스입니다 (200), 및 최대 연결 수를 설정할 때 측정 된 압력을 한 후 압력 시험 압력 크지 않다. 문제? 이전 코드에 따라서 면밀한 관찰이있을 것이다 이유

있는이 校验코드는 RPC 호출, 동료과 인터페이스가 북한처럼 지방이 아닌 值得托付终身般的高度可靠너무 오래 기다려야 이후 스레드 데이터베이스 연결 시간의 결과로, 더 이상 시간이 소요로 이어지는. 당신은 다른 초등학교 수학에 따른 계산 말했듯 그 이유는 압력 측정 문제를 이해하기 쉽습니다.

칠판에 그리기 초점 노크

북한은 비료 전에 이와 같은 사고의 깊이를 통과, 우리는? 우리는 면접 경험하기 전에 팬을보고 무엇을 얻을의 확장에 대해 생각, 문제가 반복적으로 말했다

사실, 그는 인터뷰는이 문제가 발생하고, 기본 문제를 측정하는 우리의 압력이 같은 문제가 있지만, 사실 면접관의 결론이 충분히 정확하지 않습니다.의 함께 알리바바의 개발 설명서를 살펴 보자

그래서 학대의 종류는 사실,이 방법은 종종라고해도 볼 수 있지만 모든 단일 테이블 삽입, 업데이트 작업을 향한 지방, 실행 시간이 매우 짧다?라고, 그래서 더 큰 동시성 문제가 크지 않은 곰. 열쇠는이 거래이다 보다 전통적인 기업들에서 일부 학생들이 더 많은 일을하고 있기 때문에, 모든 방법이 의미가 있는지 여부, 호출 여부 거래 방법은 트랜잭션이 키가 있는지 확인하기 위해 정말 能用就行CRUD 작업을, 그것은 쉽게입니다 서비스 방법은 직접 표시 업무 노트, 다음 트랜잭션에 관련되지 않은 문제 한푼 많은 수의 트랜잭션을 시작하며 같은이 문서의 예를 들어 등 쿼리 검사 작업, 같은 파일 IO 작업 등 시간이 많이 걸리는 작업을하고 무관했다 业务校验이 거래에서 완전히 불필요합니다. 대중, 실제 전투 장면 아무것도의 원칙 소스를 향한 지방의 수에 대해 우려하지로, 일반적으로 대응하는 실제 장면을 작동하지. 내가 고통의 원칙에 약간의 인터뷰를 요청, 인터뷰 경찰은 또한 심층 계속 방향을 변경했다!

이 경험을 통해 문제가 영원히 끝이 해결되기 때문에, 우리는? 그것 확장 어떻게 생각하지만, 우리는 지속적으로 더 많은 가치를 짜내는이 질문을 넣어 생각을 할 수 있습니다! 우리가 알리 사양 설명서를 살펴 보자

제 고장으로 요약됩니다 것은. RPC 방법을 잠금 단위를 최소화하고 RPC 방법은 요소의 네트워크를 포함하기 때문에, 잠금에서 호출 피하기 위해 노력하는 시간이 그의 통제를 호출 많은이, 너무 점유 잠금 시간을 야기하기 쉽다 긴.

사실,이 측정 압력과 우리의 문제는 동일합니다. 먼저 두 RPC의 역할을 (RPC는 분산 트랜잭션 보증 필요) 재생할 수 없습니다 로컬 트랜잭션 트랜잭션을 부르지 만, RPC 데이터베이스 연결이 너무 오래 점유하기 때문에 통제 할 수없는 요인으로 이어질 것입니다. 인터페이스 시간을 일으키는 것은 알아. 물론, 우리는 또한 수 APM시간 빗질 토폴로지 인터페이스 도구를 소모 될, 압력 시험 전에 이러한 문제가 노출되어있다.

최근에 작성된

추천

출처juejin.im/post/5cf52ed3e51d454d1d6284c4