本文目錄一覽:
- 1、使用Go 語言開發大型 MMORPG 遊戲服務器怎麼樣
- 2、嵌入式golang佔用內存高
- 3、golang如何去封裝外部接口
- 4、socket 通信粘包怎麼處理
- 5、Golang中的自定義json序列化
- 6、深入理解golang
使用Go 語言開發大型 MMORPG 遊戲服務器怎麼樣
從2013年起,經朋友推薦開始用Golang編寫遊戲登陸服務器, 配合C++做第三方平台驗證. 到編寫獨立工具導表工具GitHub – davyxu/tabtoy: 跨平台的高性能便捷電子表格導出器. 以及網絡庫GitHub – davyxu/cellnet: 簡單,方便,高效的Go語言的遊戲服務器底層. 最終使用這些工具及庫編寫整個遊戲服務器框架, 我的感受是很不錯的
細節看來, 有如下的幾個點:
語言, 庫
Golang語言特性和C很像, 簡單, 一張A4紙就能寫完所有特性. 你想想看, C++到了領悟階段, 也只用那幾個簡單特性, 剩下的都是一大堆解決各種內存問題的技巧. 而Golang一開始就簡單, 何必浪費生命去研究那一大堆的奇技淫巧呢?
Golang的坑只有2個:1. interface{}和nil配合使用, 2. for循環時, 將循環變量引入閉包(Golang, Lua, C#閉包變量捕獲差異) 完全不影響正常使用, 複合語言概念, 只是看官方後面怎麼有效的避免
用Golang就忘記繼承那套東西, 用組合+接口
用Golang服務器如何保證解決遊戲服務器存盤一致性問題? stop the world是肯定的, 但是Golang可以從語言層並發序列化玩家數據, 再通過後台存盤
channel是goroutine雖然是Golang的語言特性. 但是在編寫服務器時, 其實只有底層用的比較多.
Golang的第三方庫簡直多如牛毛, 好的也很多
不要說模板了, C#的也不好用, 官方在糾結也不要加, 使用中, 沒模板確實有點不方便. 用interface{}/反射做泛型對於Golang這種強類型語言來說,還是有點打臉
運行期
Golang和C++比性能的話, 這是C++的優勢, Golang因為沒虛擬機, 只有薄薄的一層調度層. 因此性能是非常高的, 用一點性能犧牲換開發效率, 妥妥的
1.6版後的GC優化的已經很好了, 如果你不是高性能,高並發Web應用, 非要找出一堆的優化技巧的話. 只用Golang寫點遊戲服務器, 那點GC損耗可以忽略不計
和其他現代語言一樣, 崩潰捕捉是標配功能, 我用Golang的服務器線上跑, 基本沒碰到過崩潰情況
熱更新: 官方已經有plugin系統的提交, 跨平台的. 估計很快就可以告別手動cgo做so熱更新
開發, 調試, 部署, 優化
LiteIDE是我首選的Golang的IDE, 雖然有童鞋說B格不高. 但這估計實在是找不到缺點說了, 別跟我說Visual Studio, 那是宇宙級的…
曾經聽說有人不看好Golang, 我問為啥: 說這麼新的語言, 不好招人,後面打聽到他是個策劃… 好吧
真實情況是這樣的: Golang對於有點編程基礎的新人來說, 1周左右可以開始貢獻代碼. 老司機2~3天.
開發效率還是不錯的, 一般大的遊戲功能, 2*2人一周3~4個整完. 這換C++時代, 大概也就1~2個還寫不完. 對接服務器sdk的話, 大概1天接個10多個沒問題
Golang自帶性能調優工具, 從內存, CPU, 阻塞點等幾個方面直接出圖進行分析, 非常直觀, 可以參考我博客幾年前的分析: 使用Golang進行性能分析(Profiling)
Golang支持交叉編譯, 跨平台部署, 什麼概念? linux是吧? 不問你什麼版本, 直接windows上編譯輸出一個elf, 甩到服務器上開跑.不超過1分鐘時間..
嵌入式golang佔用內存高
嵌入式golang佔用內存高可能問題在於緩存。
清空日誌後比較驚喜地發現,內存瞬間暴降至20M。
嵌入式系統由硬件和軟件組成.是能夠獨立進行運作的器件。其軟件內容只包括軟件運行環境及其操作系統。硬件內容包括信號處理器、存儲器、通信模塊等在內的多方面的內容。相比於一般的計算機處理系統而言,嵌入式系統存在較大的差異性,它不能實現大容量的存儲功能,因為沒有與之相匹配的大容量介質,大部分採用的存儲介質有E-PROM、EEPROM等,軟件部分以API編程接口作為開發平台的核心。嵌入式系統最核心的層次是中央處理單元部分,它包含運算器和控制器模塊,在cpu的基礎上進一步配上存儲器模塊、電源模塊、複位模塊等就構成了通常所說的最小系統。由於技術的進步,集成電路生產商通常會把許多外設做進同一個集成電路中,這樣在使用上更加方便,這樣一個芯片通常稱之為微控制器。在微控制器的基礎上進一步擴展電源傳感與檢測、執行器模塊以及配套軟件並構成一個具有特定功能的完整單元,就稱之為一個嵌入式系統或嵌入式應用。
golang如何去封裝外部接口
1.為什麼golang的開發效率高?golang是一編譯型的強類型語言,它在開發上的高效率主要來自於後發優勢,不用考慮舊有噁心的歷史,又有一個較高的工程視角。良好的避免了程序員因為“{需不需要獨佔一行”這種革命問題打架,也解決了一部分趁編譯時間找產品妹妹搭訕的階級敵人。它有自己的包管理機制,工具鏈成熟,從開發、調試到發布都很簡單方便;有反向接口、defer、coroutine等大量的syntacticsugar;編譯速度快,因為是強類型語言又有gc,只要通過編譯,非業務毛病就很少了;它在語法級別上支持了goroutine,這是大家說到最多的內容,這裡重點提一下。首先,coroutine並不稀罕,語言並不能超越硬件、操作系統實現神乎其神的功能。golang可以做到事情,其他語言也可以做到,譬如c++,在boost庫裡面自己就有的coroutine實現(當然用起來跟其他boost庫一樣噁心)。golang做的事情,是把這一套東西的使用過程簡化了,並且提供了一套channel的通信模式,使得程序員可以忽略諸如死鎖等問題。goroutine的目的是描述並發編程模型。並發與並行不同,它並不需要多核的硬件支持,它不是一種物理運行狀態,而是一種程序邏輯流程。它的主要目的不是利用多核提高運行效率,而是提供一種更容易理解、不容易出錯的語言來描述問題。實際上golang默認就是運行在單OS進程上面的,通過指定環境變量GOMAXPROCS才能轉身跑在多OS進程上面。有人提到了網易的pomelo,開源本來是一件很不錯的事情,但是基於自己對callbackhell的偏見,我一直持有這種態度:敢用nodejs寫大規模遊戲服務器的人,都是真正的勇士:)。2、Erlang與Golang的coroutine有啥區別,coroutine是啥?coroutine本質上是語言開發者自己實現的、處於userspace內的線程,無論是erlang、還是golang都是這樣。需要解決沒有時鐘中斷;碰着阻塞式i\o,整個進程都會被操作系統主動掛起;需要自己擁有調度控制能力(放在並行環境下面還是挺麻煩的一件事)等等問題。那為啥要廢老大的勁自己做一套線程放userspace裡面呢?並發是服務器語言必須要解決的問題;systemspace的進程還有線程調度都太慢了、佔用的空間也太大了。把線程放到userspace的可以避免了陷入systemcall進行上下文切換以及高速緩衝更新,線程本身以及切換等操作可以做得非常的輕量。這也就是golang這類語言反覆提及的超高並發能力,分分鐘給你開上幾千個線程不費力。不同的是,golang的並發調度在i/o等易發阻塞的時候才會發生,一般是內封在庫函數內;erlang則更誇張,對每個coroutine維持一個計數器,常用語句都會導致這個計數器進行reduction,一旦到點,立即切換調度函數。中斷介入程度的不同,導致erlang看上去擁有了preemptivescheduling的能力,而golang則是cooperativeshceduling的。golang一旦寫出純計算死循環,進程內所有會話必死無疑;要有大計算量少i\o的函數還得自己主動叫runtime.Sched()來進行調度切換。3、golang的運行效率怎麼樣?我是相當反感所謂的ping\pong式benchmark,運行效率需要放到具體的工作環境下面考慮。首先,它再快也是快不過c的,畢竟底下做了那麼多工作,又有調度,又有gc什麼的。那為什麼在那些benchmark裡面,golang、nodejs、erlang的響應效率看上去那麼優秀呢,響應快,並發強?並發能力強的原因上面已經提到了,響應快是因為大量非阻塞式i\o操作出現的原因。這一點c也可以做到,並且能力更強,但是得多寫不少優質代碼。然後,針對遊戲服務器這種高實時性的運行環境,GC所造成的跳幀問題確實比較麻煩,前面的大神@達達有比較詳細的論述和緩解方案,就不累述了。隨着golang的持續開發,相信應該會有非常大的改進。一是屏蔽內存操作是現代語言的大勢所趨,它肯定是需要被實現的;二是GC算法已經相當的成熟,效率勉勉強強過得去;三是可以通過incremental的操作來均攤cpu消耗。用這一點點效率損失換取一個更高的生產能力是不是值得呢?我覺得是值得的,硬件已經很便宜了,人生苦短,讓自己的生活更輕鬆一點吧:)。4、基於以上的論述,我認為採用go進行小範圍的MMORPG開發是可行的。
socket 通信粘包怎麼處理
一、socket 通信粘包的處理方法:
1、對於發送方引起的粘包現象,用戶可通過編程設置來避免,TCP提供了強制數據立即傳送的操作指令push,TCP軟件收到該操作指令後,就立即將本段數據發送出去,而不必等待發送緩衝區滿;
2、對於接收方引起的粘包,則可通過優化程序設計、精簡接收進程工作量、提高接收進程優先級等措施,使其及時接收數據,從而盡量避免出現粘包現象;
3、由接收方控制,將一包數據按結構字段,人為控制分多次接收,然後合併,通過這種手段來避免粘包。
二、實現代碼:
三、方法注意事項:
1、第一種編程設置方法雖然可以避免發送方引起的粘包,但它關閉了優化算法,降低了網絡發送效率,影響應用程序的性能,一般不建議使用。
2、第二種方法只能減少出現粘包的可能性,但並不能完全避免粘包,當發送頻率較高時,或由於網絡突發可能使某個時間段數據包到達接收方較快,接收方還是有可能來不及接收,從而導致粘包;
3、第三種方法雖然避免了粘包,但應用程序的效率較低,對實時應用的場合不適合。
四、實驗環境
1、硬件環境:服務器:pentium 350 微機 、客戶機:pentium 166微機、網絡平台:由10兆共享式hub連接而成的局域網;
2、軟件環境:操作系統:windows 98 、編程語言:visual c++ 5.0
Golang中的自定義json序列化
後端開發人員跟前端對接接口的時候,或多或少都會面臨一些溝通問題,比如說枚舉字符的定義,比如有整形狀態字段: state
通常給前端的時候,前段要做的是將1,2,3以及對應的中文釋義存儲為key/value的形式,key與value單看都無法知道對方的語義,
比如我只知道狀態值為“1”, 是無法將其與“成功”對應起來的(當然這套狀態的設計者肯定是知道的),後端通常給到前端的restful api
接口定義也是key/value的形式,這乍一看其實也沒啥毛病,只要有key/value也沒問題,後端定義通常會是
但數字的表現形式終歸是不不太明確的,如果對狀態的定義換成以下形式:
基本可以理解為中英文互譯了,理解起來也會更清晰一些不是,如果這麼做的話,後端給到前端的響應字段狀態的類型就需要修改成字符器格式
後端還是要做一層字符串到整型的轉換,從目的來講,我們只是想返給前端的 state 字段是字符串而已,也就是在做json序列化的時候將整型與字符串做一層轉換,有更優雅的做法如下所示
只需要做兩件事,自定義類型 MyState ,實現 MarshalJSON 方法
只要類型實現了 MarshalJSON 方法,在json序列化時就會調用此方法,如此一來,我們就輕鬆實現了自定義json序列化,反序列化同樣如此
實現起來也很簡單
需要注意的是, UnmarshalJSON 方法操作過程需要給 receiver 也就是 u 賦值,所以必須是指針類型,同樣的,在實現
MarshalJSON 方法, receiver 的類型需要與結構體定義中的類型保持一致,否則自定義序列化會失敗
參考:
深入理解golang
最近三年,在工作中使用go開發了不少服務。深感go的便捷,以及它的runtime的複雜。我覺得需要定期的進行總結,因此決定寫這篇文章,也許更準確的,應該叫筆記。
最近終於解決了一個和cgo有關的問題。這個問題從發現到解決前後經歷了接近4個月,當然,和人手不足也有關係。而對於我個人而言,這個問題其實歷時2年!這得從頭說起。
在上一家公司的一個項目里,有一個服務做音視頻數據的提取,這個服務運行在嵌入式設備TX2上。音視頻提取這一關鍵功能主要利用nvidia基於gstreamer開發的插件,這個插件可以發揮nvidia gpu的硬件解碼功能。當時這個服務使用go和c混編的方式,問題的癥狀是服務運行一段時間後,不輸出音視頻數據。遺憾的是,由於疫情,項目停止,因此沒有機會繼續研究這個問題。
時間來到去年底。當前這個項目進行壓力測試,發現關鍵的語音處理服務運行一段時間後,會出現不拉流的情況,因此也沒有後續的結果輸出。癥狀和上一個項目非常像。雖然使用的第三方SDK不一樣,但同樣用了go和c混編的方式。一開始,焦點就放在go的運行時上,覺得可能是go和c相互調用的方式不對。經過合理猜測,並用測試進行驗證後,發現問題還是在第三方拉流的SDK上,它們的回調函數必須要快,否則有可能會阻塞它們的回調線程。當然,在go調用c的時候,如果耗時比較長,會對go的運行時造成一些副作用;在c回調go的時候,go的運行時也有可能阻塞c的回調線程。但go的運行時已經比較成熟,因此我覺得它對這個問題的貢獻不大。以上採用了假設-驗證的方法,主要的原因還是第三方的拉流SDK不開源。在定位問題的過程中,使用了gdb的gcore來生成堆棧;也搭建了灰度環境來進行壓力測試,以及完善監控,這些都是解決方法的一部分。
正是這一問題,促使我更多的了解go的運行時。而我看得越多,越覺得go的運行時是一個龐大的怪物。因此,抱着能了解一點是一點的心態,不斷的完善這篇筆記。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/252861.html