基于開源技術(shù)的移動社交網(wǎng)絡(luò)開發(fā)實(shí)例課件_第1頁
基于開源技術(shù)的移動社交網(wǎng)絡(luò)開發(fā)實(shí)例課件_第2頁
基于開源技術(shù)的移動社交網(wǎng)絡(luò)開發(fā)實(shí)例課件_第3頁
基于開源技術(shù)的移動社交網(wǎng)絡(luò)開發(fā)實(shí)例課件_第4頁
基于開源技術(shù)的移動社交網(wǎng)絡(luò)開發(fā)實(shí)例課件_第5頁
已閱讀5頁,還剩41頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡介

基于開源技術(shù)的

移動社交網(wǎng)絡(luò)開發(fā)實(shí)例自我介紹與插播小廣告eBay中國區(qū)研發(fā)中心(MTS1工程師)螞蟻金服金融核心事業(yè)部(支付寶)技術(shù)專家點(diǎn)滴號:wangsheng微信號:

博客:

歡迎注冊點(diǎn)滴號,共同討論其中的技術(shù)實(shí)現(xiàn)目的:提供相關(guān)開源實(shí)踐,認(rèn)識更多朋友,技術(shù)無止境,歡迎大家多多提供更好的solution以及指正錯誤的地方。點(diǎn)滴現(xiàn)狀…內(nèi)容:以核心框架實(shí)踐為主,至于基本框架的使用:如Spring,MyBatis,Hibernate,Shiro,JPA,JTA,JMS等只做簡單介紹或者不介紹。第一部分:應(yīng)用介紹:具有基本社交應(yīng)用的功能一對一分享和私聊–和好友一對一分享和私聊2.建圈子–為親人、密友、同學(xué)、團(tuán)隊(duì)建私密圈子,為興趣、奇思妙想、社交組織建公開圈子,吸引志趣相投的人。

3.找圈子–找志趣相投的圈子,從陌生人到朋友

4.分享無拘束-每個圈子都是私密空間,分享更自由

5.聊天無干擾–以圈子為單位聊天,圈子間互不干擾

6.二維碼加好友、加圈子–掃描二維碼加好友、加圈子特點(diǎn)介紹:2.聊天和分享保存在云端,換手機(jī)時自動同步

3.可以撤回長達(dá)7天內(nèi)的聊天消息

4.分享時可以同時指定多個圈子或朋友

5.所有聊天、分享均經(jīng)過加密

6.可為每張圖片添加文字說明和鏈接,每張圖片可以是一個故事。第二部分:技術(shù)概況RESTJ2EE平臺:JPA/JTA/JMS等MQTT協(xié)議Solr全文搜索Shiro安全認(rèn)證SpringMybatisHibernateRedis緩存FastDFS文件存儲MAVENV1.0主要技術(shù)–高內(nèi)聚,低耦合Jetty、Tomcat、GITRESTAndroidIOSNodeJSJqueryHtml5QueueBaseonErlang{GO}AppWeb系統(tǒng)架構(gòu)V1.0:快速原型,小眾用戶

后期增加operation-manager

系統(tǒng)架構(gòu)V2.0:ScaleOut與大眾用戶群

邏輯架構(gòu)部署圖:simpleisbeautiful第三部分:詳細(xì)實(shí)現(xiàn)《一》基于Solr的圈子活動搜索–廣度與精度的權(quán)衡1.基于優(yōu)先級的增量索引設(shè)計(jì)。2.mmseg4j中文分詞與詞庫擴(kuò)展?!緣簻y結(jié)果更甚勝庖丁分詞】3.建立活動/圈子/空間信息各自私有的core。4.配置相關(guān)屬性以進(jìn)行索引和檢索。5.SolrAdmin進(jìn)行索引分析。6.Java的Client包SolrJ。1、為什么不用更簡化,以往性能表現(xiàn)更好的ElasticSearch2、為什么用基于正向最大匹配算法的開源實(shí)現(xiàn)mmseg4j,而不用精確度更高的基于逆向匹配算法的開源實(shí)現(xiàn)------廣度與精度之間的權(quán)衡3、mmseg4j,代碼維護(hù)在github上,可以方便的管理問題與源碼貢獻(xiàn)。獨(dú)一無二的基于優(yōu)先級的增量索引:冪等同步擴(kuò)展性:按Priority索引(現(xiàn)有均為P1)字段名數(shù)據(jù)類型長度鍵注釋bidINT11PK聯(lián)合主鍵BusinessIDtidINT11PK聯(lián)合主鍵表IDo_statusenum11

pending,success,failedo_timesINT2

索引次數(shù)priorityINT11

索引優(yōu)先級last_update_timeDATETIME11FK最后一次索引更新時間commentsvarchar60

索引情況說明Solr增量索引信息表:index_netsSyncManager定時將新增的數(shù)據(jù)添加到index_nets中。IndexManager用于管理基于優(yōu)先級的Timer對index_nets中的新增數(shù)據(jù)進(jìn)行索引。MysqlCircle/Actitiy/message…MysqlIndex_netsSyncManagerSolrIndex庫IndexManagerP1TimerP2TimerP3TimerIndexManagerIndexManager搜索中的怪事情,首先從SolrAdmin中找答案搜索中的怪事情–從SolrAdmin中找答案-具體事例1、助詞惹的禍,輸入關(guān)鍵字“大師的圈子”進(jìn)行查詢,搜索出:“六指琴魔的上海鋼琴師”。解決方案:配置停止詞:stopwords.txt,包括語氣組詞等無意義的詞<fieldTypename="text_mmseg4j_maxword"class="solr.TextField"positionIncrementGap="100"><analyzer><tokenizerclass="com.chenlb.mmseg4j.solr.MMSegTokenizerFactory"mode="max-word"dicPath="/root/solr/solr-data/solr/circle/conf"/><filterclass="solr.StopFilterFactory"ignoreCase="true"words="stopwords.txt"/></analyzer></fieldType>3、maxword算法替換complex算法:“臉譜為員工開放了很多福利,比如員工可以參加各種體育活動,為家人提供專屬的空間等?!比绻褂胏omplex算法,只有輸入“體育活動”才能搜出結(jié)果,但用戶希望輸入“活動”即有搜索結(jié)果。 3.1、complex算法:“體育活動”是整體 3.2、maxword算法:“體育”和“活動”分開了4、maxword只最多支持2個字惹的禍:對于內(nèi)容“林書豪來中國,來北京了”:如果我們只使用關(guān)鍵字“林書豪”便可得出上面的結(jié)果,這似乎是我們要的結(jié)果,但如果索引庫中存在一段內(nèi)容是“來自華山的林平之練就了葵花寶典”,你會發(fā)現(xiàn)我輸入“林書豪”后,上面的內(nèi)容也會被搜索出來。于是使用SolrAdmin可知,這是因?yàn)樵~庫中缺少“林書豪”,林書豪被活生生的拆分成了“林”,“書”,“豪”。將“林書豪”加入詞庫后,由于小經(jīng)驗(yàn):于是在詞庫words.dic添加“林書豪”,但是添加后還存在同樣的問題,這是因?yàn)閙axword算法最多只支持2個字,于是在詞庫中同時加上“書豪”和“林書”就可以提高準(zhǔn)確度了。SolrCloud中提供NRT近實(shí)時搜索:Redis緩存機(jī)制緩解近實(shí)時首先來看下索引和Solr實(shí)體對照圖:Shard更像組的概念,每個Shard存儲的Doc各不相同,但同一Shard下的Doc相同,互為副本。SolrCloud批量添加索引,批量索引路由,需要高并發(fā)能力SolrCloud中創(chuàng)建索引可以分為5個步驟(如下圖所示)

SolrCloud索引的檢索

——基于索引的Shard的個數(shù),把查詢轉(zhuǎn)為多個子查詢

SolrShardSplitting/ReSharding:將原有Shard的Replica均勻的分布到更多的Shard的更多的Solr節(jié)點(diǎn)上去SolrCloud與Zookeeper–配置比較簡單SolrCloud索引操作的基本架構(gòu)圖基于FastDFS的文件上傳與下載文件上傳:1.Client詢問Trackerserver上傳到哪個Storageserver2.Trackerserver返回一臺可用的Storageserver(IP地址和端口)3.Client直接和該Storageserver建立連接,進(jìn)行文件上傳,Storageserver返回新生成的文件ID(包括組/卷名和文件名),文件上傳結(jié)束。文件下載:1.Client詢問Trackerserver可以從哪臺Storageserver上下載指定的文件,參數(shù)為文件ID(包括組名和文件名)2.Trackerserver返回一臺可用的Storageserver(IP地址和端口)3.Client直接和該Storageserver建立連接,完成文件下載。簡單的配置和API線下配置事例:connect_timeout=2network_timeout=30charset=UTF-8http.tracker_http_port=8080http.anti_steal_token=nohttp.secret_key=FastDFS1234567890tracker_server=56:22122storage_server=55:23000String=PROTOCOL+trackerServer.getInetSocketAddress().getHostName()+…uploadResults=storageClient.upload_(),(),meta_list);

privatestaticTrackerClienttrackerClient;

privatestaticTrackerServertrackerServer;

privatestaticStorageServerstorageServer;

privatestaticStorageClientstorageClient;實(shí)踐之:基于FastDFS、MQTT,Mysql/Redis的文件、圖片管理系統(tǒng)的開源實(shí)現(xiàn)《三》MQTT協(xié)議–轉(zhuǎn)發(fā)消息:Mosquito,ErLang

輕量級移動應(yīng)用系統(tǒng)的首先MQTT(MessageQueuingTelemetryTransport,消息隊(duì)列遙測傳輸)是一套輕量級跨平臺的基于發(fā)布/訂閱消息傳輸協(xié)議,其設(shè)計(jì)思想開放、簡單、輕量、易于實(shí)現(xiàn)。專門為低帶寬、不穩(wěn)定網(wǎng)絡(luò)以及計(jì)算和處理能力受限的設(shè)備所設(shè)計(jì),該協(xié)議采用小型傳輸,耗電量小,能大大降低網(wǎng)絡(luò)流量,最小化數(shù)據(jù)包并有效分配與傳輸,非常適合移動系統(tǒng)上面的應(yīng)用。MQTT協(xié)議提供了3種類別的信息傳遞服務(wù)質(zhì)量,值分別是0、1、2。其中Atmostonce(值是0)至多一次,消息發(fā)布完全依賴于底層的TCP/IP網(wǎng)絡(luò),會發(fā)生消息丟失;Atleastonce(值是1)至少一次,確保消息到達(dá),但可能發(fā)生消息重復(fù);Exactlyonce(值是2)只有一次,確保消息只到達(dá)一次。經(jīng)過壓測發(fā)現(xiàn),使用IBM自身提供的Javalibrary以及mosquitobroker性能并沒有官網(wǎng)上聲稱的出色,而使用Go/Erlanng編寫的broker性能更加出色,但I(xiàn)BM自身提供的API具有可讀性強(qiáng)和可維護(hù)行好的優(yōu)點(diǎn),但由Erlang編寫的broker屬于我們的產(chǎn)品的一大技術(shù)點(diǎn),準(zhǔn)備以后發(fā)布開源實(shí)現(xiàn),此處暫不作更深的討論。MQTT協(xié)議–多次握手/簽約確保信息發(fā)送成功:exactlyonce

dameonservice,callback,retry,握手模塊分布式、跨JVM責(zé)任鏈模式處理用戶restcall請求:restcall通知Advisor1.基于責(zé)任鏈模式,使每個相關(guān)的URL請求都有機(jī)會被相應(yīng)的handler處理,從而大大提高了可擴(kuò)展性。2.ActionMeditor基于調(diào)停者模式,使得調(diào)用者只與meditor交互,不直接與各個Handler交互,降低業(yè)務(wù)邏輯模塊之間的耦合度。

事實(shí):對于每一種用戶請求的URL,應(yīng)該有相應(yīng)的handler進(jìn)行處理。

問題:當(dāng)前請求應(yīng)該由哪個handler處理?擴(kuò)展性?《四》對組件間restcallSayNo–Linkedin分布式的消息隊(duì)列KafkaMQTT/ActiveMQKafkabusZookeeper,可以將其想象成它維持了一張表,記錄了各個節(jié)點(diǎn)的IP、端口等配置信息。每個Consumer啟動后會在Zookeeper上注冊一個臨時的consumerregistry:包含Consumer所屬的ConsumerGroup以及訂閱的topics。每個ConsumerGroup關(guān)聯(lián)一個臨時的ownerregistry和一個持久的offsetregistry。對于被訂閱的每個partition包含一個ownerregistry,內(nèi)容為訂閱這個partition的consumerid,同時包含一個offsetregistry,內(nèi)容為該consumerid上一次訂閱的offset。Zookeeper、Producer、Broker、Consumer的協(xié)同工作為了便于理解,假定此時Kafka集群中有兩臺Producer,但只有一臺Kafka的Broker、Zookeeper和Consumer。如下圖所示的部署集群。整個系統(tǒng)運(yùn)行的順序可簡單歸納為:1、啟動Zookeeper的server。2、啟動Kafka的server。3、Producer如果生產(chǎn)了數(shù)據(jù),會先通過Zookeeper找到Broker,然后將數(shù)據(jù)存放進(jìn)Broker。4、Consumer如果要消費(fèi)數(shù)據(jù),會先通過Zookeeper找對應(yīng)的Broker,然后消費(fèi)。Producer代碼實(shí)例:producer=newProducer(...);message=newMessage("Hello".getBytes());set=newMessageSet(message);producer.send("topic1",set);發(fā)布消息時,Producer先構(gòu)造一條消息,將消息加入到消息集set中(Kafka支持批量發(fā)布,可以往消息集合中添加多條消息,然后一次性發(fā)布),send消息時,client需指定消息所屬的topic。Consumer代碼實(shí)例:streams[]=Consumer.createMessageStreams("topic1",1);for(message:streams){bytes=message.payload();//dosomethingwiththebytes}Kafka的存儲策略1、Kafka以topic來進(jìn)行消息管理,每個topic包含多個partition,一個partition對應(yīng)一個邏輯log,由多個segment組成。2、每個segment中存儲多條消息,消息id由其邏輯位置決定,即從消息id可直接定位到消息的存儲位置,避免id到位置的額外映射。

3、每個partition在內(nèi)存中對應(yīng)一個index,記錄每個segment中的第一條消息偏移。

4、發(fā)布者發(fā)到某個topic的消息會被均勻的分布到多個part上(隨機(jī)或根據(jù)用戶指定的回調(diào)函數(shù)進(jìn)行分布),broker收到發(fā)布消息往對應(yīng)part的最后一個segment上添加該消息,當(dāng)某個segment上的消息條數(shù)達(dá)到配置值或消息發(fā)布時間超過閾值時,segment上的消息會被flush到磁盤,只有flush到磁盤上的消息訂閱者才能訂閱到,segment達(dá)到一定的大小后將不會再往該segment寫數(shù)據(jù),broker會創(chuàng)建新的segment。為什么不要ActiveMQ

-Kafka的HA機(jī)制(性能與數(shù)據(jù)持久化之間的權(quán)衡)1、DataReplicationKafka分配Replica的算法-盡可能均衡(假設(shè)總共有n個broker):將所有Broker和待分配的Partition排序?qū)⒌趇個Partition分配到第(imodn)個Broker上將第i個Partition的第j個Replica分配到第((i+j)moden)個Broker上2、Kafka傳播(Propagate)消息、Follower與Leader的ACK的過程(性能與可靠性之間的權(quán)衡)3、PartitionFollower和Leader間的ISR復(fù)制機(jī)制(時間和條數(shù))4、Partition的重新分配5、LeaderElection(Kafka借助Zookeeper和ISR選擇Leader)6、有了Replication機(jī)制后,每個Partition可能有多個備份。某個Partition的Replica列表叫作AR(AssignedReplicas),AR中的第一個Replica即為“PreferredReplica”。創(chuàng)建一個新的Topic或者給已有Topic增加Partition時,Kafka保證PreferredReplica被均勻分布到集群中的所有Broker上。理想情況下,PreferredReplica會被選為Leader。以上兩點(diǎn)保證了所有Partition的Leader被均勻分布到了集群當(dāng)中,這一點(diǎn)非常重要,因?yàn)樗械淖x寫操作都由Leader完成,若Leader分布過于集中,會造成集群負(fù)載不均衡。但是,隨著集群的運(yùn)行,該平衡可能會因?yàn)锽roker的宕機(jī)而被打破,PreferredReplicaLeaderElectionTool工具就是用來幫助恢復(fù)Leader分配的平衡?!段濉稴torm實(shí)時圈子推薦:根據(jù)用戶的行為、興趣愛好以及圈子的

變化情況實(shí)時為新注冊用戶、定期為新用戶推薦最合適的圈子

當(dāng)前:簡單的圈子weigh計(jì)算排名推薦:weightManager,cronJobnightly不知道Strom,自己如何實(shí)現(xiàn)實(shí)時推薦?1、需要考慮的因素:低延遲。實(shí)時計(jì)算系統(tǒng),延遲是一定要低的。高性能。性能不高就是浪費(fèi)機(jī)器,浪費(fèi)機(jī)器就是浪費(fèi)¥。分布式??紤]多機(jī)復(fù)雜應(yīng)用問題。可擴(kuò)展。伴隨著業(yè)務(wù)的發(fā)展,我們的數(shù)據(jù)量、計(jì)算量可能會越來越大,所以希望這個系統(tǒng)是可擴(kuò)展的。容錯。這是分布式系統(tǒng)通用問題。一個節(jié)點(diǎn)掛了不能影響我們的應(yīng)用。2、實(shí)現(xiàn)方案:

消息隊(duì)列+分布在各個機(jī)器上的工作進(jìn)程易用性不夠。需要開發(fā)人員考慮各個處理組件的分布、消息的傳遞。消息不丟失。用戶發(fā)布的一個消息不能在實(shí)時處理的時候給丟了,對吧?更嚴(yán)格一點(diǎn),如果是一個精確數(shù)據(jù)統(tǒng)計(jì)的應(yīng)用,那么它處理的消息要不多不少才行。消息嚴(yán)格有序。有些消息之間是有強(qiáng)相關(guān)性的,如果處理時搞亂順序完全是不一樣的效果了。當(dāng)我們使用JDK中的Executor框架/ForkJoin框架,Queue以及一系列的跨JVM的操作之后,基本上就是實(shí)現(xiàn)了一個Storm的雛形。Storm基本架構(gòu)Spout(消息源)Bolt(消息處理者)Streamgrouping(數(shù)據(jù)的分發(fā)方式)Topology(拓?fù)洌¦orker(工作進(jìn)程)Task(執(zhí)行具體邏輯的任務(wù))Executor(執(zhí)行Task的線程)Configuration(配置)Storm消息源:Spout、計(jì)算拓補(bǔ):Topology、消息處理者:Bolt消息源Spouts是storm里面一個topology里面的消息生產(chǎn)者。一般來說消息源會從一個外部源讀取數(shù)據(jù)并且向topology里面發(fā)出消息:tuple。消息源Spouts可以是可靠的也可以是不可靠的。一個可靠的消息源可以重新發(fā)射一個tuple,如果這個tuple沒有被storm成功的處理。但是一個不可靠的消息源Spouts一旦發(fā)出一個tuple就把它徹底忘了—也就不可能再發(fā)了。消息源Spouts可以發(fā)射多條消息流stream。要達(dá)到這樣的效果,使用OutFieldsDeclarer.declareStream來定義多個stream,然后使用SpoutOutputCollector來發(fā)射指定的stream.一個實(shí)時計(jì)算應(yīng)用程序的邏輯在storm里面被封裝到topology對象里面,我把它叫做計(jì)算拓補(bǔ).Storm里面的topology相當(dāng)于Hadoop里面的一個MapReduceJob,它們的關(guān)鍵區(qū)別是:一個MapReduceJob最終總是會結(jié)束的,然而一個storm的topoloy會一直運(yùn)行—除非你顯式的殺死它。一個Topology是Spouts和Bolts組成的圖狀結(jié)構(gòu),而鏈接Spouts和Bolts的則是Streamgroupings。所有的消息處理邏輯被封裝在bolts里面。Bolts可以做很多事情:過濾,聚合,查詢數(shù)據(jù)庫等等。Bolts的主要方法是execute,它以一個tuple作為輸入,Bolts使用OutputCollector來發(fā)射tuple,Bolts必須要為它處理的每一個tuple調(diào)用OutputCollector的ack方法,以通知storm這個tuple被處理完成了。–從而我們通知這個tuple的發(fā)射者Spouts。一般的流程是:Bolts處理一個輸入tuple,發(fā)射0個或者多個tuple,然后調(diào)用ack通知storm自己已經(jīng)處理過這個tuple了。storm提供了一個IBasicBolt會自動調(diào)用ack。Storm集群結(jié)構(gòu)在Storm的集群里面有兩種節(jié)點(diǎn):控制節(jié)點(diǎn)和工作節(jié)點(diǎn)??刂乒?jié)點(diǎn)上面運(yùn)行一個叫Nimbus進(jìn)程,Nimbus負(fù)責(zé)在集群里面分發(fā)代碼,分配計(jì)算任務(wù),并且監(jiān)控狀態(tài)。每一個工作節(jié)點(diǎn)上面運(yùn)行一個叫做Supervisor進(jìn)程。Supervisor負(fù)責(zé)監(jiān)聽從Nimbus分配給它執(zhí)行的任務(wù),據(jù)此啟動或停止執(zhí)行任務(wù)的worker進(jìn)程N(yùn)imbus和Supervisor之間的所有協(xié)調(diào)工作都是通過Zookeeper集群完成。Storm:Worker、Task、消息流(Stream)、消息分發(fā)策略:Streamgroupings1、Supervisor會監(jiān)聽分配給它那臺機(jī)器的工作,根據(jù)需要啟動/關(guān)閉工作進(jìn)程,這個工作進(jìn)程就是worker,每一個worker都會占用工作節(jié)點(diǎn)的一個端口,這個端口可以在storm.yarm中配置。一個topology可能會在一個或者多個工作進(jìn)程里面執(zhí)行,每個工作進(jìn)程執(zhí)行整個topology的一部分,所以一個運(yùn)行的topology由運(yùn)行在很多機(jī)器上的很多工作進(jìn)程組成。2、每一個Spout和Bolt會被當(dāng)作很多task在整個集群里面執(zhí)行。默認(rèn)情況下每一個task對應(yīng)到一個線程(Executor),這個線程用來執(zhí)行這個task,而streamgrouping則是定義怎么從一堆task發(fā)射tuple到另外一堆task。3、消息流是storm里面的最關(guān)鍵的抽象。一個消息流是一個沒有邊界的tuple序列,而這些tuples會被以一種分布式的方式并行地創(chuàng)建和處理。對消息流的定義主要是對消息流里面的tuple的定義,我們會給tuple里的每個字段一個名字。并且不同tuple的對應(yīng)字段的類型必須一樣。也就是說:兩個tuple的第一個字段的類型必須一樣,第二個字段的類型必須一樣,但是第一個字段和第二個字段可以有不同的類型。在默認(rèn)的情況下,tuple的字段類型可以是:integer,long,short,byte,string,double,float,boolean和bytearray。你還可以

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論