91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Dubbo 邁出云原生重要一步 - 應用級服務發現解析

發布時間:2020-08-11 11:26:20 來源:ITPUB博客 閱讀:163 作者:阿里巴巴云原生公眾號 欄目:服務器

Dubbo 邁出云原生重要一步 - 應用級服務發現解析

作者 | 劉軍(陸龜)  Apache Dubbo PMC


Dubbo 邁出云原生重要一步 - 應用級服務發現解析

概述


社區版本 Dubbo 從 2.7.5 版本開始,新引入了一種基于實例(應用)粒度的服務發現機制,這是我們為 Dubbo 適配云原生基礎設施的一步重要探索。版本發布到現在已有近半年時間,經過這段時間的探索與總結,我們對這套機制的可行性與穩定性有了更全面、深入的認識;同時在 Dubbo 3.0 的規劃也在全面進行中,如何讓應用級服務發現成為未來下一代服務框架 Dubbo 3.0 的基礎服務模型,解決云原生、規模化微服務集群擴容與可伸縮性問題,也已經成為我們當前工作的重點。

既然這套新機制如此重要,那它到底是怎么工作的呢?今天我們就來詳細解讀一下。在最開始的社區版本,我們給這個機制取了一個神秘的名字 - 服務自省,下文將進一步解釋這個名字的由來,并引用服務自省代指這套應用級服務發現機制。

熟悉 Dubbo 開發者應該都知道,一直以來都是面向 RPC 方法去定義服務的,并且這也是 Dubbo 開發友好性、治理功能強的基礎。既然如此,那我們為什么還要定義個應用粒度的服務發現機制呢?這個機制到底是怎么工作的?它與當前機制的區別是什么?它能給我們帶來哪些好處那?對適配云原生、性能提升又有哪些幫助?

帶著所有的這些問題,我們開始本文的講解。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析

服務自省是什么?


首先,我們先來解釋文章開篇提到的問題:

  1. 應用粒度服務發現是到底是一種怎樣的模型,它與當前的 Dubbo 服務發現模型的區別是什么?

  2. 我們為什么叫它服務自省?


所謂“應用/實例粒度” 或者“RPC 服務粒度”強調的是一種地址發現的數據組織格式。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


以 Dubbo 當前的地址發現數據格式為例,它是“RPC 服務粒度”的,它是以 RPC 服務作為 key,以實例列表作為 value 來組織數據的:


"RPC Service1": [
  {"name":"instance1""ip":"127.0.0.1""metadata":{"timeout":1000}},
  {"name":"instance2""ip":"127.0.0.1""metadata":{"timeout":2000}},
  {"name":"instance3""ip":"127.0.0.1""metadata":{"timeout":3000}},
]
"RPC Service2": [Instance list of RPC Service2],
"RPC ServiceN": [Instance list of RPC ServiceN]


而我們新引入的“應用粒度的服務發現”,它以應用名(Application)作為 key,以這個應用部署的一組實例(Instance)列表作為 value。這帶來兩點不同:


  1. 數據映射關系變了,從 RPC Service -> Instance 變為 Application -> Instance;

  2. 數據變少了,注冊中心沒有了 RPC Service 及其相關配置信息。


"application1": [
  {"name":"instance1""ip":"127.0.0.1""metadata":{}},
  {"name":"instance2""ip":"127.0.0.1""metadata":{}},
  {"name":"instanceN""ip":"127.0.0.1""metadata":{}}
]


要進一步理解新模型帶來的變化,我們看一下應用與 RPC 服務間的關系,顯而易見的,1 個應用內可能會定義 n 個 RPC Service。因此 Dubbo 之前的服務發現粒度更細,在注冊中心產生的數據條目也會更多(與 RPC 服務成正比),同時也存在一定的數據冗余。


簡單理解了應用級服務發現的基本機制,接著解釋它為什么會被叫做“服務自省”?


其實這還是得從它的工作原理說起,上面我們提到,應用粒度服務發現的數據模型有幾個以下明顯變化:數據中心的數據量少了,RPC 服務相關的數據在注冊中心沒有了,現在只有 application - instance 這兩個層級的數據。為了保證這部分缺少的 RPC 服務數據仍然能被 Consumer 端正確的感知,我們在 Consumer 和 Provider 間建立了一條單獨的通信通道:Consumer 和 Provider 兩兩之間通過特定端口交換信息,我們把這種 Provider 自己主動暴露自身信息的行為認為是一種內省機制,因此從這個角度出發,我們把整個機制命名為:服務自省


Dubbo 邁出云原生重要一步 - 應用級服務發現解析

為什么需要服務自省?


上面講服務自省的大概原理的時候也提到了它給注冊中心帶來的幾點不同,這幾點不同體現在 Dubbo 框架側(甚至整個微服務體系中),有以下優勢:


  • 與業界主流微服務模型對齊,比如 SpringCloud、Kubernetes Native Service 等;

  • 提升性能與可伸縮性。注冊中心數據的重新組織(減少),能最大幅度的減輕注冊中心的存儲、推送壓力,進而減少 Dubbo Consumer 側的地址計算壓力;集群規模也開始變得可預測、可評估(與 RPC 接口數量無關,只與實例部署規模相關)。


1. 對齊主流微服務模型

自動、透明的實例地址發現(負載均衡)是所有微服務框架需要解決的事情,這能讓后端的部署結構對上游微服務透明,上游服務只需要從收到的地址列表中選取一個,發起調用就可以了。要實現以上目標,涉及兩個關鍵點的自動同步:


  • 實例地址,服務消費方需要知道地址以建立鏈接;

  • RPC 方法定義,服務消費方需要知道 RPC 服務的具體定義,不論服務類型是 rest 或 rmi 等。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


對于 RPC 實例間借助注冊中心的數據同步,REST 定義了一套非常有意思的成熟度模型,感興趣的朋友可以參考這里的鏈接 :

https://www.martinfowler.com/articles/richardsonMaturityModel.html

按照文章中的 4 級成熟度定義,Dubbo 當前基于接口粒度的模型可以對應到 L4 級別。


接下來,我們看看 Dubbo、SpringCloud 以及 Kubernetes 分別是怎么圍繞自動化的實例地址發現這個目標設計的。


2. Spring Cloud


Spring Cloud 通過注冊中心只同步了應用與實例地址,消費方可以基于實例地址與服務提供方建立鏈接,但是消費方對于如何發起 HTTP 調用(SpringCloud 基于 rest 通信)一無所知,比如對方有哪些 HTTP endpoint,需要傳入哪些參數等。


RPC 服務這部分信息目前都是通過線下約定或離線的管理系統來協商的。這種架構的優缺點總結如下:


  • 優勢:部署結構清晰、地址推送量小;

  • 缺點:地址訂閱需要指定應用名, provider 應用變更(拆分)需消費端感知;RPC 調用無法全自動同步。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


3. Dubbo

Dubbo 通過注冊中心同時同步了實例地址和 RPC 方法,因此其能實現 RPC 過程的自動同步,面向 RPC 編程、面向 RPC 治理,對后端應用的拆分消費端無感知,其缺點則是地址推送數量變大,和 RPC 方法成正比。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


4. Dubbo + Kubernetes

Dubbo 要支持 Kubernetes native service,相比之前自建注冊中心的服務發現體系來說,在工作機制上主要有兩點變化:


  • 服務注冊由平臺接管,provider 不再需要關心服務注冊;

  • consumer 端服務發現將是 Dubbo 關注的重點,通過對接平臺層的 API-Server、DNS 等,Dubbo client 可以通過一個 Service Name(通常對應到 Application Name)查詢到一組 Endpoints(一組運行 provider 的 pod),通過將 Endpoints 映射到 Dubbo 內部地址列表,以驅動 Dubbo 內置的負載均衡機制工作。


Kubernetes Service 作為一個抽象概念,怎么映射到 Dubbo 是一個值得討論的點

Service Name - > Application Name,Dubbo 應用和 Kubernetes 服務一一對應,對于微服務運維和建設環節透明,與開發階段解耦。


apiVersion: v1
kind: Service
metadata:
  name: provider-app-name
spec:
  selector:
    app: provider-app-name
  ports:
    - protocol: TCP
      port:
      targetPort: 9376


Service Name - > Dubbo RPC Service,Kubernetes 要維護調度的服務與應用內建 RPC 服務綁定,維護的服務數量變多。


---
apiVersion: v1
kind: Service
metadata:
  name: rpc-service-1
spec:
  selector:
    app: provider-app-name
  ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
  name: rpc-service-2
spec:
  selector:
    app: provider-app-name
  ports: ##
...
---
apiVersion: v1
kind: Service
metadata:
  name: rpc-service-N
spec:
  selector:
    app: provider-app-name
  ports: ##
...


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


結合以上幾種不同微服務框架模型的分析,我們可以發現,Dubbo 與 SpringCloud、Kubernetes 等不同產品在微服務的抽象定義上還是存在很大不同的。SpringCloud 和 Kubernetes 在微服務的模型抽象上還是比較接近的,兩者基本都只關心實例地址的同步,如果我們去關心其他的一些服務框架產品,會發現它們絕大多數也是這么設計的;


即 REST 成熟度模型中的 L3 級別。


對比起來 Dubbo 則相對是比較特殊的存在,更多的是從 RPC 服務的粒度去設計的。


對應 REST 成熟度模型中的 L4 級別。


如我們上面針對每種模型做了詳細的分析,每種模型都有其優勢和不足。而我們最初決定 Dubbo 要做出改變,往其他的微服務發現模型上的對齊,是我們最早在確定 Dubbo 的云原生方案時,我們發現要讓 Dubbo 去支持 Kubernetes Native Service,模型對齊是一個基礎條件;另一點是來自用戶側對 Dubbo 場景化的一些工程實踐的需求,得益于 Dubbo 對多注冊、多協議能力的支持,使得 Dubbo 聯通不同的微服務體系成為可能,而服務發現模型的不一致成為其中的一個障礙,這部分的場景描述請參見這里


5. 更大規模的微服務集群 - 解決性能瓶頸


這部分涉及到和注冊中心、配置中心的交互,關于不同模型下注冊中心數據的變化,之前原理部分我們簡單分析過。為更直觀的對比服務模型變更帶來的推送效率提升,我們來通過一個示例看一下不同模型注冊中心的對比:


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


圖中左邊是微服務框架的一個典型工作流程,Provider 和  Consumer 通過注冊中心實現自動化的地址通知。其中,Provider 實例的信息如圖中表格所示:


應用 DEMO 包含三個接口 DemoService 1 2 3,當前實例的 ip 地址為 10.210.134.30。


  • 對于 Spring Cloud 和 Kubernetes 模型,注冊中心只會存儲一條 DEMO - 10.210.134.30+metadata 的數據;

  • 對于老的 Dubbo 模型,注冊中心存儲了三條接口粒度的數據,分別對應三個接口 DemoService 1 2 3,并且很多的址數據都是重復的。


可以總結出,基于應用粒度的模型所存儲和推送的數據量是和應用、實例數成正比的,只有當我們的應用數增多或應用的實例數增長時,地址推送壓力才會上漲。


而對于基于接口粒度的模型,數據量是和接口數量正相關的,鑒于一個應用通常發布多個接口的現狀,這個數量級本身比應用粒度是要乘以倍數的;另外一個關鍵點在于,接口粒度導致的集群規模評估的不透明,相對于實i例、應用增長都通常是在運維側的規劃之中,接口的定義更多的是業務側的內部行為,往往可以繞過評估給集群帶來壓力。


以 Consumer 端服務訂閱舉例,根據我對社區部分 Dubbo 中大規模頭部用戶的粗略統計,根據受統計公司的實際場景,一個 Consumer 應用要消費(訂閱)的 Provier 應用數量往往要超過 10 個,而具體到其要消費(訂閱)的的接口數量則通常要達到 30 個,平均情況下 Consumer 訂閱的 3 個接口來自同一個 Provider 應用,如此計算下來,如果以應用粒度為地址通知和選址基本單位,則平均地址推送和計算量將下降 60% 還要多。


而在極端情況下,也就是當 Consumer 端消費的接口更多的來自同一個應用時,這個地址推送與內存消耗的占用將會進一步得到降低,甚至可以超過 80% 以上。


一個典型的幾段場景即是 Dubbo 體系中的網關型應用,有些網關應用消費(訂閱)達 100+ 應用,而消費(訂閱)的服務有 1000+ ,平均有 10 個接口來自同一個應用,如果我們把地址推送和計算的粒度改為應用,則地址推送量從原來的 n  1000 變為 n  100,地址數量降低可達近 90%。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析

工作原理


1. 設計原則


上面一節我們從服務模型及支撐大規模集群的角度分別給出了 Dubbo 往應用級服務發現靠攏的好處或原因,但這么做的同時接口粒度的服務治理能力還是要繼續保留,這是 Dubbo 框架編程模型易用性、服務治理能力優勢的基礎。


以下是我認為我們做服務模型遷移仍要堅持的設計原則:


  • 新的服務發現模型要實現對原有 Dubbo 消費端開發者的無感知遷移,即 Dubbo 繼續面向 RPC 服務編程、面向 RPC 服務治理,做到對用戶側完全無感知;

  • 建立 Consumer 與 Provider 間的自動化 RPC 服務元數據協調機制,解決傳統微服務模型無法同步 RPC 級接口配置的缺點。


2. 基本原理詳解


應用級服務發現作為一種新的服務發現機制,和以前 Dubbo 基于 RPC 服務粒度的服務發現在核心流程上基本上是一致的:即服務提供者往注冊中心注冊地址信息,服務消費者從注冊中心拉取&訂閱地址信息。


這里主要的不同有以下兩點:


  • 注冊中心數據以“應用 - 實例列表”格式組織,不再包含 RPC 服務信息;


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


以下是每個 Instance metadata 的示例數據,總的原則是 metadata 只包含當前 instance 節點相關的信息,不涉及 RPC 服務粒度的信息。


總體信息概括如下:實例地址、實例各種環境標、metadata service 元數據、其他少量必要屬性。


{
  "name""provider-app-name",
  "id""192.168.0.102:20880",
  "address""192.168.0.102",
  "port"20880,
  "sslPort"null,
  "payload": {
    "id"null,
    "name""provider-app-name",
    "metadata": {
      "metadataService""{\"dubbo\":{\"version\":\"1.0.0\",\"dubbo\":\"2.0.2\",\"release\":\"2.7.5\",\"port\":\"20881\"}}",
      "endpoints""[{\"port\":20880,\"protocol\":\"dubbo\"}]",
      "storage-type""local",
      "revision""6785535733750099598",
    }
  },
  "registrationTimeUTC"1583461240877,
  "serviceType""DYNAMIC",
  "uriSpec"null
}


  • Client – Server 自行協商 RPC 方法信息。


在注冊中心不再同步 RPC 服務信息后,服務自省在服務消費端和提供端之間建立了一條內置的 RPC 服務信息協商機制,這也是“服務自省”這個名字的由來。服務端實例會暴露一個預定義的 MetadataService RPC 服務,消費端通過調用 MetadataService 獲取每個實例 RPC 方法相關的配置信息。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


當前 MetadataService 返回的數據格式如下:


[
  "dubbo://192.168.0.102:20880/org.apache.dubbo.demo.DemoService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider&timestamp=1583469714314", 
 "
dubbo://192.168.0.102:20880/org.apache.dubbo.demo.HelloService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider&timestamp=1583469714314",
  "
dubbo://192.168.0.102:20880/org.apache.dubbo.demo.WorldService?anyhost=true&application=demo-provider&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&methods=sayHello&pid=9585&release=2.7.5&side=provider&timestamp=1583469714314"
]


熟悉 Dubbo 基于 RPC 服務粒度的服務發現模型的開發者應該能看出來,服務自省機制機制將以前注冊中心傳遞的 URL 一拆為二:


  • 一部分和實例相關的數據繼續保留在注冊中心,如 ip、port、機器標識等;

  • 另一部分和 RPC 方法相關的數據從注冊中心移除,轉而通過 MetadataService 暴露給消費端。


理想情況下是能達到數據按照實例、RPC 服務嚴格區分開來,但明顯可以看到以上實現版本還存在一些數據冗余,有些也數據還未合理劃分。尤其是 MetadataService 部分,其返回的數據還只是簡單的 URL 列表組裝,這些 URL其實是包含了全量的數據。


以下是服務自省的一個完整工作流程圖,詳細描述了服務注冊、服務發現、MetadataService、RPC 調用間的協作流程。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


  1. 服務提供者啟動,首先解析應用定義的“普通服務”并依次注冊為 RPC 服務,緊接著注冊內建的 MetadataService 服務,最后打開 TCP 監聽端口;

  2. 啟動完成后,將實例信息注冊到注冊中心(僅限 ip、port 等實例相關數據),提供者啟動完成;

  3. 服務消費者啟動,首先依據其要“消費的 provider 應用名”到注冊中心查詢地址列表,并完成訂閱(以實現后續地址變更自動通知);

  4. 消費端拿到地址列表后,緊接著對 MetadataService 發起調用,返回結果中包含了所有應用定義的“普通服務”及其相關配置信息;

  5. 至此,消費者可以接收外部流量,并對提供者發起 Dubbo RPC 調用。


在以上流程中,我們只考慮了一切順利的情況,但在更詳細的設計或編碼實現中,我們還需要嚴格約定一些異常場景下的框架行為。比如,如果消費者 MetadataService 調用失敗,則在重試知道成功之前,消費者將不可以接收外部流量。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析

服務自省中的關鍵機制


1. 元數據同步機制


Client 與 Server 間在收到地址推送后的配置同步是服務自省的關鍵環節,目前針對元數據同步有兩種具體的可選方案,分別是:內建 MetadataService;獨立的元數據中心,通過中細化的元數據集群協調數據。


  • 內建 MetadataServiceMetadataService 通過標準的 Dubbo 協議暴露,根據查詢條件,會將內存中符合條件的“普通服務”配置返回給消費者。這一步發生在消費端選址和調用前;

 

  • 元數據中心復用 2.7 版本中引入的元數據中心,provider 實例啟動后,會嘗試將內部的 RPC 服務組織成元數據的格式到元數據中心,而 consumer 則在每次收到注冊中心推送更新后,主動查詢元數據中心。


注意 consumer 端查詢元數據中心的時機,是等到注冊中心的地址更新通知之后。也就是通過注冊中心下發的數據,我們能明確的知道何時某個實例的元數據被更新了,此時才需要去查元數據中心。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


2. RPC 服務 < - > 應用映射關系


回顧上文講到的注冊中心關于“應用 - 實例列表”結構的數據組織形式,這個變動目前對開發者并不是完全透明的,業務開發側會感知到查詢/訂閱地址列表的機制的變化。具體來說,相比以往我們基于 RPC 服務來檢索地址,現在 consumer 需要通過指定 provider 應用名才能實現地址查詢或訂閱。


老的 Consumer 開發與配置示例:


<!-- 框架直接通過 RPC Service 1/2/N 去注冊中心查詢或訂閱地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181"/>
<dubbo:reference interface="RPC Service 1" />
<dubbo:reference interface="RPC Service 2" />
<dubbo:reference interface="RPC Service N" />


新的 Consumer 開發與配置示例:


<!-- 框架需要通過額外的 provided-by="provider-app-x" 才能在注冊中心查詢或訂閱到地址列表 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181?registry-type=service"/>
<dubbo:reference interface="RPC Service 1" provided-by="provider-app-x"/>
<dubbo:reference interface="RPC Service 2" provided-by="provider-app-x" />
<dubbo:reference interface="RPC Service N" provided-by="provider-app-y" />


以上指定 provider 應用名的方式是 Spring Cloud 當前的做法,需要 consumer 端的開發者顯示指定其要消費的 provider 應用。


以上問題的根源在于注冊中心不知道任何 RPC 服務相關的信息,因此只能通過應用名來查詢。


為了使整個開發流程對老的 Dubbo 用戶更透明,同時避免指定 provider 對可擴展性帶來的影響(參見下方說明),我們設計了一套 RPC 服務到應用名的映射關系,以嘗試在 consumer 自動完成 RPC 服務到 provider 應用名的轉換。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析


Dubbo 之所以選擇建立一套“接口-應用”的映射關系,主要是考慮到 service - app 映射關系的不確定性。一個典型的場景即是應用/服務拆分,如上面提到的配置 <dubbo:reference interface="RPC Service 2" provided-by="provider-app-x" />,PC Service 2 是定義于 provider-app-x 中的一個服務,未來它隨時可能會被開發者分拆到另外一個新的應用如 provider-app-x-1 中,這個拆分要被所有的 PC Service 2 消費方感知到,并對應用進行修改升級,如改為 <dubbo:reference interface="RPC Service 2" provided-by="provider-app-x-1" />,這樣的升級成本不可否認還是挺高的。


到底是 Dubbo 框架幫助開發者透明的解決這個問題,還是交由開發者自己去解決,當然這只是個策略選擇問題,并且 Dubbo 2.7.5+ 版本目前是都提供了的。其實我個人更傾向于交由業務開發者通過組織上的約束來做,這樣也可進一步降低 Dubbo 框架的復雜度,提升運行態的穩定性。


Dubbo 邁出云原生重要一步 - 應用級服務發現解析

總結與展望


應用級服務發現機制是 Dubbo 面向云原生走出的重要一步,它幫 Dubbo 打通了與其他微服務體系之間在地址發現層面的鴻溝,也成為 Dubbo 適配 Kubernetes Native Service 等基礎設施的基礎。


我們期望 Dubbo 在新模型基礎上,能繼續保留在編程易用性、服務治理能力等方面強大的優勢。但是我們也應該看到應用粒度的模型一方面帶來了新的復雜性,需要我們繼續去優化與增強;另一方面,除了地址存儲與推送之外,應用粒度在幫助 Dubbo 選址層面也有進一步挖掘的潛力。


作者簡介


劉軍,Github 賬號 Chickenlj,Apache Dubbo PMC,項目核心開發,見證了Dubbo從重啟開源到Apache畢業的整個流程。現任職阿里云云原生應用平臺團隊,參與服務框架、微服務相關工作,目前主要在推動 Dubbo 3.0 - Dubbo 云原生。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

秦皇岛市| 香格里拉县| 汾西县| 望都县| 当阳市| 洛南县| 商洛市| 富平县| 邻水| 中方县| 蕉岭县| 阳西县| 汝南县| 连江县| 天台县| 陇川县| 扶余县| 平遥县| 烟台市| 镇安县| 元江| 诸城市| 邯郸市| 余姚市| 林口县| 名山县| 南昌市| 饶平县| 德昌县| 中方县| 连城县| 新干县| 琼中| 喀什市| 肇庆市| 上虞市| 邯郸市| 陕西省| 景德镇市| 吉林省| 蒙自县|