版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、hbase存儲架構(gòu)英文原文:hbase最隱秘的問題之一就是它的數(shù)據(jù)是如何存儲的。雖然大多數(shù)用戶都不會因為這個問題向你抱怨,但是如果你想學(xué)習(xí)哪些高級的配置選項并了解它們的意思,你可能就需要來了解一下這個存儲問題了?!霸鯓硬拍馨裩base調(diào)整到最適合我需求的狀態(tài)?”你可能對于這樣一系列類似的問題非常感興趣。那么你就需要繞過這些問題來學(xué)習(xí)hbase的基礎(chǔ)知識。另一個支持你學(xué)習(xí)這些基礎(chǔ)知識的理由是有時候各種各樣你想不到的災(zāi)難需要你恢復(fù)整個hbase。我首先學(xué)習(xí)了hbase中控制各種不同文件的獨立的類,然后根據(jù)我對整個hbase存儲系統(tǒng)的理解在腦海中構(gòu)建hbase架構(gòu)的圖像。但是我發(fā)現(xiàn)想要在頭腦中構(gòu)建出
2、一幅連貫的hbase架構(gòu)圖片很困難,于是我就把它畫了出來。你可能注意到了這不是一個uml圖或者調(diào)用圖。這個圖混合了類和他們管理控制的文件,將注意力集中到了本文要討論的主題上。后面我將會討論這張圖所涉及到的細(xì)節(jié),包括一些配置文件項是如何影響底層的文件存儲系統(tǒng)的。好,我們現(xiàn)在來分析這張圖里面到底包含了什么。首先hbase操控兩種基本類型的文件,一種用于存儲wal的log,另一種用于存儲具體的數(shù)據(jù)。這兩種文件主要由hregionserver來管理,但是在有的情況下hmaster會跳過hregionserver,直接操作這兩種文件。你可能注意到了,這些文件都被存儲在hdfs上面,并且每個文件包含了多個
3、數(shù)據(jù)塊。配置文件中就有一個選項用來調(diào)整系統(tǒng)控制數(shù)據(jù)的大小。我們后面會詳細(xì)討論這個問題。接下來看一下數(shù)據(jù)的大致流程。假設(shè)你需要通過某個特定的rowkey查詢一行記錄,首先client端會連接zookeeper qurom,通過zookeeper,client能獲知哪個server管理-root- region。接著client訪問管理-root-的server,進而獲知哪個server管理.meta.表。這兩個信息client只會獲取一次并緩存起來。在后續(xù)的操作中client會直接訪問管理.meta.表的server,并獲取region分布的信息。一旦client獲取了這一行的位置信息,比如這一
4、行屬于哪個region,client將會緩存這個信息并直接訪問hregionserver。久而久之client緩存的信息漸漸增多,即使不訪問.meta.表也能知道去訪問哪個hregionserver。注意:當(dāng)hbase啟動的時候hmaster負(fù)責(zé)分配region給hregionserver,這其中當(dāng)然也包括-root-表和.meta.表的region。接下來hregionserver打開這個region并創(chuàng)建一個hregion對象。當(dāng)hregion打開以后,它給每個table的每個hcolumnfamily創(chuàng)建一個store實例。每個store實例擁有一個或者多個storefile實例。sto
5、refile對hfile做了輕量級的包裝。除了store實例以外,每個hregion還擁有一個memstore實例和一個hlog實例?,F(xiàn)在我們就可以看看這些實例是如何在一起工作的,遵循什么樣的規(guī)則以及這些規(guī)則的例外。保留住put現(xiàn)在看一下數(shù)據(jù)是怎樣被寫到實際的存儲中去的。client發(fā)起了一個htable.put(put)請求給hregionserver,hregionserver會將請求匹配到某個具體的hregion上面。緊接著的操作時決定是否寫wal log。是否寫wal log由client傳遞的一個標(biāo)志決定,你可以設(shè)置這個標(biāo)志:put.writetowal(boolean)。wal l
6、og文件是一個標(biāo)準(zhǔn)的hadoop sequencefile(現(xiàn)在還在討論是否應(yīng)該把文件格式改成一個更適合hbase的格式)。在文件中存儲了hlogkey,這些keys包含了和實際數(shù)據(jù)對應(yīng)的序列號,用途是當(dāng)regionserver崩潰以后能將wal log中的數(shù)據(jù)同步到永久存儲中去。做完這一步以后,put數(shù)據(jù)會被保存到memstore中,同時會檢查memstore是否已經(jīng)滿了,如果已經(jīng)滿了,則會觸發(fā)一個flush to disk的請求。hregionserver有一個獨立的線程來處理flush to disk的請求,它負(fù)責(zé)將數(shù)據(jù)寫成hfile文件并存到hdfs上。它也會存儲最后寫入的數(shù)據(jù)序列號,
7、這樣就可以知道哪些數(shù)據(jù)已經(jīng)存入了永久存儲的hdfs中?,F(xiàn)在讓我們來看看這些存儲文件。存儲文件hbase在hdfs上面的所有文件有一個可配置的根目錄,默認(rèn)根目錄是/hbase。通過使用hadoop的dfs工具就可以看到這些文件夾的結(jié)構(gòu)。在根目錄下面你可以看到一個.logs文件夾,這里面存了所有由hlog管理的wal log文件。在.logs目錄下的每個文件夾對應(yīng)一個hregionserver,每個hregionserver下面的每個log文件對應(yīng)一個region。有時候你會發(fā)現(xiàn)一些oldlogfile.log文件(在大多數(shù)情況下你可能看不到這個文件),這個文件在一種異常情況下會被產(chǎn)生。這個異常情
8、況就是hmaster對log文件的訪問情況產(chǎn)生了懷疑,它會產(chǎn)生一種稱作“l(fā)og splits”的結(jié)果。有時候hmaster會發(fā)現(xiàn)某個log文件沒人管了,就是說任何一個hregionserver都不會管理這個log文件(有可能是原來管理這個文件的hregionserver掛了),hmaster會負(fù)責(zé)分割這個log文件(按照它們歸屬的region),并把那些hlogkey寫到一個叫做oldlogfile.log的文件中,并按照它們歸屬的region直接將文件放到各自的region文件夾下面。各個hregion會從這個文件中讀取數(shù)據(jù)并將它們寫入到memstore中去,并開始將數(shù)據(jù)flush to d
9、isk。然后就可以把這個oldlogfile.log文件刪除了。注意:有時候你可能會發(fā)現(xiàn)另一個叫做oldlogfile.log.old的文件,這是由于hmaster做了重復(fù)分割log文件的操作并發(fā)現(xiàn)oldlogfile.log已經(jīng)存在了。這時候就需要和hregionserver以及hmaster協(xié)商到底發(fā)生了什么,以及是否可以把old的文件刪掉了。從我目前遇到的情況來看,old文件都是空的并且可以被安全刪除的。hbase的每個table在根目錄下面用一個文件夾來存儲,文件夾的名字就是table的名字。在table文件夾下面每個region也用一個文件夾來存儲,但是文件夾的名字并不是region
10、的名字,而是region的名字通過jenkins hash計算所得到的字符串。這樣做的原因是region的名字里面可能包含了不能在hdfs里面作為路徑名的字符。在每個region文件夾下面每個columnfamily也有自己的文件夾,在每個columnfamily文件夾下面就是一個個hfile文件了。所以整個文件夾結(jié)構(gòu)看起來應(yīng)該是這個樣子的:/hbase/在每個region文件夾下面你會發(fā)現(xiàn)一個.regioninfo文件,這個文件用來存儲這個region的meta data。通過這些meta data我們可以重建被破壞的.meta.表,關(guān)于.regioninfo的應(yīng)用你可以參考hbase-7和
11、hbase-1867。有一件事情前面一直沒有提到,那就是region的分割。當(dāng)一個region的數(shù)據(jù)文件不斷增長并超過一個最大值的時候(你可以配置這個最大值 hbase.hregion.max.filesize),這個region會被切分成兩個。這個過程完成的非常快,因為原始的數(shù)據(jù)文件并不會被改變,系統(tǒng)只是簡單的創(chuàng)建兩個reference文件指向原始的數(shù)據(jù)文件。每個reference文件管理原始文件一半的數(shù)據(jù)。reference文件名字是一個id,它使用被參考的region的名字的hash作為前綴。例如:1278437856009925445.3323223323。reference文件只含有
12、非常少量的信息,這些信息包括被分割的原始region的key以及這個文件管理前半段還是后半段。hbase使用halfhfilereader類來訪問reference文件并從原始數(shù)據(jù)文件中讀取數(shù)據(jù)。前面的架構(gòu)圖只并沒有畫出這個類,因為它只是臨時使用的。只有當(dāng)系統(tǒng)做compaction的時候原始數(shù)據(jù)文件才會被分割成兩個獨立的文件并放到相應(yīng)的region目錄下面,同時原始數(shù)據(jù)文件和那些reference文件也會被清除。前面dump出來的文件結(jié)構(gòu)也證實了這個過程,在每個table的目錄下面你可以看到一個叫做compaction.dir的目錄。這個文件夾是一個數(shù)據(jù)交換區(qū),用于存放split和compac
13、t region過程中生成的臨時數(shù)據(jù)。hfile現(xiàn)在我們將深入hbase存儲架構(gòu)的核心,探討hbase具體的數(shù)據(jù)存儲文件的結(jié)構(gòu)。storefile以hfile格式保存在hdfs上。hfile就是這個數(shù)據(jù)存儲文件的結(jié)構(gòu)(ryan rawson就是靠它揚名立萬的)。創(chuàng)建hfile這樣一個文件結(jié)構(gòu)的目的只有一個:快速高效的存儲hbase的數(shù)據(jù)。hfile是基于hadoop tfile的(參見 hadoop-3315)。hfile模仿了google bigtable中sstable的格式。原先hbase使用hadoop的mapfile,但是這種文件已經(jīng)被證明了效率差?,F(xiàn)在讓我們來看看這個文件結(jié)構(gòu)到底是
14、什么樣的。首先這個文件是不定長的,長度固定的只有其中的兩塊:trailer和fileinfo。正如圖中所示的,trailer中有指針指向其他數(shù)據(jù)塊的起始點。index數(shù)據(jù)塊記錄了每個data塊和meta塊的起始點。data塊和meta塊都是可有可無的,但是對于大部分的hfile,你都可以看到data塊。那么每個塊的大小是如何確定的呢?這個值可以在創(chuàng)建一個table的時候通過hcolumndescriptor(實際上應(yīng)該稱作familydescriptor)來設(shè)定。這里我們可以看一個例子:name = docs, families = name = cache, compression = no
15、ne, versions = 3, ttl = 2147483647, blocksize = 65536, in_memory = false, blockcache = false, name = contents, compression = none, versions = 3, ttl = 2147483647, blocksize = 65536, in_memory = false, blockcache = false, 從這里可以看出這是一個叫做docs的table,它有兩個family:cache和contents,這兩個family對應(yīng)的hfile的數(shù)據(jù)塊的大小都是64k
16、。關(guān)于如何設(shè)定數(shù)據(jù)塊的大小,我們應(yīng)用一段hfile源碼中的注釋:我們推薦將數(shù)據(jù)塊的大小設(shè)置為8kb至1mb。大的數(shù)據(jù)塊比較適合順序的查詢(比如scan),但不適合隨機查詢,想想看,每一次隨機查詢可能都需要你去解壓縮一個大的數(shù)據(jù)塊。小的數(shù)據(jù)塊適合隨機的查詢,但是需要更多的內(nèi)存來保存數(shù)據(jù)塊的索引(data index),而且創(chuàng)建文件的時候也可能比較慢,因為在每個數(shù)據(jù)塊的結(jié)尾我們都要把壓縮的數(shù)據(jù)流flush到文件中去(引起更多的flush操作)。并且由于壓縮器內(nèi)部還需要一定的緩存,最小的數(shù)據(jù)塊大小應(yīng)該在20kb 30kb左右??赡軓那懊娴拿枋瞿銜l(fā)現(xiàn)數(shù)據(jù)塊(data block)是數(shù)據(jù)壓縮的一個單位
17、。后面我們會深入data block內(nèi)部去了解它的詳細(xì)構(gòu)造。在hbase的配置文件中你會看到一個參數(shù):hfile.min.blocksize.size,這個參數(shù)看上去只會用在數(shù)據(jù)遷移或者通過工具直接創(chuàng)建hfile的過程中。(貌似hbase創(chuàng)建hfile不會使用這個參數(shù),hbase使用的是.meta.表中記錄的那個值)。呼,到現(xiàn)在為止解釋的還不錯吧。好了,讓我們繼續(xù)。有時候我們可能會想知道一個hfile是否正常以及它里面包含了什么內(nèi)容。沒問題,已經(jīng)有一個應(yīng)用程序來做這件事了。hfile.main()本身就提供了一個用來dump hfile的工具。這里有一個dump文件的例子:第一部分是存儲具體數(shù)
18、據(jù)的keyvalue對,每個數(shù)據(jù)塊除了開頭的magic以外就是一個個keyvalue對拼接而成。后面會詳細(xì)介紹每個keyvalue對的內(nèi)部構(gòu)造。第二部分是tailer塊的具體內(nèi)容,最后一部分是fileinfo塊的具體內(nèi)容。dump hfile還有一個作用就是檢查hfile是否正常。keyvalue對hfile里面的每個keyvalue對就是一個簡單的byte數(shù)組。但是這個byte數(shù)組里面包含了很多項,并且有固定的結(jié)構(gòu)。我們來看看里面的具體結(jié)構(gòu):開始是兩個固定長度的數(shù)值,分別表示key的長度和value的長度。緊接著是key,開始是固定長度的數(shù)值,rowlength表示row的長度,緊接著是ro
19、w,然后是固定長度的數(shù)值,表示family的長度,然后是family,接著是qualifier,然后是兩個固定長度的數(shù)值,表示time stamp和key type。value部分沒有這么復(fù)雜的結(jié)構(gòu),就是純粹的數(shù)據(jù)。.apache.hadoop.hbase.keyvalue是用來處理這個keyvalue,你可能會發(fā)現(xiàn)在這個類里面有兩個方法:getkey和getrow。getkey當(dāng)然是用來獲取key的內(nèi)容,那么getrow是什么?其實是用來獲取rowkey的。rowkey不是hbase的基本元素嗎?是的,這個類已經(jīng)不是純粹的key&value處理,它已經(jīng)打上了hbase的烙印。
20、好了,這篇文章就到此為止了,它對hbase的存儲架構(gòu)做了一個大致的介紹。希望這篇文章對于那些想更深入的挖掘hbase細(xì)節(jié)的人來說,能作為一個起點。hbase 數(shù)據(jù)文件在hdfs上的存儲posted on july 24, 2010 by harry_ding hbase 數(shù)據(jù)文件在hdfs上的存儲英文原文:在hdfs上面最不明確的事情之一就是數(shù)據(jù)的冗余。它完全是自動進行的,因為無法得知其中詳細(xì)的信息,我們需要做的就是相信它。hbase完全相信hdfs存儲數(shù)據(jù)的安全性和完整性,并將數(shù)據(jù)文件交給hdfs存儲。正是因為hdfs的數(shù)據(jù)冗余方式對于hbase來說是完全透明的,產(chǎn)生了一個問題:hbase的
21、效率會受到多大的影響?說的簡單一點,當(dāng)hbase需要存取數(shù)據(jù)時,如何保證有一份冗余的數(shù)據(jù)塊離自己最近?當(dāng)我們對hbase做一次mapreduce的掃描操作時,這個問題尤其顯現(xiàn)出來。所有的regionserver都在從hdfs上面讀取數(shù)據(jù),理想的狀況當(dāng)然是每個regionserver要讀取的數(shù)據(jù)都離自己很近。這個問題就牽扯到hbase的數(shù)據(jù)文件是如何在hdfs上面存儲的。讓我們首先拋開hbase,假設(shè)要處理的數(shù)據(jù)就是hdfs上面的數(shù)據(jù)塊,看看hadoop是如何工作的。mapreduce總是有一個建議,那就是在每個tasktracker上面map/reduce程序要處理的數(shù)據(jù)在本地就有一份冗余。這
22、樣程序只需要與本地數(shù)據(jù)交互,減少了網(wǎng)絡(luò)流量并提高了效率。為了做到這一點,hdfs會把大文件分割成很多小文件來存儲,我們稱之為數(shù)據(jù)塊(block)。每個數(shù)據(jù)塊的大小比操作系統(tǒng)數(shù)據(jù)塊的大小要大得多,默認(rèn)是64m,但通常我們選擇128m,或者某個更大的值(這取決與你的文件大小,最好你的單個文件大小總是大于一個數(shù)據(jù)塊)。在mapreduce中,每個數(shù)據(jù)塊會被分配給一個task,這個task就負(fù)責(zé)處理這個數(shù)據(jù)塊中的數(shù)據(jù)。所以數(shù)據(jù)塊越大,產(chǎn)生的task就越少,需要mapper的數(shù)量就越少。hadoop自己知道每個數(shù)據(jù)塊存儲的位置,這樣在任務(wù)分配的時候就可以直接在存儲數(shù)據(jù)塊的機器上啟動task,或者選擇一個
23、最近機器啟動task。真是因為每個數(shù)據(jù)塊有多份冗余,使得hadoop有更大的選擇空間。只要找到一份冗余符合條件就行了,不是嗎?這樣hadoop就可以保證在mapreduce期間task總是操作本地數(shù)據(jù)。讓我們回到hbase,現(xiàn)在你已經(jīng)理解了hadoop是如何保證在mapreduce的過程中每個task都盡量處理本地數(shù)據(jù)。如果你看過hbase的存儲架構(gòu)你就會知道hbase只是簡單的將hfile和wal log存儲在hdfs上面。通過簡單的調(diào)用hdfs的api來創(chuàng)建文件:filesystem.create(path path)。接下來你會關(guān)心兩件事情的效率:1)隨機的訪問 2)通過mapreduc
24、e掃描全表。我們當(dāng)然希望當(dāng)每個regionserver讀取數(shù)據(jù)時存儲數(shù)據(jù)的數(shù)據(jù)塊就在本地。它能做到嗎?第一種情況,你有兩個集群,一個集群裝hadoop,另一個集群裝hbase,兩個集群是分隔開的,只有網(wǎng)線來傳輸數(shù)據(jù)。好了,討論到此為止,神也幫不了你。第二種情況,你有一個大的集群,每臺機器都混裝了hadoop和hbase,每個regionserver上面都有一個datanode(這是我們最希望看到的)。好,這樣的話regionserver就具備了從本地讀取數(shù)據(jù)的前提。我們還剩下一個問題,如何保證每個regionserver管理的region所對應(yīng)的hfile和wal log就存在本地的datan
25、ode上面?設(shè)想一種情況,你對hbase創(chuàng)建了大量的數(shù)據(jù),每個regionserver都管理了各自的region,這時你重啟了hbase,重啟了所有的regionserver,所有的region都會被隨機的分配給各個regionserver,這種情況下你顯然無法保證我們希望的本地數(shù)據(jù)存儲。在討論如何解決這個問題之前我們先強調(diào)一點:hbase不應(yīng)該頻繁的被重啟,并且部署的架構(gòu)不應(yīng)該被頻繁的改變,這是能解決這個問題的一個基礎(chǔ)。寫入hdfs的文件都有一個特點,一旦寫入一個文件就無法更改(由于種種原因)。因此hbase會定期的將數(shù)據(jù)寫入hdfs中并生成一個新文件。這里有一個讓人驚奇的地方:hdfs足夠
26、聰明,它知道如何將文件寫到最合適的地方。換句話說,它知道把文件放到什么地方使得regionserver用起來最方便。如果想知道hdfs如何做到這一點,我們需要深入學(xué)習(xí)hadoop的源代碼,看看前面提到的filesystem.create(path path) 具體是怎么工作的。在hdfs中實際調(diào)用的函數(shù)是:distributedfilesystem.create(path path), 他看起來是這個樣子的:public fsdataoutputstream create(path f) throws ioexception return create(f, true);public fsda
27、taoutputstream create(path f, fspermission permission, boolean overwrite, int buffersize, short replication, long blocksize, progressable progress) throws ioexception return new fsdataoutputstream(dfs.create(getpathname(f), permission, overwrite, replication, blocksize, progress, buffersize), statis
28、tics);其中dfs是一個連接到hdfs namenode的dfsclient。當(dāng)你向hdfs寫入數(shù)據(jù)的時候,數(shù)據(jù)都流過dfsclient.dfsoutputstream,dfsclient將這些數(shù)據(jù)收集,積攢到一定程度后,作為一個block寫入到datanode里面。將一個block寫到datanode的過程都發(fā)生在dfsclient.dfsoutputstream.datastreamer里面,它是一個運行在后臺的守護線程。注意,從現(xiàn)在開始我們將逐漸揭開解決問題的秘密方法。在接收到一個block以后,datastreamer需要知道這個block應(yīng)該被寫到哪些datanode上面,同時它
29、也應(yīng)該讓namenode知道這個block寫到了哪些datanode上面。它的做法是聯(lián)絡(luò)namenode:hi,我這里有一個文件的一個block,請告訴我應(yīng)該寫在哪些datanode上面?nodes = nextblockoutputstream(src);-long starttime = system.currenttimemillis();lb = locatefollowingblock(starttime);block = lb.getblock();nodes = lb.getlocations();-return namenode.addblock(src, clientname
30、);這時namenode收到了一個添加block的請求,它包含兩個參數(shù):src和clientname其中src標(biāo)明了這個block屬于哪個文件,clientname則是client端的名稱。我們跳過一些簡單的步驟來看最重要的一步:public locatedblock getadditionalblock(string src, string clientname) throws ioexception inodefileunderconstruction pendingfile = checklease(src, clientname);filelength = pendingfputeco
31、ntentsummary().getlength();blocksize = pendingfile.getpreferredblocksize();clientnode = pendingfile.getclientnode();replication = (int)pendingfile.getreplication();/ choose targets for the new block tobe allocated.datanodedescriptor targets = replicator.choosetarget(replication, clientnode, null, bl
32、ocksize);最重要的一步就是replicator.choosetarget(),它的具體實現(xiàn)如下:private datanodedescriptor choosetarget(int numofreplicas, datanodedescriptor writer, list excludednodes, long blocksize, int maxnodesperrack, list results) if (numofreplicas = 0 | clustermap.getnumofleaves()=0) return writer;int numofresults = res
33、ults.size();boolean newblock = (numofresults=0);if (writer = null & !newblock) writer = (datanodedescriptor)results.get(0);try switch(numofresults) case 0:writer = chooselocalnode(writer, excludednodes, blocksize, maxnodesperrack, results);if (numofreplicas = 0) break;case 1:chooseremoterack(1, results.get(0), excludednodes, blocksize, maxnodesperrack, results);if (numofreplicas = 0) break;case
溫馨提示
- 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)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 供暖設(shè)備運行維護協(xié)議
- 倉庫租賃合同版權(quán)聲明(2024年版)
- 2024年國際物流中心建設(shè)施工安全協(xié)議
- 2(2024版)標(biāo)的為二手游戲虛擬貨幣買賣的合同
- 2024年大數(shù)據(jù)中心設(shè)計與建設(shè)委托合同
- 2024年工程管理委托協(xié)議書
- 供應(yīng)鏈融資協(xié)議(2024年版)
- 2024年垃圾處理與物流服務(wù)協(xié)議
- 2024年土地流轉(zhuǎn)及農(nóng)業(yè)經(jīng)營權(quán)轉(zhuǎn)讓合同
- 2024年工廠設(shè)備維修與保養(yǎng)合同
- 武漢市住宅物業(yè)服務(wù)等級指導(dǎo)標(biāo)準(zhǔn)(試行)
- 健康素養(yǎng)66條課件
- 馬克思主義中國化進程與青年學(xué)生使命擔(dān)當(dāng)學(xué)習(xí)通超星課后章節(jié)答案期末考試題庫2023年
- 設(shè)備部-常用維修工具的使用課件
- 教老外一些基礎(chǔ)漢語教學(xué)課件
- 鋅鋼護欄安裝施工技術(shù)
- BOSCH 噴油器型號與參數(shù)對照表
- 常用中醫(yī)護理技術(shù)在腫瘤患者中的應(yīng)用
- 大學(xué)生溝通成功的案例(9篇)
- 2022年全國大學(xué)生英語競賽D類試題(含答案)
- 音樂欣賞PPT全套完整教學(xué)課件
評論
0/150
提交評論