네트워크
글 11개
MagicOnion 은 StreamingHub 에서만 자기 몫의 할당을 없앴다
MagicOnion 을 빼고 같은 일을 하는 gRPC 와 비교하면, StreamingHub 왕복은 할당이 같고 Unary 는 호출당 약 1.6 KB 에 페이로드 1바이트마다 1바이트를 더 씁니다. 상자, 마샬러, 풀이 그 차이를 만듭니다.
MagicOnion 의 Unity 패키지는 채널과 허브를 한 곳에서 닫는다
Unity 에디터는 플레이 모드를 꺼도 프로세스가 살아서, 닫지 않은 채널과 허브 수신 루프가 남습니다. MagicOnion 의 Unity 패키지는 모든 채널을 레지스트리 하나에 모아 종료 때 허브, 채널 순서로 닫습니다.
MagicOnion 의 필터는 메서드를 바인딩할 때 한 번 조립된다
필터는 요청마다 불리는 것처럼 보이지만, 사슬과 필터 인스턴스는 MapMagicOnionService 가 메서드를 바인딩할 때 한 번 만들어집니다. 그래서 요청당 할당은 0 이고, 대신 필터 필드와 생성자 주입은 모든 요청이 나눠 씁니다.
MagicOnion 의 하트비트는 상대의 메시지 처리 루프를 잰다
네트워크는 멀쩡한데 하트비트가 연결을 끊습니다. MagicOnion 의 하트비트는 PING 이 아니라 허브 메시지라서, 답이 상대의 처리 루프를 지나야 나오기 때문입니다. 메인 스레드가 멈추거나 서버 요청 큐가 차면 끊깁니다.
MagicOnion 의 그룹 브로드캐스트는 한 번 직렬화하고 연결마다 복사한다
방에 50명이 있어도 room.All.OnMessage 한 번은 직렬화를 한 번만 하고, 받는 연결마다 바이트를 복사해 응답 큐에 넣고 돌아옵니다. 대신 Single 을 돌리면 직렬화가 사람 수만큼이고, 느린 수신자는 알림 없이 끊깁니다.
MagicOnion 의 StreamingHub 클라이언트는 리시버를 연결한 곳의 스레드에서 부른다
같은 허브 연결인데 await 뒤 코드와 리시버가 다른 스레드에서 돕니다. 응답은 기다린 곳의 컨텍스트로, 리시버는 ConnectAsync 때 잡은 컨텍스트로 가고, 컨텍스트가 없으면 리시버가 수신 전체를 막습니다.
MagicOnion 의 StreamingHub 는 한 연결의 호출을 한 줄로 세운다
허브 메서드는 gRPC 메서드가 아니라 Connect 스트림 하나 위의 메시지입니다. 서버는 연결마다 용량 10 짜리 큐와 소비 루프 하나로 호출을 순서대로 처리하고, 이 큐가 차면 수신 루프가 멈춰 교착이 납니다.
MagicOnion 클라이언트는 인터페이스 구현을 Emit 이나 소스 생성기로 만든다
MagicOnionClient.Create 는 인터페이스만 받는데 구현 객체를 돌려줍니다. JIT 에서는 Reflection.Emit, IL2CPP 에서는 소스 생성기가 같은 모양의 클래스를 만들고, 생성기를 켜면 동적 경로는 사라집니다.
MagicOnion 의 Unary 는 요청마다 ServiceContext 와 서비스 인스턴스를 새로 만든다
서비스 코드는 this.Context 로 요청 정보를 읽습니다. MagicOnion 은 호출마다 인스턴스를 받아 Context 속성을 채우므로, 서비스를 싱글턴으로 등록하면 동시 요청 200건 중 199건이 남의 컨텍스트를 봤습니다.
MagicOnion 은 MapMagicOnionService 안에서 인터페이스를 gRPC 메서드로 등록한다
.proto 도 생성 코드도 없는데 /IMathService/SumAsync 가 생깁니다. MapMagicOnionService 가 로드된 어셈블리를 훑어 grpc-dotnet 확장점에 메서드를 넣기 때문이고, 그래서 규칙에 안 맞는 서비스는 경고 없이 빠집니다.
MagicOnion 은 .proto 대신 C# 인터페이스를 스키마로 쓴다
gRPC 는 .proto 와 코드 생성을 요구합니다. MagicOnion 은 서버와 클라이언트가 같은 C# 인터페이스를 컴파일하는 것으로 그 자리를 채우고, 전송은 gRPC(HTTP/2)에 맡깁니다. 대신 이름이 곧 와이어 계약입니다.