Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Server management 기능 추가 #15

Closed
alkee-allm opened this issue Jun 18, 2020 · 9 comments · Fixed by #34
Closed

Server management 기능 추가 #15

alkee-allm opened this issue Jun 18, 2020 · 9 comments · Fixed by #34
Assignees
Labels
task normal task

Comments

@alkee-allm
Copy link
Owner

public override Task<RegisterResponse> Register(RegisterRequest request, ServerCallContext context)
{
// TODO: server management here.
var server = new Server
{
Id = "dev",
FrontendListeningPort = 5001,
PushBackendAddress = "http://localhost:5000",
LastPingTime = DateTime.Now
};

현재 임시코드 부분을 실제 동작하도록 서버-관리 기능을 추가한다

@alkee-allm alkee-allm self-assigned this Jun 23, 2020
@alkee-allm
Copy link
Owner Author

각 서버의 내부 ip 는 최초 입력된 ServerManagement backend url 을 통해 요청받은 backend 에서 ip 를 확인할 수 있겠으나, 외부 ip 가 필요한 경우 이를 알아내는 별도의 방법이 필요하다.

특히나 game server 는 matching 결과에 따라 해당 서버로 유저를 접속시켜야 하기때문에 유저가 직접 접속할 수 있는 endpoint 가 필요하기 떄문.

@alkee-allm
Copy link
Owner Author

아와 같은 아이디어에서의 문제점은 최초 IP service frontend 가 ServerManagement register 전에 별도로 존재 해야만 한다는 것.

최초의 정책 설정, 즉 해당 서버가 어떤 서비스로 실행되어야 하는지를 결정하고 기록하는 방식부터 시나리오를 잡아야 할 듯.

@alkee-allm
Copy link
Owner Author

container(docker)로 실행이 되는 경우, 결국 service TCP port 를 스스로의 힘으로 알 수 없는 이유와 마찬가지로, 외부 환경(ip-port 등)은 host 로부터 환경변수 등으로 전달받아 이를 사용하는 방식으로 진행하는 것이 가장 단순할 것.

@alkee-allm
Copy link
Owner Author

외부로부터 받은 ip(frontend address) 정보를 사용하기 위해 #28 문제가 우선 수정되어야 할 것.

@alkee-allm
Copy link
Owner Author

backend - frontend 가 하나의 서비스 위에서 동작하기 때문에 routing 시에 서로다른 주소로만 연결될 수 있도록 장치(filter)가 필요하다.

@alkee-allm
Copy link
Owner Author

alkee-allm commented Aug 25, 2020

grpc 는 별도의 routing filter 를 갖지 않기때문에 제공하는 Interceptor를 이용해야할 듯.

Interceptor 의 virtual 함수 중 UnaryServerHandler 가 서버 method 가 호출되는 경우 발생.

내부 network 에서의 호출인지 어떻게 판단하지?

context.Hostcontext.Peer 가 string 으로만 제공되기때문에, dns 사용여부 ipv4, ipv6 등의 차이 등등, 이를 이용해 내부 연결인지 확인하기가 매우 어렵다. header 에 server backend 전용 token 을 삽입하고 이를 검증하는 방식이 합리적일 것.

이렇게 하려면, backend 함수 호출시 개별적으로 호출하던 방식을 통합해 header 를 사용하도록 refactoring 되어야 한다.

public override async Task<Null> Broadacast(BroadacastRequest request, ServerCallContext context)
{
    using var channel = Grpc.Net.Client.GrpcChannel.ForAddress(config.ServerManagementBackendAddress);
    var client = new K2B.ServerManagement.ServerManagementClient(channel);
    await client.BroadcastAsync(new K2B.PushRequest
...

@alkee-allm
Copy link
Owner Author

alkee-allm commented Aug 25, 2020

각 service 별로 generated 된 stub 를 가지고 있고, 이들 각각 가지고 있는 method 들을 실행하는 구조이기 때문에 단순히 묶기(generalize)가 어렵다.
channel 과 stub 가 thread-safe 하다니 이들만이라도 재사용하도록 해볼까 생각했으나, PushBackend 와 같이 고정되지 않은 channel 들을 사용하는 경우가 많아 이역시 간단하지 않아보인다.

재사용이 가능하다 하더라도, channel 에 header 를 붙이기 위해서 channel credential 을 확정(insecure or ssl)해야 해 어려움이 있고, 그렇지 않으면 매 client call 마다 meta 를 설정해야할텐데, 이 역시 문제가 있다.

일단 header 를 확인하는 방법은, interceptor 를 grpc 에 추가하고

            services.AddGrpc(options =>
            {
                options.Interceptors.Add<Filter.BackendValidator>();
            });

UnaryServerHandler 에서 header(MetaData.Entry) 를 검사

        public override Task<TResponse> UnaryServerHandler<TRequest, TResponse>(TRequest request, ServerCallContext context, UnaryServerMethod<TRequest, TResponse> continuation)
        { // Server 의 handler 가 호출될 때
            if (IsBackendMethod(context.Method) == false) return base.UnaryServerHandler(request, context, continuation); // not interested
            if (config.BackendGroupId == context.RequestHeaders.FirstOrDefault((me) => me.Key == "BackendGroupId")?.Value)
                return base.UnaryServerHandler(request, context, continuation);

            throw new ApplicationException("invalid backend request");
        }

지저분하지만, Unity 작업(#24)에서와 마찬가지로 stub method 를 호출할때마다 header 를 parameter 로 전달.
추후에 #30 과 함께 정리가 될 수 있을 것으로 기대.

@alkee-allm
Copy link
Owner Author

최초에 생각했던 방식으로는, 서버가 시작할 때 정보(configuration)는 아무것도 가지고있지 않고 시작하고 ServerManagementServer(이하 관리서버) 에서 모든 정보(configuration)를 구성해 전달하면 이를 서버가 사용하는 방식.

관리서버가 정책에 따라 직접 Server 를 띄우는(container 생성 및 run) 상황이 아니라면, 상당히 비효율적일 것이라 생각됨.

  • 띄울 서버의 정책을 설정하고 서버의 정보(public address / port 등)등을 미리 알고 있어야 하고
  • 해당 내용을 관리서버의(또는 관리서버가 사용하는) 저장소에 반영하고
  • 실제 서비스를 띄우는 작업을 해야함.

따라서.. 관리서버는 띄워지는 서버가 요청하는 역할에 따라 서버들에 정보를 제공하고 서버들을 모니터링 하는 수준으로 한정하는 것이 좋겠다. 즉, 실제 서비스를 띄우는 시점에 띄울 서버에 직접적인 설정으로 서버 역할을 지정.

다만, 서버의 scale-out / in 시에 서버마다 해야하는 설정은 최소화(자동화 가능한 수준)하면 될 것. 심지어 K2 에서는 게임서버의 scale-in/out(container 의 생성 및 삭제 관리)이 빈번할 것으로 예상되는데 이는 이 프로젝트의 영역이 아니다. 따라서 이 project(out game server)의 scale out 이 빈번하지 않을 것이라 예상되어 오래 고민하고 복잡한 구조를 가져갈 필요성이 매우 낮다.

@alkee-allm
Copy link
Owner Author

서버통계를 제공하는 방법이나, 게임서버의 컨트롤(서버 스위칭 및 분산 연결)등은 이후 별도의 issue 에서 다루도록 할 것.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
task normal task
Projects
None yet
Development

Successfully merging a pull request may close this issue.

1 participant