精品国产一级在线观看,国产成人综合久久精品亚洲,免费一级欧美大片在线观看

如何過渡到微服務架構

責任編輯:cres

作者:Parminder Singh Kocher

2019-01-04 10:16:45

來源:企業(yè)網(wǎng)D1Net

原創(chuàng)

當你遇到可擴展性問題或發(fā)現(xiàn)該問題已經(jīng)變得代價高昂,并且你很難以對整體式應用程序進行定期的更新時,那么你是時候轉(zhuǎn)向微服務方法了。

當你遇到可擴展性問題或發(fā)現(xiàn)該問題已經(jīng)變得代價高昂,并且你很難以對整體式應用程序進行定期的更新時,那么你是時候轉(zhuǎn)向微服務方法了。下面來看看怎么做。
 
至此,你知道了微服務的定義和工作原理,現(xiàn)在是時候開始著手解決問題了:即如何實現(xiàn)向微服務過渡。
 
對微服務過渡的需求
 
整體式應用程序十分龐大(就代碼行而言),也十分復雜(就功能相互依賴性、數(shù)據(jù)等方面而論),它為各大地理區(qū)域的數(shù)十萬用戶提供服務,它需要多個開發(fā)人員和IT工程師的參與。整體式應用程序可能類似于圖1所呈現(xiàn)的樣子。
 
有時,即使具備所有這些特性,應用程序一開始也許能正常運行。你可能不會遇到應用程序可擴展性或性能方面的難題。但隨著時間的推移和使用的增加,問題會顯現(xiàn)出來,而不同的應用程序會出現(xiàn)不同的問題。
 
例如,對于云應用程序或網(wǎng)絡應用程序,由于有更多用戶使用你的服務,你可能會遇到擴展性問題,又或者是由于耗時更長的構建時間和回歸測試,云應用程序或網(wǎng)絡應用程序可能會變得十分昂貴,而且你很難發(fā)布常規(guī)的新更新。如圖2所示,整體式應用程序的用戶或開發(fā)人員可能會遇到右側(cè)列出的一個或多個問題。
 
 
 
那時,向微服務遷移就不僅僅是一個時髦的想法了,這聽起來就像是救命稻草。遷移將類似于圖3中所示的應用程序。
 
 
那么,你如何做出這樣的改變呢?有兩種可能的情況:
 
• 創(chuàng)建全新的應用程序。
• 轉(zhuǎn)換或遷移已存在的單一應用程序。
 
后一種情況的可能性更大,但無論你目前處于什么樣的情況,了解這兩種情況的來龍去脈是值得的。
 
使用微服務創(chuàng)建新的應用程序
 
我還沒有發(fā)現(xiàn)多少從頭開始構建基于微服務的應用程序的真實場景。通常情況是,應用程序已經(jīng)到位,我所研究的大多數(shù)應用程序中,從整體式架構過度到微服務架構的情況更常見。在這些例子中,架構師和開發(fā)人員的意圖一直是重用一些現(xiàn)有的實施方案。但由于各種技能在市場上唾手可得,一些成功的實現(xiàn)方案已經(jīng)公布,我們將看到更多從頭開始構建基于微服務的應用程序的例子,因此探索這種情況當然是值得的。
 
假設你已經(jīng)了解了所有要求,你已經(jīng)著手設計你要構建的應用程序的架構。在你開始時,有很多常見的最佳實踐可供你考慮,這些實踐將在以下各節(jié)中逐一介紹。
 
組織的就緒情況
 
你必須問自己的第一個問題是,你的組織是否已準備好過渡到微服務。這意味著貴組織的各個部門現(xiàn)在需要以下列方式對構建和發(fā)布軟件進行不同的思考:
 
• 團隊結(jié)構。整體性應用程序團隊(如果有這么一個團隊)必須分解為幾個高績效的團隊,這些團隊已經(jīng)了解微服務的最佳實踐或接受過微服務最佳實踐方面的培訓。如圖3所示,新系統(tǒng)將由一系列獨立服務構成,各個獨立服務負責提供特定的服務。這是微服務范式的一個關鍵優(yōu)勢:它減少了通信方面的開銷,包括多個連續(xù)不斷的會議。團隊試圖解決什么業(yè)務問題或領域,就按什么形式進行組織。于是乎,通信就關系到人們要遵循的時間和一系列標準/協(xié)議,以便這些微服務可以作為一個彼此協(xié)作的平臺。
• 所有的團隊都必須做好準備,獨立于其他團隊運作。團隊必須達到標準的Scrum團隊的規(guī)模;否則,溝通將再次成為問題。執(zhí)行力是關鍵,所有的團隊都必須能夠滿足不斷變化的業(yè)務需求。
• 工具和培訓。組織是否已經(jīng)準備好投資新工具和人員培訓,這是關鍵需求之一。在大多數(shù)情況下,組織必須淘汰現(xiàn)有的工具和流程,轉(zhuǎn)而采用新的工具和流程。這將需要投入大量的資本,花錢雇用具備新技能的人并重新培訓現(xiàn)有的員工。從長遠來看,如果采用微服務的決定是正確的,那么組織將節(jié)約成本并收回投資。
 
基于服務的方法
 
與整體式應用程序不同,對于微服務,你需要采用自足的,基于服務的方法。將你的應用程序設想為一系列松散地結(jié)合在一起的服務,這些服務相互通信以提供完整的應用程序功能。每項服務都必須被視為一項獨立的,完備的服務,其自身的生命周期可由獨立的團隊進行開發(fā)和維護。這些團隊可以從各種技術中進行選擇,包括最適合其服務需求的語言或數(shù)據(jù)庫。
 
例如,對于電子商務站點,團隊會編寫完全獨立的服務,如購物車方面的微服務(具備內(nèi)存數(shù)據(jù)庫),以及另一個服務,如下單方面的微服務(具備關系數(shù)據(jù)庫)。實際的應用程序可以將微服務用于基本功能,例如身份驗證、賬戶、用戶注冊和通知,這些功能的業(yè)務邏輯封裝在API網(wǎng)關中,該API網(wǎng)關基于客戶端和外部請求調(diào)用這些微服務。
 
提醒一下:微服務可能是單個開發(fā)人員所實現(xiàn)的小型服務,或者是由需要幾個開發(fā)人員開發(fā)的復雜服務所實現(xiàn)的小型服務。由于使用了微服務,規(guī)模不再重要;這一切都要看情況,即某個服務必須提供的一個特定的功能。
 
此時人們還必須考慮其它方面,如擴展能力、性能和安全性。擴展能力方面的需求可能各不相同,并且在每個微服務級別按需提供這種需求。所有級別的安全性都必須予以考慮,包括靜態(tài)數(shù)據(jù)、進程間通信、動態(tài)數(shù)據(jù)等。
 
進程間(服務到服務的)通信
 
安全性和通信協(xié)議是必須考慮的關鍵方面。異步通信是最佳選擇,因為它可以使所有請求按計劃進行,并且不會長時間占用資源。
 
使用RabbitMQ之類的消息總線可能有助于這種通信。RabbitMQ很簡單,并且每秒可以達到數(shù)十萬條消息的規(guī)模。為了防止消息傳遞系統(tǒng)在發(fā)生故障時成為單點故障,你必須正確設計消息傳遞總線以實現(xiàn)更高的可用性。除RabbitMQ外還有其它選擇,如ActiveMQ,這是另一個輕量級消息傳遞平臺。
 
安全性是現(xiàn)階段的關鍵。除了選擇正確的通信協(xié)議之外,人們還可以使用AppDynamics等行業(yè)標準的工具來監(jiān)視進程間通信并以此作為衡量標準。所有的異常情況都必須自動向安全團隊發(fā)出報告。
 
當微服務的數(shù)量達到數(shù)千個時,事情的處理就變得很復雜。我會在第三章中解釋如何通過發(fā)現(xiàn)服務(discovery service)和API網(wǎng)關解決此類問題。
 
選擇技術
 
過渡到微服務的最大優(yōu)勢是,它使選擇更加多樣化。每個團隊都可以獨立選擇最適合既定微服務使用的語言、技術、數(shù)據(jù)庫等。在整體式方式中,團隊通常不具備這種靈活性,因此請確保你不會忽視機會,更不要錯過機會。
 
即使一個團隊正在處理多個微服務,每個微服務也必須被視為一個完備的服務,并且要對這些微服務進行分析。在為每個微服務選擇技術時,請必須牢記擴展性、部署、構建時間、集成和插件的可操作性等因素。對于具有較輕巧的數(shù)據(jù)但訪問速度較快的微服務,內(nèi)存數(shù)據(jù)庫也許是最佳選擇,而其它數(shù)據(jù)庫則可能共享相同的關系數(shù)據(jù)庫或NoSQL數(shù)據(jù)庫。
 
實施
 
實施是關鍵階段;這是所有培訓和最佳實踐方面的知識派上用場的地方。你要記住的一些關鍵方面包括:
 
• 獨立性。每個微服務都必須具備高度自主性,有自己的生命周期并以這種方式得到處理。獨立性需要開發(fā)和維護,而不依賴于其它微服務。
• 源代碼控制。安裝適當?shù)陌姹究刂葡到y(tǒng)是必須的,每個微服務必須遵循標準。將存儲庫標準化也很有用,因為這可以確保所有團隊使用相同的源代碼控制機制。這在各方面都有所幫助(例如代碼評估),使人們可以在一個地方輕松地訪問所有的代碼。從長遠來看,用同一個源代碼來控制所有的服務是有意義的。
• 環(huán)境。所有不同的環(huán)境(例如開發(fā)、測試、階段和生產(chǎn))必須得到適當?shù)谋Wo,實現(xiàn)適當?shù)淖詣踊_@里的自動化包括構建過程;這樣代碼就可以根據(jù)需要進行集成,每天都要進行集成。雖然Jenkins得到了廣泛的使用,但還有幾種工具可供人們使用。Jenkins是一個開源工具,這個工具有助于將軟件構建自動化,有助于發(fā)布過程,包括持續(xù)集成和持續(xù)交付(CI / CD)。
• 自動防止故障。一切都有可能出錯,而軟件故障是不可避免的。必須在微服務開發(fā)中解決下游服務的故障處理問題。即使其它的服務失敗了,也必須失敗得優(yōu)雅些,以至于用戶不能看到失敗。這包括管理服務響應時間(超時),處理下游服務的API更改并限制自動重試的次數(shù)。
 
使用微服務時,不要害怕用復制粘貼的辦法來重用代碼,但要有限度。這可能會導致一些代碼重復,但總比使用共享的代碼要好,共享的代碼最終可能會產(chǎn)生耦合的服務(coupling service)。在微服務中,你需要去耦合,而不需要緊耦合(tight coupling)。例如,你將編寫代碼,以使用服務的輸出響應。每次從任意一個客戶端調(diào)用相同的服務時,你都可以復制此代碼。重用代碼的另一種方法是創(chuàng)建公共庫。多個客戶端可以使用相同的庫,但每個客戶端必須負責庫的維護。
 
當你創(chuàng)建太多庫,并且每個客戶端要維護不同版本的庫時,這有時極具挑戰(zhàn)性。在這種情況下,你可能必須包含同一個庫的多個不同版本,并且由于向后兼容性問題和類似的問題,構建過程可能會變得十分困難。根據(jù)你的需要,只要你可以通過客戶端控制庫的數(shù)量和版本的數(shù)量,并對其實施嚴格的流程,你就可以采用任何一種方式。這肯定會讓你避免大量的代碼重復。
 
鑒于微服務的龐大數(shù)量,對問題進行調(diào)試可能會變得十分困難,因此你需要在此階段進行某種檢測。其中一個最佳實踐就是,使用唯一的請求ID標記每個請求并記錄每個請求。此唯一ID能發(fā)現(xiàn)原始請求,并且應由各個服務將其傳遞給所有的下游請求。
 
當你看到問題時,你可以清楚地追溯日志并發(fā)現(xiàn)有問題的服務。如果你建立了一個集中化的日志記錄系統(tǒng),此解決方案將最有效。所有服務都應用標準格式將所有消息記錄到此共享系統(tǒng),以便團隊可以根據(jù)需要從一個地方(從基礎設施到應用程序)重現(xiàn)事件。用于集中式日志記錄的共享庫是值得研究的。市場上有幾種日志管理和聚合工具(例如ELK(Elasticsearch,Logstash,Kibana)和Splunk),它們都十分理想。
 
部署
 
自動化是部署過程中的關鍵。如果沒有自動化,微服務范式幾乎是不可能成功的。微服務也許有成百上千個,但對敏捷交付來說,自動化是必須的。
 
試想一下部署數(shù)千個微服務并對其進行維護的情景。當其中一個微服務發(fā)生故障時會怎樣?你怎么知道哪臺機器有足夠的資源來運行你的微服務?在自動化沒有到位的情況下管理這種故障變得非常復雜。而Kubernetes和Docker Swarm等各種工具則可以將部署過程自動化。
 
運營
 
該過程的操作部分也必須自動化。再說一次,我談論的是數(shù)百上千個微服務——因此組織的能力必須十分成熟,成熟到能夠處理這種級別的復雜度。你需要一個支持系統(tǒng),包括以下東西:
 
• 從基礎設施、應用程序API乃至最終的性能,一切都必須受到監(jiān)控,一切都必須實施能在適當閾值下觸發(fā)的自動警報。不妨創(chuàng)建一個實時的儀表盤,在問題出現(xiàn)期間,儀表盤會顯示數(shù)據(jù)并發(fā)出警報。
• 按需的擴展性。有了微服務,擴展性就成了最簡單的任務。提供你想要擴展的微服務的另一個實例,并將其放在現(xiàn)有的負載均衡器之后;一切就設置好了。但在規(guī)模化的環(huán)境中,這也需要自動化。這關系到設置一個整數(shù)值來分辨你要為特定微服務運行的實例數(shù)。
• API的曝光度。在大多數(shù)情況下,你希望在外部公開API,以供外部用戶使用。最好用邊緣服務器來完成,因為它可以處理所有外部請求。邊緣服務器可以使用API網(wǎng)關和發(fā)現(xiàn)服務來完成工作,你可以為每種設備類型(例如移動設備或瀏覽器)或用例使用一個邊緣服務器。網(wǎng)飛創(chuàng)建了一個名為Zuul的開源應用程序,該程序可用于此功能及其它功能。
• 斷路器(Circuit breaker)。向失敗的服務發(fā)送請求毫無意義。因此,你可以構建一個斷路器,這個斷路器可以追蹤向每個服務發(fā)出的每一個請求是否成功。在多個故障發(fā)生的情況下,在一段時間內(nèi),你應該阻止對該特定服務發(fā)出的所有請求(“斷開電路”)。在設定的時間到期后應該發(fā)出下一個請求,依此類推。一旦響應成功就重新連接電路。這必須在服務實例的級別上完成。網(wǎng)飛的Hystrix提供了一個實施開源斷路器的方案。
 
將整體式應用程序遷移到微服務
 
雖然構建基于微服務的新應用程序的大多數(shù)最佳實踐也適用于從現(xiàn)有的整體式應用程序進行遷移,還有一些額外的準則(但是如果遵循這些準則)可以使遷移變得更簡單,更高效。
 
雖然將整個整體式應用程序轉(zhuǎn)換為完全基于微服務的應用程序的做法看似正確,但在某些情況下,將每個功能轉(zhuǎn)換為微服務,這可能并不高效,或成本可能非常高。畢竟,你最終可能會從頭開始編寫應用程序。正確的遷移方法可能是漸進式方法,如圖4所示。
 
 
接下來的問題是:從哪里開始使用當前的整體式應用程序?如果應用程序真的很舊,很耗時且難以拆分(也就是說,如果內(nèi)聚性的程度很高的話),那么從頭開始可能會更好。在其他情況下,即可以快速禁用部分代碼并且技術架構沒有完全過時,那么你最好先將組件重建為微服務并替換舊代碼。
 
微服務標準
 
于是乎,問題就變成了應該先遷移什么組件,甚至變成了遷移組件是否有必要。這讓我想到了我所謂的“微服務標準”,微服務標準概述了多種可能方法中的一種方法,即選擇應該遷移到微服務的功能并確定其優(yōu)先級。微服務標準就是你建立的一系列規(guī)則,這些規(guī)則可以根據(jù)組織此刻的需要將現(xiàn)有的整體式應用程序組件轉(zhuǎn)換為微服務,要么可以轉(zhuǎn)換,要么不能。
 
這里所說的“時間”非常重要,因為隨著時間的推移,組織的需求可能會發(fā)生變化,你可能不得不回過頭來,在晚些時候?qū)⒏嘟M件轉(zhuǎn)換為微服務。換句話說,隨著需求的變化,整體式應用程序的其它組件可能會具備轉(zhuǎn)化為微服務的資格。
 
以下是在轉(zhuǎn)換過程中可被視為微服務標準的最佳做法:
 
• 你需要確定哪些功能用得多。首先將頻頻使用的服務或應用程序功能轉(zhuǎn)換為微服務。請記住:微服務只執(zhí)行一個有明確定義的服務。牢記這一原則并相應地對應用程序進行劃分。
• 你很可能會碰到性能不佳的組件,但你還有其它的組件可選擇。你也許有開源的插件可用,或者你可能想從頭開始構建服務。請記住,微服務的邊界是很關鍵的東西。只要你設計微服務的目的是讓它單單把一件事做好,那就沒問題。確定服務的邊界往往很難,你會發(fā)現(xiàn),只要多實踐,邊界就更容易確定了。考察微服務邊界的另一種方法是,你必須在幾周內(nèi)(如果必須這么做的話)重寫整個微服務,而不是花費幾個月的時間來重寫服務。
• 更好的技術替代方案或多語言編程。領域特定語言(Domain-specific language)可用于解決問題域(problem domain)方面的問題。這尤其適用于各種組件,即你過去收到大量增強請求的組件,而你希望這些能夠繼續(xù)收到這樣的請求。使用市面上的新語言或功能不僅可以將此類組件的實施工作簡化,而且還可以使未來的維護和更新變得更加容易,如果你是這么認為的,那么現(xiàn)在正是解決此類更改的正確時機。在其他情況下,你可能會發(fā)現(xiàn),另一種語言提供的并發(fā)抽象比當前使用的抽象更容易。你可以將新語言用于已知的微服務,而應用程序的其余部分仍然可以使用不同的語言。同樣,你可能希望某些微服務的速度變得非常快,你還有可能決定用C語言編寫這些微服務,以獲得最大的收益,而不是用另一種高級語言編寫。利用這種靈活性才是最重要的。
• 存儲方面的替代方案或多混合持久化(polyglot persistence)。隨著大數(shù)據(jù)的興起,應用程序的某些組件可能會通過NoSQL數(shù)據(jù)庫而不是關系數(shù)據(jù)庫來實現(xiàn)價值。如果應用程序中任何一個諸如此類的組件可能從此替代方案中受益,那么這可能是轉(zhuǎn)向NoSQL的合適時機。
 
這就是你必須考慮的關鍵方面,即你必須考慮整體式應用程序中的每個服務或功能,你首先要優(yōu)先處理這些項目的轉(zhuǎn)化工作。一旦你從高優(yōu)先級項目得出數(shù)值,你就可以應用其它規(guī)則。
 
• 修改方面的請求。在所有軟件的生命周期中追蹤新的改善請求或更改,這是一件很重要的事情。由于受到構建時間和部署時間的限制,需要頻頻修改功能很適合微服務。將這些服務分離就可以減少構建時間和部署時間,因為你不必構建整個應用程序,只需更改微服務,這也可能會增加應用程序其余部分的可用時間。
• 應用程序的某些部分總是會增加部署的復雜性。在整體式應用程序中,即使特定功能未受影響,你仍然必須完成整個構建和部署過程。如果存在這樣的情況,去除應用程序的這些部分并用微服務取而代之,這大有裨益,這樣你就可以減少整個應用程序其余部分的總體部署時間。在我們了解容器后,我們會詳細討論這種做法。
• 輔助服務(Helper service)。在大多數(shù)應用程序中,核心服務或主服務依賴于某些幫助程序服務。這些輔助功能的可用性可能會影響核心服務的可用性。例如,在服務臺應用程序中,工單服務取決于產(chǎn)品目錄服務。如果產(chǎn)品目錄服務不可用,則用戶無法提交要求解決問題的工單。如果存在這種情況,你必須將輔助服務轉(zhuǎn)換為微服務并以合適的方式使其具有高度的可用性,以便輔助服務可以更好地為核心服務提供服務。(這些服務也稱為斷路服務(circuit-breaker service)。)
 
根據(jù)應用程序的不同,這些標準可能需要將大多數(shù)服務轉(zhuǎn)換為微服務,不過這也沒關系。這里的目的是簡化轉(zhuǎn)換過程,以便你可以確定路線圖的優(yōu)先事項并對其進行定義,即遷移到基于微服務的架構的路線圖。
 
為服務重建架構
 
一旦你確定了要作為微服務遷移的功能,你就可以按照早期方案中的最佳實踐開始重新架構所選的服務。以下是需要注意的方面:
 
• 微服務定義。為每個功能定義合適的微服務,這些微服務應包括通信機制(API)、技術定義等。試想一下你的現(xiàn)有功能所使用的數(shù)據(jù),或相應地創(chuàng)建和規(guī)劃微服務的數(shù)據(jù)策略。如果該函數(shù)在甲骨文這樣體量較大的數(shù)據(jù)庫上,那么移植到MySQL是否有意義?你要確定如何管理數(shù)據(jù)關系。最后,將每個微服務用作單獨的應用程序。
• 重構代碼。如果你不換用編程語言,你就可以重用某些代碼。以存儲/數(shù)據(jù)庫層為例——共享與專用,在內(nèi)存中與在外部。我們的目標不是添加新功能(除非真的有必要),而是重新打包現(xiàn)有代碼并公開所需的API。
• 在開始編碼之前,請確定源代碼控制機制和版本控制機制,并確保這些標準得到了遵循。每個微服務都是一個單獨的項目,并作為單獨的應用程序部署。
• 數(shù)據(jù)遷移。如果你決定創(chuàng)建新的數(shù)據(jù)庫,那么你還必須遷移舊數(shù)據(jù)。這通常是通過編寫簡單的SQL腳本來處理,具體取決于你的源和目標。
• 整體式代碼。為了防止不得不回滾的問題,你一開始就得將現(xiàn)有代碼留在整體式應用程序中。你要么更新其余的代碼以使用新的微服務,要么分割應用程序流量(如果可能的話),從而使用整體式版本和微服務版本,第二種情況更好。這樣你就有機會測試性能并關注性能。一旦有把握,你就可以將所有流量移動到微服務并禁用舊代碼或?qū)⑵鋭h除。
• 獨立的構建、部署和管理。獨立地構建和部署每個微服務。在推出新版本的微服務時,你可以在一段時間內(nèi)劃分舊版本和新版本之間的流量。這意味著你可能在生產(chǎn)環(huán)境中運行同一個微服務的兩個版本或更多版本。某些用戶流量可以被轉(zhuǎn)至新的微服務版本,以確保服務正常運行。如果新版本沒有以最佳方式工作,或沒有按預期執(zhí)行,那么將所有的流量回滾到先前的版本并繼續(xù)對新版本進行開發(fā)則變得很容易。這里的關鍵是,建立可重復的自動部署流程并轉(zhuǎn)向持續(xù)交付。
•舊代碼刪除。如果你還沒有確認一切都得到了妥善的遷移并按預期運作,那你就不能刪除臨時代碼并從舊存儲位置刪除數(shù)據(jù)。請務必在此過程中進行備份。
 
微服務的混合方法
 
在編寫全新的應用程序時,開發(fā)人員可以直接遵循微服務架構的原則和藍圖來構建軟件應用程序。
 
開發(fā)人員有時會遵循一種將微服務和整體性應用程序混合起來的方法。在這種情況下,他們可以將部分應用程序開發(fā)為微服務,其余部分則遵循基于特定標準的標準SOA/MVC實踐(譯注:SOA即面向服務的架構,MVC即模型-視圖-控制器模式)。這個想法就是,并非應用所有的應用程序組件都可以用作微服務。
 
微服務提供了很大的靈活性,但這種靈活性部署是沒有代價的。混合方法就是在靈活性和成本之間取得平衡,條件是,組件最終可以從整體性部件中提取出來并根據(jù)需要轉(zhuǎn)換為微服務。關鍵是在此過渡期間牢記這兩種方法和微服務標準。

鏈接已復制,快去分享吧

企業(yè)網(wǎng)版權所有?2010-2024 京ICP備09108050號-6京公網(wǎng)安備 11010502049343號

  • <menuitem id="jw4sk"></menuitem>

    1. <form id="jw4sk"><tbody id="jw4sk"><dfn id="jw4sk"></dfn></tbody></form>
      主站蜘蛛池模板: 象山县| 石泉县| 霸州市| 石阡县| 大名县| 措美县| 通城县| 洛浦县| 抚顺县| 茶陵县| 仁怀市| 日喀则市| 缙云县| 东丰县| 武穴市| 睢宁县| 富平县| 河南省| 巴林右旗| 新宾| 顺昌县| 琼结县| 枞阳县| 彭山县| 镇安县| 吉木乃县| 饶河县| 上饶县| 临颍县| 修水县| 余姚市| 镇赉县| 汕头市| 福清市| 通河县| 太白县| 原平市| 获嘉县| 安宁市| 靖州| 金平|