Nginx에 대한 자료를 읽으면서 단일 소켓에서 들어오는 연결을 수락하는 두 가지 전통적인 방법 중 하나가 다음과 같다는 것을 알았습니다.
단일 포트에서 실행되는 다중 스레드 서버에서 사용되는 두 번째 전통적인 접근 방식은 다음과 같습니다.모든 스레드(또는 프로세스)를 소유합니다.
accept()
다음 형식의 간단한 이벤트 루프에서 단일 청취 소켓에 대한 호출이 이루어집니다.while (1) { new_fd = accept(...); process_connection(new_fd); }
에서 인용SO_REUSEPORT 소켓 옵션.
그러다가 Nginx도 이 접근 방식을 사용하는 것 같았습니다.
표시된 대로
SO_REUSEPORT
옵션이 활성화되지 않으면 단일 수신 소켓이 작업자 스레드에 들어오는 연결에 대해 알리고 각 작업자 스레드는 연결을 얻으려고 시도합니다.
에서 인용NGINX 버전 1.9.1의 소켓 샤딩:
아진아 여기야오픈 소스 애플리케이션 아키텍처(2권): nginxaccept
, 다음과 같은 키워드로 페이지를 검색하세요 .
앞서 언급했듯이 nginx는 각 연결에 대해 프로세스나 스레드를 생성하지 않습니다. 대신에,작업자 프로세스는 공유된 "수신" 소켓의 새 요청을 수락하고 각 작업자 프로세스 내에서 효율적인 실행 루프를 실행하여 작업자 프로세스당 수천 개의 연결을 처리합니다.nginx에는 전용 쿼럼이나 작업자에 대한 연결 할당이 없습니다. 이 작업은 운영 체제 커널 메커니즘에 의해 수행됩니다.
그래서정말 충격받았어아무도 나에게 프로세스나 스레드에 걸쳐 청취 소켓을 받아들이는 것이 괜찮고 결과가 좋지 않다고 말하지 않았기 때문입니다.경쟁 조건.
왜냐하면 공유자원을 활용하면 가장 먼저 떠오르는 것이 "이 함수 호출은 스레드로부터 안전합니까?"? 그래서 구글링을 하다가 StackOverflow에서 관련 질문을 찾았습니다.
허용된 답변은 다시 한 번 이 동작을 보여 주지만 참조를 전혀 제공하지 않으며 댓글 아래의 사람들은 여전히 공식 문서의 정의에 대해 논쟁을 벌이고 있습니다.
thread-safe
그 시점에서는 멀티스레딩이라고 되어 있어서 주어진 속성이 충분하지 않다고 생각했습니다.또는 프로세스 accept
단일 청취 소켓에서. 나에겐 이것보다 더 강력한 것이 필요하다.
그래서 책을 읽으러 왔어요리눅스 프로그래밍 인터페이스, 존재하다§5.1 원자성과 경쟁 조건, 그것은 다음과 같이 씁니다:
원자성은 시스템 호출 작업을 논의할 때 계속해서 접하게 되는 개념입니다. 다양한 시스템 호출 작업이 원자적으로 수행됩니다. 우리가 의미하는 바는 커널이 다른 프로세스나 스레드의 방해 없이 작업의 모든 단계가 완료되도록 보장한다는 것입니다.
원자성은 특정 작업을 성공적으로 완료하는 데 중요합니다. 특히 이를 통해 경쟁 조건(레이스 위험이라고도 함)을 피할 수 있습니다. 경쟁 조건은 공유 리소스에서 실행 중인 두 프로세스(또는 스레드)가 프로세스가 CPU에 액세스하는 상대적 순서에 따라 예상치 못한 방식으로 의존하는 결과를 생성하는 상황입니다.
그래서 내가 필요한 단어/속성은대기또는원자성.
그래서 내 질문은 다음과 같습니다
여러 프로세스나 스레드에서 청취 소켓을 수락하는 것이 원자적 작업이라고 말하는 권위 있는 곳이 있습니까?
몇 시간 동안 검색한 후에도 온라인에서 참조 자료를 찾을 수 없습니다.
답변1
https://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html
accept()
"비동기 신호 안전" 기능으로 나열됩니다. 모든 비동기 신호 안전 함수는 스레드로부터 안전하다는 것이 아래에 설명되어 있습니다. 잠금 해제된 stdio 함수와 같은 스레드 안전을 위해 일부 특정 예외가 나열되어 있습니다 accept()
.아니요말하는.
여기서는 accept
시스템 호출이라는 점에 유의하세요. 커널이 스레드로부터 안전하지 않다는 의미이므로 시스템 호출이 스레드로부터 안전하지 않다는 것은 말이 되지 않습니다!
커널은 스레드로부터 안전해야 하므로 시스템 호출도 스레드로부터 안전해야 합니다.