在現(xiàn)場施工快一個月,歷經(jīng)前期艱難調(diào)試摸索,目前系統(tǒng)已能正常運行,但是有的模塊作的很低效,我試圖將其改造一下。
現(xiàn)狀:
就拿最基本的一個功能點來說,在地圖頁面上實時顯示地理數(shù)據(jù)(例如:卡點顯示實時過車、實時顯示車輛GPS位置等),以前我的處理方式是采用頁面定時器,間隔一段時間去查詢后臺數(shù)據(jù)庫,過車數(shù)據(jù)則通過前置設(shè)備采集通過Hessian遠(yuǎn)程調(diào)用將過車數(shù)據(jù)插入后臺數(shù)據(jù)庫,其實現(xiàn)方法簡單。但是最大的弊病在于低效和易錯,由于前置采集設(shè)備采集和執(zhí)行Hessian,如果網(wǎng)絡(luò)狀態(tài)不佳,過車數(shù)據(jù)將會丟失,同時存入數(shù)據(jù)庫的時間不可能嚴(yán)格真實,但是我的頁面上定時器是嚴(yán)格按照時間去查詢,容易出現(xiàn)漏查現(xiàn)象,而且頻繁的對數(shù)據(jù)庫進(jìn)行操作,增加了數(shù)據(jù)庫的負(fù)擔(dān)。
改造:
1.引入消息中間件,前置設(shè)備作為消息生產(chǎn)者,將采集到的數(shù)據(jù)裝入消息中間件中
2.前端頁面通過WebSocket和后臺進(jìn)行連接,當(dāng)消息中間件中有消息時立即消費,通過WebSocket傳給前端頁面
改造后結(jié)構(gòu)是這樣
實現(xiàn)效果:
如何實現(xiàn):
1.安裝Kafka,Kafka在Windows安裝運行,(建議有條件還是上Linux系統(tǒng))
2.后端通過新建監(jiān)聽線程池和處理線程池來實現(xiàn)對消息中間件的監(jiān)聽和消息的消費,并且利用netty-socketio進(jìn)行訂閱和廣播
@PostConstruct
public void startConsuming() {
Configuration config = new Configuration();
config.setHostname("localhost");
config.setPort(9093);
final SocketIOServer server = new SocketIOServer(config);
server.addEventListener("chatevent", GPSMessage.class, new DataListener<GPSMessage>() {
@Override
public void onData(SocketIOClient client, GPSMessage data, AckRequest ackRequest) {
// broadcast messages to all clients
server.getBroadcastOperations().sendEvent("chatevent", data);
}
});
server.start();
listenerExecService = Executors.newFixedThreadPool(LISTENER_NUM_THREADS);
handlerExecService = Executors.newFixedThreadPool(EXECUTOR_NUM_THREADS);
consumerConfig = consumerConfigFactory.getConsumerConfig();
topicCountMap = new HashMap<String, Integer>();
topicCountMap.put(topic, CONSUMER_NUM_THREADS);
gson = new Gson();
handlerTaskFactory = (String gpsText) -> new GPSTask(gpsText, gson, server);
super.start();
}
public void start() {
ConsumerConnector consumer = Consumer.createJavaConsumerConnector(this.getConsumerConfig());
Map<String, List<KafkaStream<byte[], byte[]>>> consumerMap = consumer.createMessageStreams(this.getTopicCountMap());
Iterator var3 = consumerMap.entrySet().iterator();
while(var3.hasNext()) {
Entry<String, List<KafkaStream<byte[], byte[]>>> entry = (Entry)var3.next();
List<KafkaStream<byte[], byte[]>> streams = (List)entry.getValue();
int threadNumber = 0;
for(Iterator var7 = streams.iterator(); var7.hasNext(); ++threadNumber) {
KafkaStream<byte[], byte[]> stream = (KafkaStream)var7.next();
this.getListenerExecService().submit(new ConsumerListenTask(stream, threadNumber, this.getHandlerTaskFactory((String)entry.getKey()), this.getHandlerExecService()));
}
}
}
public class ConsumerListenTask implements Runnable {
public void run() {
ConsumerIterator it = this.kafkaStream.iterator();
while(it.hasNext()) {
byte[] messageData = (byte[])it.next().message();
String reply = new String(messageData);
this.executorPool.submit((Runnable)this.executorTaskFactory.apply(reply));
System.out.println("Consumed Thread:" + this.threadNumber + ".Consuming User: " + reply);
}
System.out.println("Shutting down Thread: " + this.kafkaStream);
}
}
public class GPSTask implements Runnable {
@Override
public void run() {
try{
GPSMessage gpsMessage = gson.fromJson(this.gpsText, GPSMessage.class);
System.out.println("+++++++++++從kafka中取到車牌號"+gpsMessage.getHphm());
socketIOServer.getBroadcastOperations().sendEvent("chatevent", gpsMessage);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.前端頁面利用socket.io監(jiān)聽事件就行
socket.on('chatevent', function(data) {
console.log(data);
switch(data.operate){
case 'create':
var coordinate = ol.proj.transform([Number(data.lon), Number(data.lat)], 'EPSG:4326', 'EPSG:3857');
var point = new ol.geom.Point(coordinate);
var markerFeature = new ol.Feature({
name: data.hphm,
type: 'position',
geometry: point
});
vectorSource.addFeature(markerFeature);
break;
}
});
4.通過kafka自帶的messageproducer,注冊topic并模擬過車數(shù)據(jù),將消息發(fā)往消息中間件,后臺通過監(jiān)聽線程池來及時消費該消息,最后通過netty-socketio廣播到前端頁面
.\bin\windows\kafka-console-producer.bat --broker-list localhost:9092 --topic gpsinfo
目前只做了個Demo,接下來可能會遇到的問題,消息生產(chǎn)和消費不同步,路上過車數(shù)據(jù)將會是短時內(nèi)大量過車,會生產(chǎn)大量的過車消息;而頁面顯示不可能和消息同步,否則一閃而過影響顯示效果,但處理不及時將會造成大量消息積壓,有待進(jìn)一步思考嘗試。