지난 이야기를 마무리하면서, consul을 구성했다. consul이 잘 작동한다면 절반의 성공을 거뒀다고 보면 된다. 이제 DarkRift2를 리눅스에서 실행하는 법과 서비스를 consul에 등록해서 DarkRift2 서버끼리 통신하는 법만 남았다.
공식 가이드를 제공하긴 하지만.. 깃허브에서 제공하는 가이드는
dotnet DarkRift.Server.Console.dll
이 부분만 중요하다. 왜냐하면 어차피 DarkRift2 소스가 무료로 모두 공개 되었기 때문에 빌드하면 되기 떄문이다.
우선 기존의 DarkRift.Consoel.exe 는 .Net FrameWork로 빌드 되었다. 그래서 리눅스에서 별 짓을 해도 잘 되지 않는다.
따라서 우리는 DarkRift.Console을 dll로 뽑아내서 리눅스에서 실행할 것이다.
sudo apt-get update && \
sudo apt-get install -y dotnet-sdk-6.0
터미널을 열고 이렇게 .Net Core가 설치가 된다. 실행하려면 donet 명령어가 필요하다.
솔루션 뷰어에서 / DakrRift / DarkRift.Client / DarkRift.Server / DarkRift.Server.Console / 이렇게 네 개의 프로젝트를 제외하고 마우스 오른쪽 키로 Exclude 하자. 네개만 있으면 빌드가 된다.
라이더를 사용하고 있지만, 비쥬얼 스튜디오도 프로젝트를 마우스 오른쪽 키로 눌러 속성 탭으로 들어가자. 그리고 애플리케이션 탭을 눌러보자. 출력형식과 대상 프레임워크를 닷넷으로 설정해주자. 코어 버전은 여러 개해도 되고 하나만 해도 된다. 그러나 프레임워크는 닷넷 코어로 해야한다. 꼭
그리고 그냥 빌드를 새로 뽑으면 된다.
\DarkRift.Server.Console\bin\Debug\net6.0 폴더를 DarkRift.Server.Console.zip 이런식으로 압축해주고 리눅스에 던져주자.
빌드를 새로 했다면, 안에 server.config 파일이 있을 것이고 cluster.config는 없을 것이다.
나중에 cluster.config 파일만 따로 하나 만들어 주자.
우선 server.config 작성 부분이다.
....
<server maxStrikes="3" />
....
<server maxStrikes="3" serverGroup ="groupName"/>
<serverRegistry advertisedHost="abc.def.ghi.jkl">
<serverRegistryConnector type="ConsulServerRegistryConnector">
<settings consulAddress="http://abc.def.ghi.jkl:8500" serviceName ="service" />
</serverRegistryConnector>
</serverRegistry>
이 부분을 바꾸면, DarkRift2가 실행될 때, ConsulServerRegistryConnector class를 찾는다. 그러므로 추후에 서버를 빌드 할 때, 커넥터를 같은 서버 프로젝트 안에 포함시켜야 한다.
groupName은 후술할 cluster.config 에 포함된 이름이어야 한다. 내가 지금 켜고자 하는 서버의 종류에 맞는 이름을 넣어둔다.
advertiseHost는 현재 DarkRift2 서버의 아이피를 입력한다. server.config 파일 아래를 살펴보면 내 서버 adress가 있다. 알맞게 바꿔주자.
<listener name="DefaultNetworkListener" type="BichannelListener" address="0.0.0.0" port="4296">
...
<plugins loadByDefault="true">
...
...
<plugins loadByDefault="true">
<plugin type="HttpHealthCheck" load="true">
<settings
port="wxyz"
host="abc.def.hij.klm"
path="/health" />
</plugin>
</plugins>
...
이렇게 함으로써, 서버 아이피 하나에 여러 포트를 구성해서 DarkRift2 서버를 실행할 수 있다. VM 여러 개를 쓸 필요가 없어진다. 단지 host는 address를 그대로 적어주지만, port는 각 서버에 맞게 다르게 할당하여야 하며, 내 서버 포트와 다르게 설정한다.
예시는 다음과 같다.
<plugins loadByDefault="true">
<plugin type="HttpHealthCheck" load="true">
<settings
port="6245"
host="localhost"
path="/health" />
</plugin>
</plugins>
<!--
Defines the settings for storing server data.
-->
<data directory="Data/"/>
<!--
Defines the listeners that will be loaded by the server.
-->
<listeners>
<listener name="LogicServerListener" type="BichannelListener" address="127.0.0.1" port="5500">
<settings noDelay="true" />
</listener>
</listeners>
<server maxStrikes="3" serverGroup ="groupName"/>
<?xml version="1.0" encoding="utf-8" ?>
<cluster>
<groups>
<group name="group1" visibility="external">
<connectsTo name="group2" />
</group>
<group name="group2" visibility="internal" />
<group name="group3" visibility="internal" />
</groups>
</cluster>
<connectsTo name="otherGroupName" />
마지막으로 C# 코딩을 통해, 현재 다크리프트 서비스를 consul에 등록하는 절차가 남았다.
<serverRegistryConnector type="ConsulServerRegistryConnector">
이 부분에서 ConsulServerRegistryConnector 대신에 다른 타입을 써도 상관 없지만, 개발진에서 제공하는 기본 스크립트가 있기 때문에 굳이 수정할 필요는 없다.
이 스크립트에서 namespace를 지우고 , consul.dll은 NuGet에서 받아서 사용한다.
수정 전
private readonly string healthCheckUrl = "http://localhost:10666/health";
여기서 localhost는 server.config에서 작성했던 부분과 같게 적는다.
<plugins loadByDefault="true">
<plugin type="HttpHealthCheck" load="true">
<settings
port="wxyz"
host="abc.def.hij.klm"
path="/health" />
</plugin>
</plugins>
수정 후
private readonly string healthCheckUrl = "http://abc.def.hij.klm:wxyz/health";
굳이 여러 아이피를 둘 필요가 없이, port 부분만 바꿔주면 하나의 아이피에서 여러 콘솔을 실행할 수 있다.
AgentServiceCheck healthCheck = new AgentServiceCheck()
{
HTTP = healthCheckUrl,
Interval = healthCheckPollInterval,
DeregisterCriticalServiceAfter = healthCheckTimeout
};
AgentServiceRegistration service = new AgentServiceRegistration
{
ID = id.ToString(),
Name = serviceName,
Address = host,
Port = port,
Tags = new string[] { "group:" + group },
Meta = properties,
Check = healthCheck,
};
host와 port는 그냥 두면 알아서 현재 서버의 아이피와 포트를 가져다 입력한다. 여기서 중요한 부분은 아래와 같다.
먼저 Name의 경우 server.config에서 작성한 다음 부분을 살펴보자.
...
<settings consulAddress="http://abc.def.ghi.jkl:8500" serviceName ="service" />
...
serviceName 이라는 항목이 있다. 이 항목과 위 스크립트의 Name이 같게 설정되어야 한다.
그리고 Tags도 중요하다. group은 clust.config와 server.config에서 설정했던 부분이다. group으로 잡아두면 알아서 입력하지만 group 앞에 "group:" 이 반드시 포함되어야 한다.
그리고 이 설정된 service와 healthCheck는 해당 스크립트 client.Agent.ServiceRegister(service);에서 실행된다.
try
{
await client.Agent.ServiceRegister(service);
}
catch (Exception e)
{
Logger.Error("Failed to register server with Consul as an exception occurred.", e);
throw e;
}
이후 , http://bind_addr:8500 에 들어가서 Service 와 Node 탭을 확인해 보면 알맞게 적용 됨을 알 수 있다.
예시 - 5개의 서비스(서버) 연결
여기까지 잘 따라왔다면, 95%정도 되었다.
서버 실행 방법은 다음과 같다.
...
cd Foo/MyServerConsoleDll
dotnet DarkRift.Server.Console.dll
...
foreach(var group in RemoteManager.GetAllGroups())
{
group.ServerJoined += OnServerJoined;
group.ServerLeft += OnServerLeft;
}
private void OnServerJoined(object? sender, ServerJoinedEventArgs e)
{
e.RemoteServer.ServerConnected += OnServerConnected;
e.RemoteServer.ServerDisconnected += OnServerDisconnected;
}
private void OnServerLeft(object? sender, ServerLeftEventArgs e)
{
e.RemoteServer.ServerConnected -= OnServerConnected;
e.RemoteServer.ServerDisconnected -= OnServerDisconnected;
}
private void OnServerConnected(object? sender, ServerConnectedEventArgs e)
{
e.RemoteServer.MessageReceived += OnServerMessageReceived;
}
private void OnServerDisconnected(object? sender, ServerDisconnectedEventArgs e)
{
e.RemoteServer.MessageReceived -= OnServerMessageReceived;
}
이때의 e.RemoteServer는 연결된 원격 서버로 예를들어 위의 clust.config를 중심으로 설명하자면
Group1의 e.RemoteServer 는 Group2 이고
Group2의 e.RemoteServer 는 Group1 이다.
ex. Write - DarkRiftWriter
using(DarkRiftWriter writer = DarkRiftWriter.Create())
{
...어쩌구저쩌구.. 보낼 메시지를 정리한다.
using (Message message = message.Create((ushort)Tag.Tags.Foo, writer))
e.RemoteServer.SendMessage(msg, SendMode.Reliable);
}
ex. Read - DarkRiftReader
using(Message message = e.GetMessage())
{
using (DarkRiftReader reader = message.GetReader())
{
var tag = reader.ReadUInt16();
var str = reader.ReadString();
}
}
여기까지가 DarkRift2 - cluster 기능 가이드다. 이제는 무료가 된 에셋인 DarkRift2를 잘 활용해보자.