2011-12-28 20 views
3

我正在用java構建一個簡單的聊天服務器,用戶之間可以進行私人對話。我想將這些對話保存在服務器級別(不在客戶端),以便我可以將它們作爲對話日誌服務列出給用戶。 我也在我的軟件中使用MySQL作爲數據庫。聊天服務器:什麼是保存對話日誌的最佳(優化)方式

我在尋找的是一種優化的方式來保存這些對話,也是一種快速的方式,以便稍後列出它們。 到目前爲止,我想到了2個實現。

  1. 使用MySQL數據庫和

    一)保存在一排爲文本交談,但問題是,有些對話是非常巨大的(大量字符的),我可能有保存的問題整個談話

    b)保存在一排談話的每一行,但這樣的速度的問題會出現,當我想列出整個會話

  2. 保存在一個分隔的文本文件每次談話,但我恐怕r可能會出現ead/write問題,特別是當用戶(客戶端)非常快地寫入(發送文本)時。

感謝

+0

爲什麼 「不是在客戶端」?有沒有特定的理由不這樣做?是否還有其他要求提供純粹的「用戶自由」服務?順便說一下,什麼是巨大的?你的服務器是如何配置的? – 2011-12-28 12:21:36

+0

最自然的解決辦法是從你的問題1(b)。如果僅在兩個用戶之間發生「對話」,則他們的ID和自動增量字段可以形成體面的主鍵。或者如果你有一個對話的概念(即對話=一個聊天會話),那麼你用它作爲ID。爲什麼這會很慢? – ArjunShankar 2011-12-28 12:22:10

+0

我不會過分擔心1b的速度。即使對話持續數年,每天有幾百封郵件,但您想要一次查看所有郵件的機率很小。即使用戶打開完整歷史記錄的聊天窗口,您也可以輕鬆地在當前視口周圍預取幾行內容。無論如何,MySQL能夠比任何人都可以更快地獲得線路。 – Fredrik 2011-12-28 12:22:54

回答

9

這是很大的問題的建築,你知道的。像Facebook和Twitter這樣的公司花費了大量的時間和金錢來以可靠的方式解決您的問題。如果你的聊天服務器很簡單(就像你寫的那樣),使用1.b方式,但是創建一個抽象層(類似saveConversation,getConversation)。如果將來的速度不能滿足你,請考慮更有效的表示,比如NoSQL數據庫(LevelDB或類似的東西)。現在不要考慮性能,製作具有良好抽象和可插拔體系結構的原型。

+0

感謝您的回答。我們目前已經在使用1.b版本,即使我們正處於Beta測試階段,我們有大約30-40次會話/天,但在一個月後,mysql服務器開始運行得有點慢。我想在將來把整個數據庫移動到Apache Cassandra,但目前需要改變很多,而且我還需要在硬件上花費更多的錢,因爲apache cassandra是資源飢渴的人 – 2011-12-28 14:16:48

+2

@Doua首先想到的應該是' 「哦,我們應該真的使用NoSQL解決方案」,但更多的是「我們做錯了什麼,上帝的名字是錯誤的,選擇幾百行對話(你真的不能一次向用戶展示更多)400k排桌子需要這麼長時間?「。所以最好看看是否所有的指標都正確使用(和存在),你只選擇你真正需要的數據等等。很多人可以在那裏做。在表格模式中提出一個問題,在確定明顯的事情是正確的之後,查詢和解釋也不會造成太大的影響。 – Voo 2011-12-28 15:46:44

+0

@Voo ok。也許我寫了一個壞榜樣。我們在最短的客戶數量(beta測試人員)的情況下,在1個月內實現了40萬行。一旦我們向公衆開放服務,我們預計將有500-1000甚至更多的客戶,這將導致每月數百萬行和1年後的數百萬。桌子很簡單。它有3列:conversation_id(int),message(varchar),add_date(datetime),session_id和add_date被索引,select是這樣的:從conversation_log中選擇消息其中conversation_id = 1 order by add_date – 2011-12-28 16:23:03

-3

建議的方法都不是最佳的存儲方式。 最好的方法是在會話的基礎上使用動態表格的條形段。

這與範式的原型: -

  1. 做一個談話多個參與者。
  2. 選項確認聊天。
  3. 動作更新選項。
  4. 發佈附件的選項。
  5. 選項可以分享您當前位置的地圖座標。
  6. 離開聊天的選項。

類型

Coordinates(
    lat FLOAT(10, 6) NOT NULL , 
    lng FLOAT(10, 6) NOT NULL 
) 

架構

dbo.User(UserId,<..Details..>) 

dbo.Conversation(ConversationId,Title,CreationDate,LastActivityDate) 

指數:LastActivityDate,的conversationId表

dbo.Participants(ConversationId,UserId) 

收集 - 動態創建

msg.msg_*ConversationId*(MessageId,FromUserId,Message,Attachment,LocationCoordinates,Action,LogDate,AcknowledgeDate) 

抽象

usp_TouchMessage(@Which): 
    if (not exists (select 1 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA+'.'+TABLE_NAME = 'msg.msg_'+CAST(@Which as nvarchar(max))) 
    begin 
     @dynamic_sql = 'create table msg.msg_'+CAST(@Which as nvarchar(max))+' (MessageId uniqueidentifier,FromUserId uniqueidentifier,Message nvarchar(max),Attachment BLOB,LocationCoordinates Coordinates,Action nvarchar(max),LogDate DateTime, AcknowledgeDate DateTime);'; 
     exec(@dynamic_sql); 
     @dynamic_sql = 'CREATE TRIGGER msg.trig_msg_'+CAST(@Which as nvarchar(max))+' ON msg.msg_'+CAST(@Which as nvarchar(max))+' AFTER INSERT AS Delete From msg.msg_'+CAST(@Which as nvarchar(max))+' where MessageId in (Select MessageId,ROW_NUMBER() OVER (order by LogDate Desc,AcknowledgeDate Desc,MessageId Desc) RN from msg.msg_'+CAST(@Which as nvarchar(max))+') where RN>=5000'; 
     exec(@dynamic_sql); 

    end 

usp_GetParticipants(@Where) : 
    Select User.UserId,User.FullName 
      from Participants 
       inner join Users on (
         Participants.UserId = Users.UserId 
        And Participants.ConversationId = @Where 
       ); 


usp_AddParticipants(@Who, @Where) : 
    insert into Participants(ConversationId,UserId) values (@Where, @Who); 
    @action = (select User.FullName + ' has joined the chat' from User where User.UserId = @Who); 
    update Conversation set LastActivityDate = GETUTCDATE() where ConversationId = @conversation_id; 
    exec usp_TouchMessage(@Where); 
    @dynamic_sql = 'insert into msg.msg_'+CAST(@Where as nvarchar(max))+' (MessageId,FromUserId,Action,LogDate) values (NewId(),@Who,@Action,GETUTCDATE())'; 
    sp_executesql @dynamic_sql, N'@Who uniqueidentifier,@Action nvarchar(max)', @Who = @Who, @Action = @Action; 


usp_GetConversationList() : 
    With Participation As (
     Select User.UserId,User.FullName,Participants.ConversationId 
      from Participants 
       inner join Users on (Participants.UserId = Users.UserId) 
    ) select Conversation.*, 
      (STUFF((
        SELECT ',' + CAST([FullName] AS nvarchar(max)) 
         FROM Participation 
        WHERE (Participation.ConversationId = Conversation.ConversationId) 
       FOR XML PATH ('') 
      ),1,1,'')) ParticipantList 
     from Conversation 
    order by Conversation.LastActivityDate; 


usp_GetConversationById(@Which,@Lite = 0,@Page = 1) : 
    Select User.UserId,User.FullName 
      from Participants 
      inner join Users on (Participants.UserId = Users.UserId and Participants.ConversationId = @Which); 
    @dynamic_sql = 'select * from 
         (select u.UserId,u.FullName,m.MessageId,' 
           +(case when @Lite=1 then 'm.Message,m.LocationCoordinates,m.Attachment,m.Action,' else '' end) 
           +'m.LogDate,m.AcknowledgeDate, ROW_NUMBER() Over (order by m.LogDate Desc,m.AcknowledgeDate Desc,m.MessageId Desc) RN 
          From msg.msg_'+CAST(@Which AS nvarchar(max))+' m 
          inner join User u on (m.FromUserId = u.UserId) 
         ) tmp 
        where RN Between ((@Page-1)*20+1) AND (@Page*20+1) 
       '; 
    sp_executesql @dynamic_sql, N'@Page bigint', @Page = @Page; 
    If @Page = 1 And @Lite=0 
    begin 
     @dynamic_sql = 'update msg.msg_'+CAST(@Which as nvarchar(max))+' Set AcknowledgeDate = GETUTCDATE() where AcknowledgeDate is null and FromUserId <> @Who'; 
     sp_executesql @dynamic_sql, N'@Who uniqueidentifier', @Who = @Who; 
    end 

usp_GetConversation(@Who,@WithWhome,@Lite = 0,@Page = 1) : 
    @conversation_id = (
     Select top 1 ConversationId 
      from Participants self 
      inner join Participants partner 
       on (self.ConversationId = partner.ConversationId and self.UserId = @Who and partner.UserId = @WithWhome) 
      where (Select count(1) from Participants where ConversationId = self.ConversationId) = 2 
    ); 
    if(@conversation_id is not null) 
    then 
     exec usp_GetConversationById(@conversation_id, @Lite, @Page); 
    end 


usp_PostConversationById(@Who,@Which,@WhatMessage,@WhichLocation,@WhatAttachment) : 
    update Conversation set LastActivityDate = GETUTCDATE() where ConversationId = @Which; 
    exec usp_TouchMessage(@Which); 
    @dynamic_sql = 'insert into msg.msg_'+CAST(@Which as nvarchar(max))+' (MessageId,FromUserId,Message,Attachment,LocationCoordinates,LogDate) values (NewId(),@Who,@WhatMessage,@WhichLocation,@WhatAttachment,GETUTCDATE())'; 
    sp_executesql @dynamic_sql, N'@Who uniqueidentifier,@WithWhome uniqueidentifier,@WhatMessage nvarchar(max),@WhichLocation Coordinates,@WhatAttachment BLOB', @Who = @Who, @WhatMessage = @WhatMessage, @WhichLocation = @WhichLocation, @WhatAttachment = @WhatAttachment; 


usp_PostConversation(@Who,@WithWhome,@WhatMessage,@WhichLocation,@WhatAttachment) : 
    @conversation_id = (
     Select top 1 ConversationId 
      from Participants self 
      inner join Participants partner 
       on (self.ConversationId = partner.ConversationId and self.UserId = @Who and partner.UserId = @WithWhome) 
      where (Select count(1) from Participants where ConversationId = self.ConversationId) = 2 
    ); 
    if(@conversation_id is not null) 
    then 
     @conversation_id = newid() 
     insert into Conversation(ConversationId,CreationDate) values (@conversation_id,GETUTCDATE()); 
     exec usp_AddParticipants(@Who,@conversation_id); 
     exec usp_AddParticipants(@WithWhome,@conversation_id); 
    end 
    exec usp_PostConversationById(@Who,@conversation_id,@WhatMessage,@WhichLocation,@WhatAttachment); 


usp_UpdateConversationAlias(@Who,@Which,@WithWhat) : 
    @action = (select User.FullName + ' has changed title'+isnull(' from <b>'+Conversation.Title+'</b>','')+isnull(' to <b>'[email protected]+'</b>','') from User inner join Conversation on (Conversation.ConversationId = @Which and User.UserId = @Who)); 
    update Conversation set LastActivityDate = GETUTCDATE(), Title = @WithWhat where ConversationId = @conversation_id; 
    if (not exists (select 1 from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA+'.'+TABLE_NAME = 'msg.msg_'+CAST(@Which as nvarchar(max))) 
    exec usp_TouchMessage(@Which); 
    @dynamic_sql = 'insert into msg.msg_'+CAST(@Which as nvarchar(max))+' (MessageId,FromUserId,Action,LogDate) values (NewId(),@Who,@Action,GETUTCDATE())'; 
    sp_executesql @dynamic_sql, N'@Who uniqueidentifier,@Action nvarchar(max)', @Who = @Who, @Action = @Action; 


usp_LeaveConversation(@Who,@Which) : 
    delete from Participants where ConversationId = @Where and UserId = @Who; 
    if(not exists (Select 1 From Participants Where ConversationId = @Which)) 
    begin 
     @dynamic_sql = 'drop table msg.msg_'+CAST(@Which as nvarchar(max))+'; 
     exec @dynamic_sql; 
     delete from Conversation where ConversationId = @Which; 
    end 
    else 
    begin 
     @action = (select User.FullName + ' has left the chat' from User where User.UserId = @Who); 
     update Conversation set LastActivityDate = GETUTCDATE() where ConversationId = @conversation_id; 
     exec usp_TouchMessage(@Which); 
     @dynamic_sql = 'insert into msg.msg_'+CAST(@Which as nvarchar(max))+' (MessageId,FromUserId,Action,LogDate) values (NewId(),@Who,@Action,GETUTCDATE())'; 
     sp_executesql @dynamic_sql, N'@Who uniqueidentifier,@Action nvarchar(max)', @Who = @Who, @Action = @Action; 
    end 
相關問題