paulwong

          Flume日志收集


          一、Flume介紹

          Flume是一個(gè)分布式、可靠、和高可用的海量日志聚合的系統(tǒng),支持在系統(tǒng)中定制各類數(shù)據(jù)發(fā)送方,用于收集數(shù)據(jù);同時(shí),F(xiàn)lume提供對(duì)數(shù)據(jù)進(jìn)行簡(jiǎn)單處理,并寫到各種數(shù)據(jù)接受方(可定制)的能力。

          設(shè)計(jì)目標(biāo):

          (1) 可靠性

          當(dāng)節(jié)點(diǎn)出現(xiàn)故障時(shí),日志能夠被傳送到其他節(jié)點(diǎn)上而不會(huì)丟失。Flume提供了三種級(jí)別的可靠性保障,從強(qiáng)到弱依次分別為:end-to-end(收到數(shù)據(jù)agent首先將event寫到磁盤上,當(dāng)數(shù)據(jù)傳送成功后,再刪除;如果數(shù)據(jù)發(fā)送失敗,可以重新發(fā)送。),Store on failure(這也是scribe采用的策略,當(dāng)數(shù)據(jù)接收方crash時(shí),將數(shù)據(jù)寫到本地,待恢復(fù)后,繼續(xù)發(fā)送),Best effort(數(shù)據(jù)發(fā)送到接收方后,不會(huì)進(jìn)行確認(rèn))。

          (2) 可擴(kuò)展性

          Flume采用了三層架構(gòu),分別為agent,collector和storage,每一層均可以水平擴(kuò)展。其中,所有agent和collector由master統(tǒng)一管理,這使得系統(tǒng)容易監(jiān)控和維護(hù),且master允許有多個(gè)(使用ZooKeeper進(jìn)行管理和負(fù)載均衡),這就避免了單點(diǎn)故障問題。

          (3) 可管理性

          所有agent和colletor由master統(tǒng)一管理,這使得系統(tǒng)便于維護(hù)。多master情況,F(xiàn)lume利用ZooKeeper和gossip,保證動(dòng)態(tài)配置數(shù)據(jù)的一致性。用戶可以在master上查看各個(gè)數(shù)據(jù)源或者數(shù)據(jù)流執(zhí)行情況,且可以對(duì)各個(gè)數(shù)據(jù)源配置和動(dòng)態(tài)加載。Flume提供了web 和shell script command兩種形式對(duì)數(shù)據(jù)流進(jìn)行管理。

          (4) 功能可擴(kuò)展性

          用戶可以根據(jù)需要添加自己的agent,collector或者storage。此外,F(xiàn)lume自帶了很多組件,包括各種agent(file, syslog等),collector和storage(file,HDFS等)。

           

          二、Flume架構(gòu)

          flume的邏輯架構(gòu):

          正如前面提到的,F(xiàn)lume采用了分層架構(gòu):分別為agent,collector和storage。其中,agent和collector均由兩部分組成:source和sink,source是數(shù)據(jù)來源,sink是數(shù)據(jù)去向

          Flume使用兩個(gè)組件:Master和Node,Node根據(jù)在Master shell或web中動(dòng)態(tài)配置,決定其是作為Agent還是Collector。

          (1) agent

          agent的作用是將數(shù)據(jù)源的數(shù)據(jù)發(fā)送給collector。

          Flume自帶了很多直接可用的數(shù)據(jù)源(source),如:

          • text(“filename”):將文件filename作為數(shù)據(jù)源,按行發(fā)送
          • tail(“filename”):探測(cè)filename新產(chǎn)生的數(shù)據(jù),按行發(fā)送出去
          • fsyslogTcp(5140):監(jiān)聽TCP的5140端口,并且接收到的數(shù)據(jù)發(fā)送出去
          • tailDir("dirname"[, fileregex=".*"[, startFromEnd=false[, recurseDepth=0]]]):監(jiān)聽目錄中的文件末尾,使用正則去選定需要監(jiān)聽的文件(不包含目錄),recurseDepth為遞歸監(jiān)聽其下子目錄的深度

          更多可參見這位朋友的整理:http://www.cnblogs.com/zhangmiao-chp/archive/2011/05/18/2050465.html

          同時(shí)提供了很多sink,如:

          • console[("format")] :直接將將數(shù)據(jù)顯示在consolr上
          • text(“txtfile”):將數(shù)據(jù)寫到文件txtfile中
          • dfs(“dfsfile”):將數(shù)據(jù)寫到HDFS上的dfsfile文件中
          • syslogTcp(“host”,port):將數(shù)據(jù)通過TCP傳遞給host節(jié)點(diǎn)
          • agentSink[("machine"[,port])]:等價(jià)于agentE2ESink,如果省略,machine參數(shù),默認(rèn)使用flume.collector.event.host與flume.collector.event.port作為默認(rèn)collecotr
          • agentDFOSink[("machine" [,port])]:本地?zé)醾鋋gent,agent發(fā)現(xiàn)collector節(jié)點(diǎn)故障后,不斷檢查collector的存活狀態(tài)以便重新發(fā)送event,在此間產(chǎn)生的數(shù)據(jù)將緩存到本地磁盤中
          • agentBESink[("machine"[,port])]:不負(fù)責(zé)的agent,如果collector故障,將不做任何處理,它發(fā)送的數(shù)據(jù)也將被直接丟棄
          • agentE2EChain:指定多個(gè)collector提高可用性。 當(dāng)向主collector發(fā)送event失效后,轉(zhuǎn)向第二個(gè)collector發(fā)送,當(dāng)所有的collector失敗后,它會(huì)非常執(zhí)著的再來一遍

          更多可參見這位朋友的整理:http://www.cnblogs.com/zhangmiao-chp/archive/2011/05/18/2050472.html

          (2) collector

          collector的作用是將多個(gè)agent的數(shù)據(jù)匯總后,加載到storage中。

          它的source和sink與agent類似。

          數(shù)據(jù)源(source),如:

          • collectorSource[(port)]:Collector source,監(jiān)聽端口匯聚數(shù)據(jù)
          • autoCollectorSource:通過master協(xié)調(diào)物理節(jié)點(diǎn)自動(dòng)匯聚數(shù)據(jù)
          • logicalSource:邏輯source,由master分配端口并監(jiān)聽rpcSink

          sink,如:

          • collectorSink( "fsdir","fsfileprefix",rollmillis):collectorSink,數(shù)據(jù)通過collector匯聚之后發(fā)送到hdfs, fsdir 是hdfs目錄,fsfileprefix為文件前綴碼
          • customdfs("hdfspath"[, "format"]):自定義格式dfs

          (3) storage

          storage是存儲(chǔ)系統(tǒng),可以是一個(gè)普通file,也可以是HDFS,HIVE,HBase,分布式存儲(chǔ)等。

          (4) Master

          Master是管理協(xié)調(diào)agent和collector的配置等信息,是flume集群的控制器。

           

          在Flume中,最重要的抽象是data flow(數(shù)據(jù)流),data flow描述了數(shù)據(jù)從產(chǎn)生,傳輸、處理并最終寫入目標(biāo)的一條路徑。

          1. 對(duì)于agent數(shù)據(jù)流配置就是從哪得到數(shù)據(jù),把數(shù)據(jù)發(fā)送到哪個(gè)collector。
          2. 對(duì)于collector是接收agent發(fā)過來的數(shù)據(jù),把數(shù)據(jù)發(fā)送到指定的目標(biāo)機(jī)器上。

          注:Flume框架對(duì)hadoop和zookeeper的依賴只是在jar包上,并不要求flume啟動(dòng)時(shí)必須將hadoop和zookeeper服務(wù)也啟動(dòng)。

           

          三、Flume分布式環(huán)境部署

          1.實(shí)驗(yàn)場(chǎng)景

          • 操作系統(tǒng)版本:RedHat 5.6
          • Hadoop版本:0.20.2
          • Jdk版本:jdk1.6.0_26
          • 安裝flume版本:flume-distribution-0.9.4-bin

          部署flume在集群上,按照如下步驟:

          1. 在集群上的每臺(tái)機(jī)器上安裝flume
          2. 選擇一個(gè)或多個(gè)節(jié)點(diǎn)當(dāng)做master
          3. 修改靜態(tài)配置文件
          4. 在至少一臺(tái)機(jī)器上啟動(dòng)一個(gè)master ,所有節(jié)點(diǎn)啟動(dòng)flume node
          5. 動(dòng)態(tài)配置

          需要在集群的每臺(tái)機(jī)器上部署Flume。

          注意:flume集群整個(gè)集群的網(wǎng)絡(luò)環(huán)境要保證穩(wěn)定,可靠,否則會(huì)出現(xiàn)一些莫名錯(cuò)誤(比如:agent端發(fā)送不了數(shù)據(jù)到collector)。

          1.Flume環(huán)境安裝

          復(fù)制代碼
          $wget http://cloud.github.com/downloads/cloudera/flume/flume-distribution-0.9.4-bin.tar.gz $tar -xzvf flume-distribution-0.9.4-bin.tar.gz $cp -rf flume-distribution-0.9.4-bin /usr/local/flume $vi /etc/profile  #添加環(huán)境配置     export FLUME_HOME=/usr/local/flume     export PATH=.:$PATH::$FLUME_HOME/bin $source /etc/profile  $flume #驗(yàn)證安裝
          復(fù)制代碼

           

          2.選擇一個(gè)或多個(gè)節(jié)點(diǎn)當(dāng)做master

          對(duì)于master的選擇情況,可以在集群上定義一個(gè)master,也可以為了提高可用性選擇多個(gè)節(jié)點(diǎn)做為master。

          • 單點(diǎn)master模式:容易管理,但在系統(tǒng)的容錯(cuò)和擴(kuò)展性有缺陷
          • 多點(diǎn)master模式:通常是運(yùn)行3/5個(gè)master,能很好的容錯(cuò)

          Flume master數(shù)量的選擇原則

                分布式的master能夠繼續(xù)正常工作不會(huì)崩潰的前提是正常工作的master數(shù)量超過總master數(shù)量的一半。

          Flume master 的作用主要有兩個(gè):

          • 跟蹤各節(jié)點(diǎn)的配置情況,通知節(jié)點(diǎn)配置的改變;
          • 跟蹤來自flow的結(jié)尾操控在可靠模式下(E2E)的信息,以至于讓flow的源頭知道什么時(shí)候停止傳輸event。

           

          3.修改靜態(tài)配置文件

          site-specific設(shè)置對(duì)于flume節(jié)點(diǎn)和master通過在每一個(gè)集群節(jié)點(diǎn)的conf/flume-site.xml是可配置的,如果這個(gè)文件不存在,設(shè)置的屬性默認(rèn)的在conf/flume­-conf.xml中,在接下來的例子中,在flume的節(jié)點(diǎn)上設(shè)置master名,讓節(jié)點(diǎn)自己去尋找叫“master”的flume Master。

          復(fù)制代碼
          <?xml version="1.0"?>     <?xml-stylesheet type="text/xsl"  href="configuration.xsl"?>     <configuration>         <property>             <name>flume.master.servers</name>             <value>master</value>          </property>     </configuration>
          復(fù)制代碼

          在多master的情況下需要如下配置:

          復(fù)制代碼
          <property>     <name>flume.master.servers</name>    <value>hadoopmaster.com,hadoopedge.com,datanode4.com</value>     <description>A comma-separated list of hostnames, one for each machine in the Flume Master.</description> </property> <property>     <name>flume.master.store</name>     <value>zookeeper</value>     <description>How the Flume Master stores node configurations. Must be either 'zookeeper' or 'memory'.</description> </property> <property>     <name>flume.master.serverid</name>     <value>2</value>     <description>The unique identifier for a machine in a Flume Master ensemble. Must be different on every master instance.</description> </property>
          復(fù)制代碼

          注意:flume.master.serverid 屬性的配置主要是針對(duì)master,集群上Master節(jié)點(diǎn)的flume.master.serverid 必須是不能相同的,該屬性的值以0開始。

          當(dāng)使用agent角色時(shí),你可以通過添加下面的配置文件在flume-conf.xml中,來設(shè)置默認(rèn)的collector主機(jī):

          復(fù)制代碼
          <property>     <name>flume.collector.event.host</name>     <value>collector</value>     <description>This is the host name of the default "remote"  collector.</description> </property> <property>     <name>flume.collector.port</name>     <value>35853</value>     <description>This default tcp port that the collector listens to in order to receive events it is collecting.</description> </property>
          復(fù)制代碼

          關(guān)于配置可參見:http://www.cnblogs.com/zhangmiao-chp/archive/2011/05/18/2050443.html

           

          4.啟動(dòng)集群

          集群上節(jié)點(diǎn)啟動(dòng):

          1. 在命令行輸入:flume master 啟動(dòng)master節(jié)點(diǎn)
          2. 在命令行輸入:flume node –n nodeName 啟動(dòng)其他節(jié)點(diǎn),nodeName最好根據(jù)集群邏輯的劃分來取名子,這樣在 master進(jìn)行配置的時(shí)候比較清晰。

          名字規(guī)則自己定義,方便記憶和動(dòng)態(tài)配置即可(后續(xù)會(huì)有介紹動(dòng)態(tài)配置)

           

           5.基于flume shell的動(dòng)態(tài)配置

          關(guān)于flume shell 中的command參見:http://www.cnblogs.com/zhangmiao-chp/archive/2011/05/18/2050461.html

          假設(shè)我們目前部署的Flume集群結(jié)構(gòu)如下:

          我們想將A-F所在的機(jī)器的系統(tǒng)日志收集到HDFS中,怎么樣在flume shell中配置達(dá)到我們的目的呢?

          1. 設(shè)置邏輯節(jié)點(diǎn)(logical node)

          復(fù)制代碼
          $flume shell >connect localhost >help >exec map 192.168.0.1 agentA >exec map 192.168.0.2 agentB >exec map 192.168.0.3 agentC >exec map 192.168.0.4 agentD >exec map 192.168.0.5 agentE >exec map 192.168.0.6 agentF >getnodestatus         192.168.0.1 --> IDLE         192.168.0.2 --> IDLE         192.168.0.3 --> IDLE         192.168.0.4 --> IDLE         192.168.0.5 --> IDLE         192.168.0.6 --> IDLE         agentA --> IDLE         agentB --> IDLE         agentC --> IDLE         agentD --> IDLE         agentE --> IDLE         agentF --> IDLE >exec map 192.168.0.11 collector
          復(fù)制代碼

          這里你也可以打開web master界面查看。

          2.啟動(dòng)Collector的監(jiān)聽端口

          >exec config collector 'collectorSource(35853)' 'collectorSink("","")'#collector節(jié)點(diǎn)監(jiān)聽35853端口過來的數(shù)據(jù),這一部非常重要

          登陸到collector服務(wù)器進(jìn)行端口檢測(cè)

          $netstat -nalp|grep 35853 

          如果在master中未進(jìn)行上述配置,在collector上檢測(cè)不到此打開端口

          3.設(shè)置各節(jié)點(diǎn)的source和sink

          >exec config collector 'collectorSource(35853)' 'collectorSink("hdfs://namenode/flume/","syslog")'  >exec config agentA 'tail("/tmp/log/message")' 'agentBESink("192.168.0.11")' #經(jīng)過實(shí)驗(yàn),好像一個(gè)邏輯節(jié)點(diǎn),最多只能有一個(gè)source和sink.
          >...
          >exec config agentF 'tail("/tmp/log/message")' 'agentBESink("192.168.0.11")'

          這時(shí)的配置情況可從master web中一目了然,此時(shí)已經(jīng)可以達(dá)到我們最初的目的了。

          以上通過flume shell進(jìn)行的動(dòng)態(tài)配置,在flume master web中都可以進(jìn)行,在此不做進(jìn)一步說明。

           

           四、高級(jí)動(dòng)態(tài)配置

          高級(jí)配置其實(shí)就是在上述簡(jiǎn)單配置中增加了以下幾個(gè)特性來保證系統(tǒng)更好的運(yùn)行:

          • 多Master(Master節(jié)點(diǎn)的高可用)
          • Collector Chain(Collector的高可用)

          多Master的情況在上面已經(jīng)有過介紹,包括用途和master個(gè)數(shù)等。下面來簡(jiǎn)單看一下Collector Chain,其實(shí)也很簡(jiǎn)單,就是在動(dòng)態(tài)配置時(shí),使用agent*Chain來指定多個(gè)Collector來保證其日志傳輸?shù)目捎眯浴?匆幌乱话阏江h(huán)境中flume的邏輯圖:

          這里agentA和agentB指向collectorA,如果CollectorA crach了,根據(jù)配置的可靠性級(jí)別agent會(huì)有相應(yīng)的動(dòng)作,我們很可能為了保障高效傳輸而沒有選擇E2E(即使是這種方式,Agent本地日志累積過多依然是一個(gè)問題),一般會(huì)配置多個(gè)Collector,形成collector chain。

          >exec config agentC 'tail("/tmp/log/message")' 'agentE2EChain("collectorB:35853","collectorA:35853")' >exec config agentD 'tail("/tmp/log/message")' 'agentE2EChain("collectorB:35853","collectorC:35853")'

          這樣collectorB在出問題時(shí):

           

          五、問題和總結(jié)

          上述節(jié)點(diǎn)有如下幾類:master、agent、collector、storage,針對(duì)每類節(jié)點(diǎn)我們看一下高可用和有沒有可能引起性能瓶頸問題。

          首先,storage層的失敗collector層的失敗是一樣的,只要數(shù)據(jù)放不到最終的位置,就認(rèn)為節(jié)點(diǎn)是失敗的。我們一定會(huì)根據(jù)收集數(shù)據(jù)的可靠性設(shè)定合適的傳輸模式,而且會(huì)根據(jù)我們的配置,自己控制collector接收數(shù)據(jù)的情況,collector的性能影響的是整個(gè)flume集群的數(shù)據(jù)吞吐量,所以collector最好單獨(dú)部署,所以一般不用考慮高可用問題。

          然后,agent層的失敗,F(xiàn)lume數(shù)據(jù)安全級(jí)別的配置主要Agent的配置上,Agent提供三種級(jí)別發(fā)送數(shù)據(jù)到collector:E2E、DFO、BF,在些不贅述。看一下一位大牛的總結(jié):

          復(fù)制代碼
          agent節(jié)點(diǎn)監(jiān)控日志文件夾下的所有文件,每一個(gè)agent最多監(jiān)聽1024個(gè)文件,每一個(gè)文件在agent的都會(huì)有一個(gè)類似游標(biāo)的東西,記錄監(jiān)聽文件讀取的位置,這樣每次文件有新的記錄產(chǎn)生,那么游標(biāo)就會(huì)讀取增量記錄,根據(jù)agent配置發(fā)送到collector的安全層級(jí)屬性有E2E,DFO。
          如果是E2E的情況那么agent節(jié)點(diǎn)會(huì)首先把文件寫入到agent節(jié)點(diǎn)的文件夾下,然后發(fā)送給collector,如果最終數(shù)據(jù)最終成功存儲(chǔ)到storage層,那么agent刪除之前寫入的文件,如果沒有收到成功的信息,那么就保留信息。 如果agent節(jié)點(diǎn)出現(xiàn)問題,那么相當(dāng)于所有的記錄信息都消失了,如果直接重新啟動(dòng),agent會(huì)認(rèn)為日志文件夾下的所有文件都是沒有監(jiān)聽過的,沒有文件記錄的標(biāo)示,所以會(huì)重新讀取文件,這樣,日志就會(huì)有重復(fù),具體恢復(fù)辦法如下 將agent節(jié)點(diǎn)上監(jiān)聽的日志文件夾下已經(jīng)發(fā)送的日志文件移出,處理完,故障重新啟動(dòng)agent即可。 注:在agent節(jié)點(diǎn)失敗的情況下,按照失敗的時(shí)間點(diǎn),將時(shí)間點(diǎn)之前的數(shù)據(jù)文件移出,將flume.agent.logdir配置的文件夾清空,重新啟動(dòng)agent。
          復(fù)制代碼

          最后,master失敗,master宕機(jī),整個(gè)集群將不能工作,在重新啟動(dòng)集群,將agent監(jiān)聽的日志文件夾下的所有文件移出,然后重新啟動(dòng)master即可。在多master節(jié)點(diǎn)情況下,只要集群上正常工作的master大于總master數(shù)量的一半,集群就能正常工作,那么只要恢復(fù)其中宕機(jī)的master即可。

           

          問題總結(jié):

          復(fù)制代碼
          1.Flume在agent端采集數(shù)據(jù)的時(shí)候默認(rèn)會(huì)在/tmp/flume-{user}下生成臨時(shí)的目錄用于存放agent自己截取的日志文件,如果文件過大導(dǎo)致磁盤寫滿那么agent端會(huì)報(bào)出    Error closing logicalNode a2-18 sink: No space left on device,所以在配置agent端的時(shí)候需要注意   <property>     <name>flume.agent.logdir</name>     <value>/data/tmp/flume-${user.name}/agent</value>   </property> 屬性,只要保證flume在7*24小時(shí)運(yùn)行過程agent端不會(huì)使該路徑flume.agent.logdir磁盤寫滿即可。
          復(fù)制代碼
          2. Flume在啟動(dòng)時(shí)候會(huì)去尋找hadoop-core-*.jar的文件,需要修改標(biāo)準(zhǔn)版的hadoop核心jar包的名字 將hadoop-*-core.jar改成hadoop-core-*.jar。
          3.Flume集群中的flume必須版本一致。否則會(huì)出現(xiàn)莫名其妙的錯(cuò)誤。
          復(fù)制代碼
          4.Flume集群收集的日志發(fā)送到hdfs上建立文件夾的時(shí)間依據(jù)是根據(jù)event的時(shí)間,在源代碼上是Clock.unixTime(),所以如果想要根據(jù)日志生成的時(shí)間來生成文件的話,需要對(duì) com.cloudera.flume.core.EventImpl 類的構(gòu)造函數(shù) public EventImpl(byte[] s, long timestamp, Priority pri, long nanoTime,       String host, Map<String, byte[]> fields)重新寫,解析數(shù)組s的內(nèi)容取出時(shí)間,賦給timestamp。
          注意:flume的框架會(huì)構(gòu)造s內(nèi)容是空的數(shù)組,用來發(fā)送類似簡(jiǎn)單驗(yàn)證的event,所以需要注意s內(nèi)容為空的時(shí)候timestamp的問題。
          復(fù)制代碼
          5.如果collector和agent不在一個(gè)網(wǎng)段的話會(huì)發(fā)生閃斷的現(xiàn)象,這樣的話,就會(huì)造成agent端不能傳送數(shù)據(jù)個(gè)collector所以,在部署agent和collector最好在一個(gè)網(wǎng)段。
          6.如果在啟動(dòng)master時(shí)出現(xiàn):“試著啟動(dòng)hostname,但是hostname不在master列表里的錯(cuò)誤“,這是需要檢查是否主機(jī)地址和hostname配置的正確與否。
          7.在源端,有一個(gè)比較大的缺陷,在tail類的source,不支持,斷點(diǎn)續(xù)傳功能。因?yàn)橹貑ode后沒有記錄上次文件讀到的位置,從而沒辦法知道,下次再讀時(shí),從什么地方開始讀。 特別是在日志文件一直在增加的時(shí)候。flume的source node掛了。等flume的source再次開啟的這段時(shí)間內(nèi),增加的日志內(nèi)容,就沒辦法被source讀取到了。 不過flume有一個(gè)execStream的擴(kuò)展,可以自己寫一個(gè)監(jiān)控日志增加情況,把增加的日志,通過自己寫的工具把增加的內(nèi)容,傳送給flume的node。再傳送給sink的node。

           

          以前文章中介紹過Scribe方案,給我的最直觀感受就是:

          • scribe安裝復(fù)雜,配置簡(jiǎn)單
          • flume安裝簡(jiǎn)單,動(dòng)態(tài)配置復(fù)雜

          下面董的博客中的一副對(duì)比圖:

          posted on 2013-10-31 18:20 paulwong 閱讀(51020) 評(píng)論(1)  編輯  收藏 所屬分類: FLUME

          Feedback

          # re: Flume日志收集 2016-04-22 16:48 jiangzhenxing

          不錯(cuò),謝謝!  回復(fù)  更多評(píng)論   



          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 大同市| 大姚县| 韩城市| 孟村| 南丹县| 资溪县| 松溪县| 永德县| 威海市| 五家渠市| 新乐市| 大埔县| 石柱| 博兴县| 留坝县| 和平区| 石林| 深泽县| 时尚| 台北市| 措勤县| 蓬溪县| 政和县| 于田县| 仙游县| 红桥区| 盐津县| 永康市| 康乐县| 南昌县| 安宁市| 原阳县| 南投市| 丹阳市| 乐至县| 石河子市| 宁安市| 高要市| 梅州市| 图片| 嘉定区|