源码地址:https://github.com/cloudwu/skynet
框架結構#
skynet-src
:Skynet 的核心源碼,包括主體框架、服務管理、網路通信、計時器等模組。3rd
:Skynet 依賴的第三方庫,包括 LuaJIT、luasocket 等。config
:Skynet 的配置文件目錄。example
:Skynet 的示例代碼目錄,包括 echo 服務、pingpong 示例、socket 模組示例等。luaclib
:Skynet 的 C 擴展庫,例如 cjson、protobuf 等。lualib
:Skynet 的 Lua 擴展庫,例如 skynet、socket 等。service
:Skynet 的服務代碼目錄,包括各個服務的 Lua 源碼、初始化腳本等。test
:Skynet 的測試代碼目錄。
核心模組#
skynet_main.c
:Skynet 主函數,包括參數解析、初始化、啟動服務等。skynet.h
:Skynet 的核心頭文件,包括數據結構定義、函數聲明等。service-src
:Skynet 服務管理模組,包括服務註冊、服務查找、消息處理等。lualib-src
:Skynet Lua 擴展模組,包括 Lua 和 C 之間的交互函數等。timer.c
:Skynet 計時器模組,包括定時器的設置、刪除等。socket_server.c
:Skynet 網路通信模組,包括 TCP/UDP 網路連接、消息處理等。logger.c
:Skynet 日誌模組,包括日誌的記錄、輸出等。malloc_hook.c
:Skynet 內存管理鉤子,用於統計內存使用情況。
服務管理#
- 註冊服務:將服務註冊到框架中,使得其他服務可以調用。
- 查找服務:根據服務名查找對應的服務句柄。
- 消息處理:處理來自其他服務的消息。
Lua 擴展模組#
skynet.lua
:Skynet 的核心接口,包括服務註冊、消息發送、計時器等。socket.lua
:網路通信模組,包括 TCP、UDP、HTTP 等協議的支持。cjson.lua
:JSON 解析庫。protobuf.lua
:Google 的 Protobuf 庫的 Lua 實現。
網路通信#
1. 網路模型
skynet_socket
:Socket 的結構體,包括 Socket 的 ID、類型、地址等信息。struct skynet_context
:Actor 的上下文結構體,包括 Actor 的名字、消息隊列等信息。skynet_socket_poll
:Socket 的輪詢函數,用於處理網路事件。skynet_socket_send
:向指定的 Socket 發送數據。skynet_socket_connect
:向指定的地址和端口號連接 Socket。skynet_socket_bind
:綁定 Socket 到指定的地址和端口號。skynet_socket_listen
:開始監聽 Socket。skynet_socket_close
:關閉指定的 Socket。
2. 網路通信
skynet_send
:向指定的 Actor 發送一條消息,該函數會查找目標 Actor 並向其消息隊列中添加一條消息。skynet_socket_start
:啟動網路服務,並監聽指定的端口號。skynet_socket_poller
:網路輪詢函數,用於處理網路事件。skynet_socket_udp
:創建一個 UDP Socket,並綁定到指定的地址和端口號。skynet_socket_udp_connect
:將 UDP Socket 連接到指定的地址和端口號。skynet_socket_udp_send
:向指定的 UDP Socket 發送數據。skynet_socket_udp_address
:獲取 UDP Socket 的地址信息。skynet_socket_udp_close
:關閉指定的 UDP Socket。
Actor 模型相關#
1. 消息隊列
-
struct message
:消息的結構體,包括消息源、目標、類型、數據等信息。消息隊列中存儲的是
message
結構體,該結構體包括消息源、目標、類型、數據等信息,方便消息的傳遞和處理。 -
struct message_queue
:消息隊列的結構體,包括消息隊列頭、尾指針、消息數量等信息。message_queue
結構體是消息隊列的管理結構體,包括消息隊列頭、尾指針、消息數量等信息,用於管理消息隊列中的消息,方便消息的添加、彈出等操作。 -
skynet_mq_push
:向消息隊列中添加一條消息。skynet_mq_push
函數用於向消息隊列中添加一條消息,將消息添加到消息隊列的尾部,方便消息的處理。 -
skynet_mq_pop
:從消息隊列中彈出一條消息。skynet_mq_pop
函數用於從消息隊列中彈出一條消息,將消息從消息隊列的頭部彈出,方便消息的處理。 -
skynet_mq_length
:獲取消息隊列中的消息數量。skynet_mq_length
函數用於獲取消息隊列中的消息數量,方便統計消息的數量。 -
skynet_mq_alloc
:從內存池中分配一個消息隊列。skynet_mq_alloc
函數用於從內存池中分配一個新的消息隊列,用於消息的存儲和管理。 -
skynet_mq_mark_release
:標記消息隊列為釋放狀態,當消息隊列中的所有消息被處理完畢後,就可以將其釋放回內存池。skynet_mq_mark_release
函數用於標記消息隊列為釋放狀態,當消息隊列中的所有消息被處理完畢後,就可以將其釋放回內存池,方便內存的管理。 -
skynet_mq_release
:釋放標記為釋放狀態的消息隊列。skynet_mq_release
函數用於釋放標記為釋放狀態的消息隊列,方便內存的管理。
2. Actor 模型通信機制
-
struct skynet_context
:Actor 的上下文結構體,包括 Actor 的名字、消息隊列等信息。skynet_context
結構體是 Actor 的上下文結構體,包括 Actor 的名字、消息隊列等信息,用於管理 Actor 的狀態和各種信息。 -
skynet_context_new
:創建一個新的 Actor,並初始化其上下文結構體。skynet_context_new
函數用於創建一個新的 Actor,並初始化其上下文結構體,方便 Actor 的管理和使用。 -
skynet_context_release
:釋放 Actor 的上下文結構體。skynet_context_release
函數用於釋放 Actor 的上下文結構體,方便內存的管理。 -
skynet_context_push
:向 Actor 的消息隊列中添加一條消息。skynet_context_push
函數用於向 Actor 的消息隊列中添加一條消息,方便消息的傳遞和處理。 -
skynet_context_pop
:從 Actor 的消息隊列中彈出一條消息。skynet_context_pop
函數用於從 Actor 的消息隊列中彈出一條消息,方便消息的處理。 -
skynet_context_handle_message
:處理 Actor 的消息隊列中的所有消息。skynet_context_handle_message
函數用於處理 Actor 的消息隊列中的所有消息,方便消息的統一處理。 -
skynet_send
:向指定的 Actor 發送一條消息,該函數會查找目標 Actor 並向其消息隊列中添加一條消息。skynet_send
函數用於向指定的 Actor 發送一條消息,該函數會查找目標 Actor 並向其消息隊列中添加一條消息,方便消息的傳遞和處理。
3. 消息的傳遞過程
- 發送方使用
skynet_send
向指定的 Actor 發送一條消息。 - Skynet 根據消息的目標 Actor 查找其上下文結構體,並向其消息隊列中添加一條消息。
- 接收方使用
skynet_context_pop
從自己的消息隊列中彈出一條消息,並進行處理。
日誌模組#
- 記錄各個服務的運行狀態、錯誤信息等。
內存管理#
Skynet 的內存管理模組採用了透明的內存池實現,可以有效地減少內存分配和釋放的頻率,提高內存使用效率。具體分析如下:
- 內存池的結構
struct mem_data
:內存池中的一塊的結構體,包括前後鏈接、大小等信息。struct mem_env
:內存池的管理結構體,包括內存池的起始地址、結束地址、塊的大小等信息。
- 內存池的創建
mem_init
:初始化內存池的管理結構體,設置內存池的起始地址、結束地址、塊的大小等信息。mem_alloc
:從內存池中分配一定大小的內存,返回內存池中一個空閒塊的指針。mem_free
:將一塊內存釋放回內存池,將其標記為空閒塊。
- 內存池的擴展
mem_newpool
:在內存池管理結構體後面申請一塊新的內存池,並將其加入內存池鏈表,以支持內存池的擴展。
- 內存池的使用
skynet_malloc
:使用內存池分配一塊指定大小的內存。skynet_calloc
:使用內存池分配一塊指定大小的內存,並將其清零。skynet_free
:將一塊指定的內存釋放回內存池。
- 內存池的統計
mem_data_dump
:輸出內存池中各個塊的使用情況。mem_report
:輸出內存池的總體情況,包括使用率、總大小、空閒塊數等。
- 內存池的原理
內存池的實現原理是將一塊連續的內存分成若干大小相等的塊,用前後鏈接將這些塊串聯起來,空閒塊用一個鏈表連接,已分配的塊則不在鏈接中。內存池的管理結構體包括內存池的起始地址、結束地址、塊的大小等信息。在內存池中分配和釋放內存時,只需要簡單地修改鏈表的指針即可,不需要進行內存的分配和釋放操作,以達到快速的內存分配和釋放效果。同時,內存池的使用還可以降低內存碎片的產生,提高內存使用效率。
高併發、高吞吐、高性能分析#
skynet_socket_poller
使用了 I/O 多路復用模型,同時支持 epoll、kqueue、select 三種模式,可以有效地提高網路通信的併發處理能力。- Skynet 使用了非阻塞 I/O 模型,使用了底層操作系統提供的異步 I/O 函數,避免了 I/O 操作阻塞線程的情況,提高了系統的吞吐量和性能。
- Skynet 使用了消息隊列作為 Actor 之間通信的數據結構,避免了線程之間的競爭和鎖的使用,進一步提高了系統的併發性和性能。