張海華,楊秀波,張 非,鐘 磊
(1.深圳大學信息中心,深圳 518060;2.衡水學院現(xiàn)代教育技術管理中心,衡水 053000;3.深圳大學機電與控制工程學院,深圳 518060)
教師專業(yè)化發(fā)展主要是指教師在教育教學水平和教學技能兩方面的發(fā)展,包括教師在課堂教學的過程中,對學生的知識與能力、過程與方法、情感態(tài)度和價值觀三維目標的培養(yǎng)。繼續(xù)教育是提高教師專業(yè)業(yè)務水平,促進教師專業(yè)發(fā)展的重要途徑。[5]
某市教師繼續(xù)教育在線教學平臺涉及到人員管理、課程管理、選課管理、費用管理、教務管理、在線學習、成績管理等諸多功能。該平臺承載全市中小學及幼兒園12萬名教師的繼續(xù)教育培訓工作,所有的培訓業(yè)務流程均在網(wǎng)上進行,尤其是在開放選課的初始時間點階段,4~5萬名教師同時登錄系統(tǒng)并進行查詢和選課操作,因此對平臺的性能和可靠性提出了很高的要求。另外,由于教師繼續(xù)教育培訓業(yè)務模式經(jīng)常需要根據(jù)政策變化而變化,對平臺的易擴展性和易定制化也提出了較高的要求。
事件驅動架構(EDA)定義了設計和實現(xiàn)一個應用系統(tǒng)的方法學,在這個系統(tǒng)中,事件可傳輸于松散耦合的組件和服務之間。在線教學平臺模塊眾多,一個業(yè)務操作可能需要多個模塊協(xié)作完成,為降低模塊之間的業(yè)務耦合性,模塊之間的非強實時業(yè)務交互(即允許業(yè)務聯(lián)動有一定的時間差)采用事件驅動架構進行設計,一個模塊操作完成后,系統(tǒng)即發(fā)布本模塊操作完成的事件,其他業(yè)務關聯(lián)模塊通過監(jiān)聽事件,進行異步事件處理,達到業(yè)務的非實時交互。
基于事件驅動架構進行設計的核心是要有一個穩(wěn)定可靠的事件中心以及方便實用的API集合給應用程序使用。本文設計并實現(xiàn)了一個基于Kafka的分布式教師繼續(xù)教育在線教學平臺事件中心,提供一組API供應用程序使用。
Apache Kafka是由LinkedIn公司開發(fā)一種分布式的發(fā)布-訂閱消息系統(tǒng),是一種快速的、可擴展的、分布式的、分區(qū)的和可復制的提交日志服務機制。Kafka與傳統(tǒng)消息系統(tǒng)相比,有以下不同:它被設計為一個分布式系統(tǒng),易于向外擴展;它同時為發(fā)布和訂閱提供高吞吐量;它支持多訂閱者,當失敗時能自動平衡消費者;它將消息持久化到磁盤,因此可用于批量消費,例如ETL,以及實時應用程序。
Kafka的架構包括以下幾個核心組件:一是話題(Topic):話題是特定類型的消息流。消息是字節(jié)的有效負載(Payload),話題是消息的分類名或種子(Feed)名。二是生產(chǎn)者(Producer):生產(chǎn)者(Producer)是能夠發(fā)布消息到話題的任何對象。三是消費者(Consumer):消費者可以訂閱一個或多個話題,并從消息代理(Broker)處拉取數(shù)據(jù),從而消費這些已發(fā)布的消息,消費者也可以根據(jù)需要進行分組,同一組內的多個消費者針對同一個話題的消息僅消費一次。四是代理(Broker):已發(fā)布的消息保存在一組服務器中,這組服務器被稱為代理(Broker)或Kafka集群。
Kafka生產(chǎn)者、消費者和集群的關系如圖1所示。生產(chǎn)者發(fā)布消息到Kafka集群,消費者從Kafka集群獲取消息并處理。
圖1 Kafka生產(chǎn)者、消費者和代理環(huán)境
本文涉及的事件中心核心包括三部分:事件、事件監(jiān)聽器、事件總線。事件中心API也定義了事件、事件監(jiān)聽器、事件總線三個核心的類,如圖2所示。
圖2 事件中心API接口
事件定義了需要發(fā)布的內容,除特定的業(yè)務內容數(shù)據(jù)外,還包括事件發(fā)生的時間、事件的編號(全局唯一,確保可追溯)、時間的序列編號(主要在事件級聯(lián)觸發(fā)的時候使用,用于標識多個事件的事件鏈,便于追蹤業(yè)務流向)。
事件監(jiān)聽器用于處理事件,特定的事件監(jiān)聽器僅處理特定的事件,事件監(jiān)聽器接口如下:
除了事件和事件監(jiān)聽器,事件中心最重要的組成部分就是事件總線。事件總線用于發(fā)布事件和管理事件監(jiān)聽器,接口定義如下:
事件和事件監(jiān)聽器通過事件總線連接。當業(yè)務需要觸發(fā)事件時,首先構造事件,然后調用事件總線的publishEvent方法將事件發(fā)布出去。事件監(jiān)聽器通過事件總線的addEventListener方法將自身注冊到事件總線,由事件總線進行調度處理。
在定義了事件中心的原型之后,根據(jù)面向接口編程思想,我們進行了業(yè)務系統(tǒng)編碼開發(fā)。本節(jié)介紹如何基于Kafka實現(xiàn)上節(jié)的事件中心。
根據(jù)Kafka的架構模型,我們首先將事件中心的模型和Kafka模型進行映射,其中事件的名稱映射為Kafka的Topic,事件的內容序列化后映射成Kafka消息,事件的發(fā)送方映射為Kafka的生產(chǎn)者,事件監(jiān)聽器映射為Kafka的消費者。
模型映射后,基于Kafka的事件中心的工作核心就是實現(xiàn)事件總線,我們分別針對事件總線的發(fā)布事件方法—publishEvent和注冊事件監(jiān)聽器方法—addEventListener進行闡述。
2.2.1 發(fā)布事件方法的實現(xiàn)
根據(jù)模型映射,發(fā)布事件的核心就是使用Kafka生產(chǎn)者生產(chǎn)消息,然后將消息發(fā)布到特定的Topic上,實現(xiàn)代碼如下:
首先根據(jù)kafka服務器的配置構造生產(chǎn)者,然后調用生產(chǎn)者的發(fā)送方法將消息發(fā)送到特定的Topic上,然后關閉Kafka服務器連接。
2.2.2 注冊事件監(jiān)聽器方法的實現(xiàn)
根據(jù)模型映射,注冊事件監(jiān)聽器的核心就是構造Kafka的消息消費者,使用事件監(jiān)聽器消費消息,實現(xiàn)代碼如下。
類似于發(fā)布消息,注冊監(jiān)聽器首先要根據(jù)服務器的配置以及監(jiān)聽器實現(xiàn)構造Kafka消費者,然后不斷地從Kafka集群獲取消息,獲取到的消息通過反序列化后交給事件監(jiān)聽器進行處理。
基于Kafka的在線教學平臺事件中心目前已經(jīng)在某市教師教育網(wǎng)中大范圍應用,下面以其中一個業(yè)務為例說明應用效果。
本例使用的業(yè)務場景為教師選課子流程。根據(jù)業(yè)務要求,從選課到學習需要經(jīng)歷選課、初審、繳費、終審四個階段,初審由學校管理員操作并統(tǒng)一學校繳費,本例僅考慮選課及其關聯(lián)業(yè)務。教師選課后需要記錄選課操作日志,如果是教師本人選課,則其選課狀態(tài)為未初審,如果是學校管理員或者系統(tǒng)管理員代為教師選課,則選課狀態(tài)需要設置為已初審(跳過單位管理員審核),然后計算課程總費用,如果課程費用為0(重修該課程的),則選課狀態(tài)需要更新為已繳費(即無需繳費)。后來平臺又開發(fā)教師個人繳費功能,個人繳費的課程無需學校業(yè)務管理員初審。在引入事件驅動架構和事件中心之前,業(yè)務代碼邏輯如下圖3所示,盡管不同的模塊分別處理其內在業(yè)務,但仍然需要一個方法將不同模塊的業(yè)務進行串聯(lián),業(yè)務發(fā)生變化就需要修改這個方法,導致方法的實現(xiàn)越來越復雜,邏輯判斷越來越多,單元測試和集成測試難度也很大,提高了系統(tǒng)的不穩(wěn)定性,增加了數(shù)據(jù)出錯概率。
圖3 改造之前的選課業(yè)務流程
使用事件驅動架構引入事件中心后,我們對選課業(yè)務進行了代碼重構,具體邏輯如下:一是選課模塊在選課成功后不再關心日志記錄、計費、自動初審等業(yè)務,僅需要發(fā)布選課成功事件;二是日志模塊監(jiān)聽選課成功事件,記錄選課日志;三是計費模塊監(jiān)聽選課成功事件后處理費用計算邏輯,計費成功后發(fā)布計費成功事件;四是審核模塊監(jiān)聽計費成功事件,根據(jù)業(yè)務決定是否自動終審通過;五是審核模塊監(jiān)聽選課成功事件,根據(jù)需要決定是否需要自動初審通過;六是課程模塊監(jiān)聽選課成功事件,然后根據(jù)課程的繳費方式?jīng)Q定是否需要自動初審。其業(yè)務代碼邏輯如圖4所示:
圖4 基于事件驅動架構的選課業(yè)務流程
經(jīng)過改造后,系統(tǒng)各模塊的業(yè)務相對獨立,每個模塊專注于處理其內在業(yè)務,當業(yè)務發(fā)生變化后僅需要更改事件監(jiān)聽處理邏輯,而無須與其它模塊產(chǎn)生直接的耦合關聯(lián),每個模塊獨立進行模擬單元測試,提升了代碼的穩(wěn)定性,降低了系統(tǒng)的復雜度,提升了系統(tǒng)的整體可靠性和數(shù)據(jù)的準確性。
本文設計并實現(xiàn)了一種基于Kafka的分布式教師繼續(xù)教育在線教學平臺事件中心,其核心是使用Kafka的集群服務能力和生產(chǎn)及消費消息模型設計并實現(xiàn)了一套可以在分布式多模塊環(huán)境下使用的一整套API,并通過這一套API有效的解決了系統(tǒng)模塊間高耦合度問題,當業(yè)務發(fā)生變化后,代碼更新可以快速的發(fā)生變動,即便有新的業(yè)務接入時也不會影響現(xiàn)有業(yè)務功能。我們的后續(xù)工作將針對事件中心進行功能增強,提供可視化的界面進行事件管理,支持事件鏈的展示和事件回放處理等功能。