我是游戏服务器设计的新手,现在被分配到一个任务来重构我们的日志服务器。我创建了一个用于游戏服务器和日志服务器之间通信的类Log。
class Log
{
public:
void encode(Encoder& encoder) const;
int decode(Decoder& decoder);
private:
std::string sql_cmd;
}
在游戏服务器上,有一个用于向日志服务器发送日志请求的类。
class LogHelper
{
public:
static void LogItemChange(const GameShare::GameItem& item, const PackageChangeDetails& pcd);
{
Log log(get_item_change_sql(item,pcd);
send_to_log_server();
}
private:
static std::string get_item_change_sql(const GameShare::GameItem& item, const PackageChangeDetails& pcd);
}
问题是:
我应该在游戏服务器上生成sql文本吗?如果在游戏服务器上生成sql文本,它对游戏服务器的性能有不良影响吗?
如果没有在游戏服务器上生成sql文本,那么应该在日志服务器上生成sql文本。我应该将GameItem和PackageChangeDetails实例数据发送到日志服务器,它会使日志服务器变得复杂,有没有人有好的想法?
答案 0 :(得分:1)
如果日志的SQL是由游戏服务器生成的,那么几乎不需要任何Log Server代码,因为它成为数据库管理器的一个直通,游戏服务器几乎肯定已经知道了(尽管我想他们可能是不同的数据库),或者可以轻松地与之互动。
Log Server应该是一个单独的组件,以任何最方便的格式(性能,详细程度,大小等)登录,并且只要API足够灵活,就可以编写这样的底层实现可以在没有游戏服务器知道的情况下更换。
通过将基础实现的完整知识与游戏服务器代码相结合,您不仅可以阻止此类未来的工作,而且您还可能在游戏服务器的代码中投入大量工作,可以通过单独的线程完成Log Server。更不用说,通过打开API到SQL,你将在游戏服务器代码上放置潜在的错误,否则这些错误将被集中化。
在设计面向对象系统时,前瞻性,替换驱动方法是理想的选择。如果你可以避免耦合到除了API以外的任何东西,那么你总是可以替换API下面的任何内容而不影响外部代码(忽略错误),但是这需要考虑放入API以确保它具有足够的灵活性以适应未来
在这方面,我强烈建议您将Logging API实现为纯虚拟接口,然后在其上编写一个与数据库对话的实现,可能还有一个记录到文本文件的单独实现(用于方便的本地测试,无需数据库访问,如果这是一个问题)以及无操作实现。考虑到前两个,它应该有助于指导您更好的设计,远离耦合。
这也可能导致其他类实现的一些基本接口(例如,public: std::string to_log_string() const;
),然后Logger可以使用它来引入任何实现对象并快速将其转换为记录的消息。 / p>
所有这一切都是说,将与日志记录相关的SQL放入Log Server而不是Game Server中。游戏服务器不应该关心Log Server除了通常“记录”之外做了什么。
答案 1 :(得分:0)
不要在游戏服务器上生成SQL文本。不要在日志服务器上执行此操作。事后的SQL应仅准备好语句。在运行时生成查询与在运行时生成索引一样疯狂。因此,将最终SQL文本的生成留给数据库。
因此,游戏服务器和日志服务器之间的API应该只包含您想要记录的变量,而不是代码。
这完全避免了SQL注入的事实是一个附带的好处。但它仍然是一个真正的好处。如果您记录的是用户名,则必须考虑SQL注入。