大家好,關(guān)于mysql存儲(chǔ)過程集合的使用很多朋友都還不太明白,不過沒關(guān)系,因?yàn)榻裉煨【幘蛠頌榇蠹曳窒黻P(guān)于sql存儲(chǔ)過程寫法和調(diào)用的知識(shí)點(diǎn),相信應(yīng)該可以解決大家的一些困惑和問題,如果碰巧可以解決您的問題,還望關(guān)注下本站哦,希望對(duì)各位有所幫助!
python+mysql做一個(gè)圖書管理系統(tǒng)
開發(fā)一個(gè)圖書管理系統(tǒng),首先需要對(duì)此項(xiàng)目進(jìn)行一個(gè)簡(jiǎn)單的需求分析:
主要功能包括:
圖書信息
圖書分類
用戶信息
用戶借閱統(tǒng)計(jì)
管理員
管理員權(quán)限
接下來可以進(jìn)行數(shù)據(jù)庫(kù)的設(shè)計(jì),在這里我提供一個(gè)簡(jiǎn)單的數(shù)據(jù)庫(kù)表結(jié)構(gòu),如有不合理以及需要補(bǔ)充的可以下方進(jìn)行補(bǔ)充。
圖書信息表:
字段:
自增id(主鍵)、書名、作者、出版社、簡(jiǎn)介、縮略圖、出版日期、ISBN(國(guó)際標(biāo)準(zhǔn)書號(hào)(InternationalStandardBookNumber),專門為識(shí)別圖書等文獻(xiàn)而設(shè)計(jì)的國(guó)際編號(hào))、圖書分類、刪除標(biāo)記。
圖書分類表:
字段:自增id(主鍵)、分類名稱、分類編號(hào)、父級(jí)分類編號(hào)。
用戶信息表:
字段:
自增id(主鍵)、用戶名、密碼、添加時(shí)間、狀態(tài)、借閱次數(shù)、歸還次數(shù)。
借閱記錄表:
字段:
自增id(主鍵)、借閱人、借閱書籍編號(hào)、借閱時(shí)間、歸還時(shí)間、履約情況記錄、備注。
管理員表:
字段:
自增id(主鍵),用戶名,密碼,創(chuàng)建時(shí)間,狀態(tài),所屬角色。
管理員分組表(角色):
字段:
自增id(主鍵,角色id),角色對(duì)應(yīng)的權(quán)限。
權(quán)限表:
字段:
自增id(主鍵),權(quán)限名稱,權(quán)限所能訪問控制器集合。
以上則是對(duì)圖書管理系統(tǒng)的簡(jiǎn)要表結(jié)構(gòu)設(shè)計(jì)。
數(shù)據(jù)庫(kù)建立之后接下來就是系統(tǒng)的開發(fā)。
題主希望用到技術(shù)為python+myqsl,pyhon的web框架有:Django、Flask、Tornado。
這里可以推薦python的Flask,因?yàn)榉浅]p便,學(xué)習(xí)周期短,效率高。
數(shù)據(jù)層面的話這里推薦使用原生的sql語句,方便簡(jiǎn)單。題主可以自己封裝一個(gè)mysql的操作類,前提是安裝好python的myql驅(qū)動(dòng)。
前端方面可以考慮使用adminLTE,是一個(gè)開源的后臺(tái)管理系統(tǒng),下載即用,非常方便。
下面是adminLTE的后臺(tái)管理界面:
推薦題主把系統(tǒng)設(shè)計(jì)為前后端分離的模式,即:使用Flask寫API接口,使用Jquery請(qǐng)求接口獲取數(shù)據(jù),然后渲染頁(yè)面。當(dāng)然如果希望用到新的技術(shù)可以使用vue.js。
題主如果對(duì)底層技術(shù)比較感興趣的話可以使用Tornado這個(gè)異步的服務(wù)器框架,此框架采用異步非阻塞IO的方式,性能非常高。包括HTTP服務(wù)器、WebSocket服務(wù)等,這里只使用其HTTP服務(wù)即可。當(dāng)然學(xué)習(xí)成本也隨著提升。
如果對(duì)大家有幫助,可以點(diǎn)贊以示支持!
以上則是對(duì)圖書管理系統(tǒng)的簡(jiǎn)要設(shè)計(jì),以及采用技術(shù)推薦,如有不同意見或者需要補(bǔ)充的,歡迎大家評(píng)論指正。對(duì)IT行業(yè)感興趣的或者想通過自學(xué)進(jìn)入軟件開發(fā)行業(yè)的歡迎關(guān)注,可以提供學(xué)習(xí)上的幫助。
(私信“PHP”,“Python”,“Java”可以免費(fèi)提供學(xué)習(xí)資料哦~)
mysql怎樣建立角色數(shù)據(jù)庫(kù)和怎樣為用戶分配角色
角色一直存在各個(gè)數(shù)據(jù)庫(kù)中,比如SQLServer、Oracle等,MySQL自從版本8.0release,引入了角色這個(gè)概念。
角色的概念
角色就是一組針對(duì)各種數(shù)據(jù)庫(kù)權(quán)限的集合。比如,把一個(gè)角色分配給一個(gè)用戶,那這個(gè)用戶就擁有了這個(gè)角色包含的所有權(quán)限。一個(gè)角色可以分配給多個(gè)用戶,另外一個(gè)用戶也可以擁有多個(gè)角色,兩者是多對(duì)多的關(guān)系。不過MySQL角色目前還沒有提供類似于其他數(shù)據(jù)庫(kù)的系統(tǒng)預(yù)分配的角色。比如某些數(shù)據(jù)庫(kù)的db_owner、db_datareader、db_datawriter等等。那接下來我分幾個(gè)方面,來示例說明角色的使用以及相關(guān)注意事項(xiàng)。
示例1:一個(gè)完整角色的授予步驟
用管理員創(chuàng)建三個(gè)角色:db_owner,db_datareader,db_datawriter
創(chuàng)建三個(gè)普通用戶,分別為ytt1、ytt2、ytt3。
分別授予這三個(gè)用戶對(duì)應(yīng)的角色。
以上是角色授予的一套完整步驟。那上面有點(diǎn)非常規(guī)的地方是激活角色這個(gè)步驟。MySQL角色在創(chuàng)建之初默認(rèn)是沒有激活的,也就是說創(chuàng)建角色,并且給一個(gè)用戶特定的角色,這個(gè)用戶其實(shí)并不能直接使用這個(gè)角色,除非激活了才可以。
示例2:一個(gè)用戶可以擁有多個(gè)角色
示例3:用戶在當(dāng)前session里角色互換
其實(shí)意思是說,用戶連接到MySQL服務(wù)器后,可以切換當(dāng)前的角色列表,比如由db_owner切換到db_datareader。
示例4:關(guān)于角色的兩個(gè)參數(shù)
activate_all_roles_on_login:是否在連接MySQL服務(wù)時(shí)自動(dòng)激活角色mandatory_roles:強(qiáng)制所有用戶默認(rèn)角色
示例5:createrole和createuser都有創(chuàng)建角色權(quán)限,兩者有啥區(qū)別?
以下分別創(chuàng)建兩個(gè)用戶ytt8、ytt9,一個(gè)給createrole,一個(gè)給createuser權(quán)限。
那這里其實(shí)看到createuser包含了createrole,createuser即可以創(chuàng)建用戶,也可以創(chuàng)建角色。
示例6:MySQL用戶也可以當(dāng)角色來用
示例7:角色的撤銷
角色撤銷和之前權(quán)限撤銷類似。要么revoke,要么刪除角色,那這個(gè)角色會(huì)從所有擁有它的用戶上移除。
至此,我分了7個(gè)目錄說明了角色在各個(gè)方面的使用以及注意事項(xiàng),希望對(duì)大家有幫助。
GIS的數(shù)據(jù)是怎么存儲(chǔ)的
大數(shù)據(jù)GIS是在大數(shù)據(jù)浪潮下,GIS從傳統(tǒng)邁向大數(shù)據(jù)時(shí)代的一次變革。大數(shù)據(jù)GIS能為空間大數(shù)據(jù)的存儲(chǔ)、分析和可視化提供更先進(jìn)的理論方法和軟件平臺(tái),促進(jìn)了傳統(tǒng)GIS的產(chǎn)業(yè)升級(jí),為地理信息產(chǎn)業(yè)發(fā)展提供新的渠道和原動(dòng)力,服務(wù)于我國(guó)“十三五”期間的大數(shù)據(jù)產(chǎn)業(yè)發(fā)展和部署。
大數(shù)據(jù)GIS
大數(shù)據(jù)領(lǐng)域已經(jīng)出現(xiàn)了許多實(shí)用的IT技術(shù),例如分布式文件系統(tǒng)、分布式數(shù)據(jù)庫(kù)、分布式計(jì)算框架、流處理框架等。這些技術(shù)使我們能夠使用普通機(jī)器對(duì)大數(shù)據(jù)進(jìn)行處理和挖掘,但多聚焦于通用的非空間數(shù)據(jù)領(lǐng)域,對(duì)空間數(shù)據(jù)的專業(yè)分析能力不足。而傳統(tǒng)GIS由于受其IT技術(shù)框架的限制,并不能很好地應(yīng)對(duì)大數(shù)據(jù)對(duì)分布式存儲(chǔ)與計(jì)算、流數(shù)據(jù)處理等的技術(shù)要求。
大數(shù)據(jù)GIS就是把大數(shù)據(jù)技術(shù)與GIS技術(shù)進(jìn)行深度融合,把GIS的核心能力嵌入到大數(shù)據(jù)基礎(chǔ)框架之內(nèi),并打造出完整的大數(shù)據(jù)GIS技術(shù)體系。大數(shù)據(jù)GIS的核心技術(shù)如下圖所示:
分布式空間數(shù)據(jù)庫(kù)(DistributedSpatialDataBase,DSDB)是使用計(jì)算機(jī)網(wǎng)絡(luò)把面向物理上分散,而管理和控制又需要不同程度集中的空間數(shù)據(jù)庫(kù)連接起來,共同組成一個(gè)統(tǒng)一的數(shù)據(jù)庫(kù)的空間數(shù)據(jù)管理系統(tǒng)。
分布式空間數(shù)據(jù)庫(kù)可看成是空間數(shù)據(jù)庫(kù)+計(jì)算機(jī)網(wǎng)絡(luò)。但是它絕對(duì)不是二者的簡(jiǎn)單結(jié)合,它是把物理上分散的空間數(shù)據(jù)庫(kù)組織成為一個(gè)邏輯上單一的空間數(shù)據(jù)庫(kù)系統(tǒng);同時(shí),又保持了單個(gè)物理空間數(shù)據(jù)庫(kù)的自治性。
分布式空間數(shù)據(jù)庫(kù)系統(tǒng)是由若干個(gè)站點(diǎn)(或節(jié)點(diǎn))集合而成,它們通過網(wǎng)絡(luò)連接在一起,每個(gè)站點(diǎn)都是一個(gè)獨(dú)立的空間數(shù)據(jù)庫(kù)系統(tǒng),它們都擁有各自的數(shù)據(jù)庫(kù)和相應(yīng)的管理系統(tǒng)及其分析工具。整個(gè)數(shù)據(jù)庫(kù)在物理上存儲(chǔ)于不同的設(shè)備上,而在邏輯上是一個(gè)統(tǒng)一的空間數(shù)據(jù)庫(kù)。
分布式空間數(shù)據(jù)庫(kù)系統(tǒng)的特點(diǎn)
可靠性:在DDB中,單一部件的失效,不一定使整個(gè)系統(tǒng)失效,這比集中式數(shù)據(jù)庫(kù)的一個(gè)部件的損壞而導(dǎo)致整個(gè)系統(tǒng)的崩潰好得多,也就是可靠性提高了很多。而且,在DDB中,因?yàn)樵诓煌墓?jié)點(diǎn)上可能有數(shù)據(jù)的副本,因此可以通過多個(gè)版本的副本恢復(fù)失效的數(shù)據(jù)。自治性:DDB允許每個(gè)場(chǎng)所有各自的自主權(quán),允許機(jī)構(gòu)的各個(gè)組織對(duì)其自身的數(shù)據(jù)實(shí)施局部控制,有局部的責(zé)任制,使它們較少地依賴某些遠(yuǎn)程數(shù)據(jù)處理中心。模塊性:DDB是一個(gè)類似于模塊化的系統(tǒng),因?yàn)樵黾右粋€(gè)新的節(jié)點(diǎn),遠(yuǎn)比用一個(gè)更大的系統(tǒng)代替一個(gè)已有的集中式系統(tǒng)要容易得多。這使得整個(gè)系統(tǒng)的結(jié)構(gòu)十分靈活,增加或減少處理能力比較容易,而且這種增減對(duì)系統(tǒng)的其他部分影響較小。模塊性決定了DDB具有很強(qiáng)的升級(jí)能力和較低的投資費(fèi)用。高效率、高可用性:在DDB中,通過合理的分布數(shù)據(jù),使得數(shù)據(jù)存儲(chǔ)在其常用的節(jié)點(diǎn),這樣既縮短了響應(yīng)的時(shí)間,減少了通信費(fèi)用,又提高了數(shù)據(jù)的可用性。并且,對(duì)常用數(shù)據(jù)的重復(fù)存儲(chǔ),也可以提高系統(tǒng)的響應(yīng)速度和數(shù)據(jù)的可用性。Hbase分布式數(shù)據(jù)庫(kù)
概述:Hbase是一個(gè)基于HDFS的面向列的分布式數(shù)據(jù)庫(kù),源于Google的BigTable基于GFS進(jìn)行分布式數(shù)據(jù)存儲(chǔ)一樣,前文提到,Hbase是基于流式數(shù)據(jù)訪問,對(duì)于第時(shí)間延遲的數(shù)據(jù)訪問并不適合在HDFS上運(yùn)行,所以需要實(shí)時(shí)性的隨機(jī)訪問超大規(guī)模的數(shù)據(jù)集,使用Hbase則是更好的選擇;
作用:Hbase作為典型的非關(guān)系型數(shù)據(jù)庫(kù),Nosql數(shù)據(jù)庫(kù)主要分為以下幾類:
?基于鍵值對(duì)存儲(chǔ)的類型;
?基于文檔存儲(chǔ)的類型;
?基于列存儲(chǔ)的類型;
?基于圖形數(shù)據(jù)存儲(chǔ)的類型;
在Nosql領(lǐng)域中,Hbase本身不是最優(yōu)秀的,但得益于與hadoop的整合,為其帶來了強(qiáng)大的擴(kuò)展空間。Hbase本質(zhì)只有插入操作,更新刪除等操作都是通過插入操作來完成,這是由于底層HDFS流式訪問(一次寫入,多次讀取)決定的,每次插入數(shù)據(jù)時(shí),數(shù)據(jù)會(huì)帶有“時(shí)間戳”的標(biāo)記,形成多個(gè)版本,Hbase對(duì)于一個(gè)數(shù)據(jù)會(huì)保留其固定的版本數(shù)量,如果在查詢時(shí),也是顯示出距離當(dāng)前時(shí)間最近的一個(gè)新版本;
傳統(tǒng)的GIS數(shù)據(jù)存儲(chǔ)大多是關(guān)系型數(shù)據(jù)庫(kù),但關(guān)系型數(shù)據(jù)庫(kù)在海量數(shù)據(jù)的管理中面臨許多問題,包括高并發(fā)讀寫、難擴(kuò)展等,已經(jīng)成為制約GIS發(fā)展的瓶頸。同時(shí),GIS數(shù)據(jù)中的圖片、影像數(shù)據(jù)等都是非結(jié)構(gòu)化的,關(guān)系型數(shù)據(jù)庫(kù)不能合理地處理非結(jié)構(gòu)化數(shù)據(jù)。而HBase以其高可靠性、高擴(kuò)展性、高容錯(cuò)性、高效性以及適用于海量非結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)處理分析的優(yōu)勢(shì)在處理GIS數(shù)據(jù)方面提供了另一種思路,即解決HBase應(yīng)對(duì)GIS中的兩大挑戰(zhàn):大規(guī)模數(shù)據(jù)處理的時(shí)延和空間位置建模.
格柵數(shù)據(jù)獲取
柵格數(shù)據(jù)的索引
層級(jí)編碼、X坐標(biāo)與Y坐標(biāo)表示的不僅是一個(gè)瓦片數(shù)據(jù)的索引,同時(shí)還是瓦片數(shù)據(jù)的地理位置標(biāo)志,通過數(shù)學(xué)公式在查詢和檢索時(shí),行列編碼和經(jīng)緯度之間可以實(shí)現(xiàn)相互轉(zhuǎn)換。本文中柵格數(shù)據(jù)存于HBase,rowkey的表示方式為zoom_level、x_coordinate、y_coordinate,列簇(columnfamily)為i,列(column)為png_info。柵格數(shù)據(jù)在系統(tǒng)中的展示形式如圖所示。
在柵格數(shù)據(jù)切片及寫HBase上主要是略去了磁盤寫步驟,默認(rèn)的柵格數(shù)據(jù)獲取是以文件形式存儲(chǔ)在本地磁盤,再通過讀磁盤文件寫入HBase。對(duì)北京市分別切片至16層、18層,并將柵格數(shù)據(jù)寫入HBase測(cè)試結(jié)果
從表可以看出,改進(jìn)后略去磁盤寫操作,在柵格數(shù)據(jù)量較少時(shí)性能反而下降。但在處理數(shù)據(jù)規(guī)模較大(如對(duì)中國(guó)地圖或世界地圖進(jìn)行切片)時(shí),會(huì)因持續(xù)寫磁盤操作,生成文件夾及切片文件數(shù)太多導(dǎo)致inode(索引節(jié)點(diǎn))耗盡。經(jīng)過約24h的持續(xù)切片,生成海量切片小文件,導(dǎo)致服務(wù)器inode用盡,即使硬盤空間仍有空余,也無法在硬盤上創(chuàng)建新文件,進(jìn)而切片工作無法正常完成。
若將切片直接寫入傳統(tǒng)數(shù)據(jù)庫(kù)(如MySQL、Oracle、PostgreSQL等),寫入速度不斷降低,導(dǎo)致寫入時(shí)間不可接受,后期的檢索時(shí)間也較慢。另外,海量切片小文件寫入傳統(tǒng)數(shù)據(jù)庫(kù)會(huì)對(duì)數(shù)據(jù)庫(kù)造成較高的負(fù)載,系統(tǒng)的穩(wěn)定性和擴(kuò)展性難以控制。
經(jīng)過改進(jìn)測(cè)試,對(duì)世界地圖連續(xù)切片一個(gè)月,形成83GB的柵格數(shù)據(jù),未經(jīng)過磁盤寫操作直接寫入HBase,未出現(xiàn)任何異常情況。
本文對(duì)柵格數(shù)據(jù)的檢索也進(jìn)行了驗(yàn)證,在124217416條記錄的HBase表上檢索指定切片的響應(yīng)時(shí)間為毫秒級(jí)(0.004s)。同時(shí),HBase也支持指定范圍檢索,一次返回萬級(jí)別切片的響應(yīng)時(shí)間為秒級(jí)(5.077s)。
為了對(duì)海量矢量空間數(shù)據(jù)進(jìn)行高效存儲(chǔ)、管理與檢索,本文設(shè)計(jì)了矢量空間數(shù)據(jù)的rowkey,并將數(shù)據(jù)存儲(chǔ)于HBase。實(shí)驗(yàn)結(jié)果顯示,對(duì)中國(guó)地圖的矢量空間數(shù)據(jù)在24201991條記錄的Hbase表上檢索指定空間矢量點(diǎn)的響應(yīng)時(shí)間為毫秒級(jí)(0.021s)。檢索線或面的響應(yīng)時(shí)間為秒級(jí),若返回一個(gè)面上的千級(jí)別的坐標(biāo)點(diǎn)時(shí)間約為3.551s。
針對(duì)智慧城市建設(shè)中的數(shù)據(jù)管理問題,利用HBase分布式數(shù)據(jù)庫(kù)的列存儲(chǔ)模型特點(diǎn),設(shè)計(jì)了一種基于HBase的GIS數(shù)據(jù)管理系統(tǒng),實(shí)現(xiàn)了對(duì)矢量空間數(shù)據(jù)與柵格數(shù)據(jù)的高效存儲(chǔ)、索引與檢索。GIS矢量空間數(shù)據(jù)在HBase中存儲(chǔ),首先確定rowkey的設(shè)計(jì),使得在檢索空間位置時(shí)返回盡可能少的數(shù)據(jù)請(qǐng)求,即在檢索時(shí)既考慮經(jīng)度與緯度,又考慮空間數(shù)據(jù)類型和圖層屬性。設(shè)計(jì)了基于表名、空間數(shù)據(jù)類型、經(jīng)緯度Geohash編碼、網(wǎng)格ID的rowkey方法。為了加快切片效率和減少存儲(chǔ)成本,本文在生成柵格數(shù)據(jù)時(shí)在mapnik切片的基礎(chǔ)上做了優(yōu)化,使柵格數(shù)據(jù)不經(jīng)過磁盤寫操作,直接寫入HBase。
參考文獻(xiàn)
《基于HBase的海量GIS數(shù)據(jù)分布式處理實(shí)踐》
mysql中UUID產(chǎn)生的數(shù)據(jù),用什么數(shù)據(jù)類型存儲(chǔ)
因?yàn)檫€沒有寫入MySQL,所以你在把數(shù)據(jù)寫入Redis時(shí),需要設(shè)計(jì)一個(gè)key來唯一標(biāo)識(shí)一條數(shù)據(jù).
MySQL表中應(yīng)該設(shè)置一個(gè)唯一字段用于存儲(chǔ)這個(gè)key.
這個(gè)key可以是一個(gè)由程序即時(shí)生成的隨機(jī)唯一值,比如可以取Linux提供的uuid:
/proc/sys/kernel/random/uuid
取到后用sadd添加到Redis的
集合(元素唯一)
里.添加成功,表示集合中沒有這個(gè)uuid,在集合里是唯一的.
然后再把這個(gè)uuid用lpush添加到Redis的
列表(元素有序)
里.lpush入隊(duì)后,當(dāng)列表的長(zhǎng)度大于等于N(自定義數(shù)值)時(shí),Redis用lrange取出列表里的元素并
批量寫入
到MySQL,寫入成功后用ltrim刪掉列表中已經(jīng)處理的元素.優(yōu)化就體現(xiàn)在:原來的即時(shí)寫入轉(zhuǎn)變?yōu)榕繉懭?
風(fēng)險(xiǎn)是:Redis意外崩潰有可能丟數(shù)據(jù).
比如你的Redis配置了appendfsynceverysec
那就有丟失前1秒數(shù)據(jù)的風(fēng)險(xiǎn).
如何用redis/memcache做Mysql緩存層
Redis的作者SalvatoreSanfilippo曾經(jīng)對(duì)這兩種基于內(nèi)存的數(shù)據(jù)存儲(chǔ)系統(tǒng)進(jìn)行過比較:
1、Redis支持服務(wù)器端的數(shù)據(jù)操作:Redis相比Memcached來說,擁有更多的數(shù)據(jù)結(jié)構(gòu)和并支持更豐富的數(shù)據(jù)操作,通常在Memcached里,你需要將數(shù)據(jù)拿到客戶端來進(jìn)行類似的修改再set回去。這大大增加了網(wǎng)絡(luò)IO的次數(shù)和數(shù)據(jù)體積。在Redis中,這些復(fù)雜的操作通常和一般的GET/SET一樣高效。所以,如果需要緩存能夠支持更復(fù)雜的結(jié)構(gòu)和操作,那么Redis會(huì)是不錯(cuò)的選擇。
2、內(nèi)存使用效率對(duì)比:使用簡(jiǎn)單的key-value存儲(chǔ)的話,Memcached的內(nèi)存利用率更高,而如果Redis采用hash結(jié)構(gòu)來做key-value存儲(chǔ),由于其組合式的壓縮,其內(nèi)存利用率會(huì)高于Memcached。
3、性能對(duì)比:由于Redis只使用單核,而Memcached可以使用多核,所以平均每一個(gè)核上Redis在存儲(chǔ)小數(shù)據(jù)時(shí)比Memcached性能更高。而在100k以上的數(shù)據(jù)中,Memcached性能要高于Redis,雖然Redis最近也在存儲(chǔ)大數(shù)據(jù)的性能上進(jìn)行優(yōu)化,但是比起Memcached,還是稍有遜色。
具體為什么會(huì)出現(xiàn)上面的結(jié)論,以下為收集到的資料:
1、數(shù)據(jù)類型支持不同
與Memcached僅支持簡(jiǎn)單的key-value結(jié)構(gòu)的數(shù)據(jù)記錄不同,Redis支持的數(shù)據(jù)類型要豐富得多。最為常用的數(shù)據(jù)類型主要由五種:String、Hash、List、Set和SortedSet。Redis內(nèi)部使用一個(gè)redisObject對(duì)象來表示所有的key和value。redisObject最主要的信息如圖所示:
type代表一個(gè)value對(duì)象具體是何種數(shù)據(jù)類型,encoding是不同數(shù)據(jù)類型在redis內(nèi)部的存儲(chǔ)方式,比如:type=string代表value存儲(chǔ)的是一個(gè)普通字符串,那么對(duì)應(yīng)的encoding可以是raw或者是int,如果是int則代表實(shí)際redis內(nèi)部是按數(shù)值型類存儲(chǔ)和表示這個(gè)字符串的,當(dāng)然前提是這個(gè)字符串本身可以用數(shù)值表示,比如:”123″“456”這樣的字符串。只有打開了Redis的虛擬內(nèi)存功能,vm字段字段才會(huì)真正的分配內(nèi)存,該功能默認(rèn)是關(guān)閉狀態(tài)的。
1)String
常用命令:set/get/decr/incr/mget等;應(yīng)用場(chǎng)景:String是最常用的一種數(shù)據(jù)類型,普通的key/value存儲(chǔ)都可以歸為此類;實(shí)現(xiàn)方式:String在redis內(nèi)部存儲(chǔ)默認(rèn)就是一個(gè)字符串,被redisObject所引用,當(dāng)遇到incr、decr等操作時(shí)會(huì)轉(zhuǎn)成數(shù)值型進(jìn)行計(jì)算,此時(shí)redisObject的encoding字段為int。2)Hash常用命令:hget/hset/hgetall等應(yīng)用場(chǎng)景:我們要存儲(chǔ)一個(gè)用戶信息對(duì)象數(shù)據(jù),其中包括用戶ID、用戶姓名、年齡和生日,通過用戶ID我們希望獲取該用戶的姓名或者年齡或者生日;實(shí)現(xiàn)方式:Redis的Hash實(shí)際是內(nèi)部存儲(chǔ)的Value為一個(gè)HashMap,并提供了直接存取這個(gè)Map成員的接口。如圖所示,Key是用戶ID,value是一個(gè)Map。這個(gè)Map的key是成員的屬性名,value是屬性值。這樣對(duì)數(shù)據(jù)的修改和存取都可以直接通過其內(nèi)部Map的Key(Redis里稱內(nèi)部Map的key為field),也就是通過key(用戶ID)+field(屬性標(biāo)簽)就可以操作對(duì)應(yīng)屬性數(shù)據(jù)。當(dāng)前HashMap的實(shí)現(xiàn)有兩種方式:當(dāng)HashMap的成員比較少時(shí)Redis為了節(jié)省內(nèi)存會(huì)采用類似一維數(shù)組的方式來緊湊存儲(chǔ),而不會(huì)采用真正的HashMap結(jié)構(gòu),這時(shí)對(duì)應(yīng)的value的redisObject的encoding為zipmap,當(dāng)成員數(shù)量增大時(shí)會(huì)自動(dòng)轉(zhuǎn)成真正的HashMap,此時(shí)encoding為ht。3)List常用命令:lpush/rpush/lpop/rpop/lrange等;應(yīng)用場(chǎng)景:Redislist的應(yīng)用場(chǎng)景非常多,也是Redis最重要的數(shù)據(jù)結(jié)構(gòu)之一,比如twitter的關(guān)注列表,粉絲列表等都可以用Redis的list結(jié)構(gòu)來實(shí)現(xiàn);實(shí)現(xiàn)方式:Redislist的實(shí)現(xiàn)為一個(gè)雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內(nèi)存開銷,Redis內(nèi)部的很多實(shí)現(xiàn),包括發(fā)送緩沖隊(duì)列等也都是用的這個(gè)數(shù)據(jù)結(jié)構(gòu)。4)Set常用命令:sadd/spop/smembers/sunion等;應(yīng)用場(chǎng)景:Redisset對(duì)外提供的功能與list類似是一個(gè)列表的功能,特殊之處在于set是可以自動(dòng)排重的,當(dāng)你需要存儲(chǔ)一個(gè)列表數(shù)據(jù),又不希望出現(xiàn)重復(fù)數(shù)據(jù)時(shí),set是一個(gè)很好的選擇,并且set提供了判斷某個(gè)成員是否在一個(gè)set集合內(nèi)的重要接口,這個(gè)也是list所不能提供的;實(shí)現(xiàn)方式:set的內(nèi)部實(shí)現(xiàn)是一個(gè)value永遠(yuǎn)為null的HashMap,實(shí)際就是通過計(jì)算hash的方式來快速排重的,這也是set能提供判斷一個(gè)成員是否在集合內(nèi)的原因。5)SortedSet常用命令:zadd/zrange/zrem/zcard等;應(yīng)用場(chǎng)景:Redissortedset的使用場(chǎng)景與set類似,區(qū)別是set不是自動(dòng)有序的,而sortedset可以通過用戶額外提供一個(gè)優(yōu)先級(jí)(score)的參數(shù)來為成員排序,并且是插入有序的,即自動(dòng)排序。當(dāng)你需要一個(gè)有序的并且不重復(fù)的集合列表,那么可以選擇sortedset數(shù)據(jù)結(jié)構(gòu),比如twitter的publictimeline可以以發(fā)表時(shí)間作為score來存儲(chǔ),這樣獲取時(shí)就是自動(dòng)按時(shí)間排好序的。實(shí)現(xiàn)方式:Redissortedset的內(nèi)部使用HashMap和跳躍表(SkipList)來保證數(shù)據(jù)的存儲(chǔ)和有序,HashMap里放的是成員到score的映射,而跳躍表里存放的是所有的成員,排序依據(jù)是HashMap里存的score,使用跳躍表的結(jié)構(gòu)可以獲得比較高的查找效率,并且在實(shí)現(xiàn)上比較簡(jiǎn)單。2、內(nèi)存管理機(jī)制不同在Redis中,并不是所有的數(shù)據(jù)都一直存儲(chǔ)在內(nèi)存中的。這是和Memcached相比一個(gè)最大的區(qū)別。當(dāng)物理內(nèi)存用完時(shí),Redis可以將一些很久沒用到的value交換到磁盤。Redis只會(huì)緩存所有的key的信息,如果Redis發(fā)現(xiàn)內(nèi)存的使用量超過了某一個(gè)閥值,將觸發(fā)swap的操作,Redis根據(jù)“swappability=age*log(size_in_memory)”計(jì)算出哪些key對(duì)應(yīng)的value需要swap到磁盤。然后再將這些key對(duì)應(yīng)的value持久化到磁盤中,同時(shí)在內(nèi)存中清除。這種特性使得Redis可以保持超過其機(jī)器本身內(nèi)存大小的數(shù)據(jù)。當(dāng)然,機(jī)器本身的內(nèi)存必須要能夠保持所有的key,畢竟這些數(shù)據(jù)是不會(huì)進(jìn)行swap操作的。同時(shí)由于Redis將內(nèi)存中的數(shù)據(jù)swap到磁盤中的時(shí)候,提供服務(wù)的主線程和進(jìn)行swap操作的子線程會(huì)共享這部分內(nèi)存,所以如果更新需要swap的數(shù)據(jù),Redis將阻塞這個(gè)操作,直到子線程完成swap操作后才可以進(jìn)行修改。當(dāng)從Redis中讀取數(shù)據(jù)的時(shí)候,如果讀取的key對(duì)應(yīng)的value不在內(nèi)存中,那么Redis就需要從swap文件中加載相應(yīng)數(shù)據(jù),然后再返回給請(qǐng)求方。這里就存在一個(gè)I/O線程池的問題。在默認(rèn)的情況下,Redis會(huì)出現(xiàn)阻塞,即完成所有的swap文件加載后才會(huì)相應(yīng)。這種策略在客戶端的數(shù)量較小,進(jìn)行批量操作的時(shí)候比較合適。但是如果將Redis應(yīng)用在一個(gè)大型的網(wǎng)站應(yīng)用程序中,這顯然是無法滿足大并發(fā)的情況的。所以Redis運(yùn)行我們?cè)O(shè)置I/O線程池的大小,對(duì)需要從swap文件中加載相應(yīng)數(shù)據(jù)的讀取請(qǐng)求進(jìn)行并發(fā)操作,減少阻塞的時(shí)間。對(duì)于像Redis和Memcached這種基于內(nèi)存的數(shù)據(jù)庫(kù)系統(tǒng)來說,內(nèi)存管理的效率高低是影響系統(tǒng)性能的關(guān)鍵因素。傳統(tǒng)C語言中的malloc/free函數(shù)是最常用的分配和釋放內(nèi)存的方法,但是這種方法存在著很大的缺陷:首先,對(duì)于開發(fā)人員來說不匹配的malloc和free容易造成內(nèi)存泄露;其次頻繁調(diào)用會(huì)造成大量?jī)?nèi)存碎片無法回收重新利用,降低內(nèi)存利用率;最后作為系統(tǒng)調(diào)用,其系統(tǒng)開銷遠(yuǎn)遠(yuǎn)大于一般函數(shù)調(diào)用。所以,為了提高內(nèi)存的管理效率,高效的內(nèi)存管理方案都不會(huì)直接使用malloc/free調(diào)用。Redis和Memcached均使用了自身設(shè)計(jì)的內(nèi)存管理機(jī)制,但是實(shí)現(xiàn)方法存在很大的差異,下面將會(huì)對(duì)兩者的內(nèi)存管理機(jī)制分別進(jìn)行介紹。Memcached默認(rèn)使用SlabAllocation機(jī)制管理內(nèi)存,其主要思想是按照預(yù)先規(guī)定的大小,將分配的內(nèi)存分割成特定長(zhǎng)度的塊以存儲(chǔ)相應(yīng)長(zhǎng)度的key-value數(shù)據(jù)記錄,以完全解決內(nèi)存碎片問題。SlabAllocation機(jī)制只為存儲(chǔ)外部數(shù)據(jù)而設(shè)計(jì),也就是說所有的key-value數(shù)據(jù)都存儲(chǔ)在SlabAllocation系統(tǒng)里,而Memcached的其它內(nèi)存請(qǐng)求則通過普通的malloc/free來申請(qǐng),因?yàn)檫@些請(qǐng)求的數(shù)量和頻率決定了它們不會(huì)對(duì)整個(gè)系統(tǒng)的性能造成影響SlabAllocation的原理相當(dāng)簡(jiǎn)單。如圖所示,它首先從操作系統(tǒng)申請(qǐng)一大塊內(nèi)存,并將其分割成各種尺寸的塊Chunk,并把尺寸相同的塊分成組SlabClass。其中,Chunk就是用來存儲(chǔ)key-value數(shù)據(jù)的最小單位。每個(gè)SlabClass的大小,可以在Memcached啟動(dòng)的時(shí)候通過制定GrowthFactor來控制。假定圖中GrowthFactor的取值為1.25,如果第一組Chunk的大小為88個(gè)字節(jié),第二組Chunk的大小就為112個(gè)字節(jié),依此類推。當(dāng)Memcached接收到客戶端發(fā)送過來的數(shù)據(jù)時(shí)首先會(huì)根據(jù)收到數(shù)據(jù)的大小選擇一個(gè)最合適的SlabClass,然后通過查詢Memcached保存著的該SlabClass內(nèi)空閑Chunk的列表就可以找到一個(gè)可用于存儲(chǔ)數(shù)據(jù)的Chunk。當(dāng)一條數(shù)據(jù)庫(kù)過期或者丟棄時(shí),該記錄所占用的Chunk就可以回收,重新添加到空閑列表中。從以上過程我們可以看出Memcached的內(nèi)存管理制效率高,而且不會(huì)造成內(nèi)存碎片,但是它最大的缺點(diǎn)就是會(huì)導(dǎo)致空間浪費(fèi)。因?yàn)槊總€(gè)Chunk都分配了特定長(zhǎng)度的內(nèi)存空間,所以變長(zhǎng)數(shù)據(jù)無法充分利用這些空間。如圖所示,將100個(gè)字節(jié)的數(shù)據(jù)緩存到128個(gè)字節(jié)的Chunk中,剩余的28個(gè)字節(jié)就浪費(fèi)掉了。Redis的內(nèi)存管理主要通過源碼中zmalloc.h和zmalloc.c兩個(gè)文件來實(shí)現(xiàn)的。Redis為了方便內(nèi)存的管理,在分配一塊內(nèi)存之后,會(huì)將這塊內(nèi)存的大小存入內(nèi)存塊的頭部。如圖所示,real_ptr是redis調(diào)用malloc后返回的指針。redis將內(nèi)存塊的大小size存入頭部,size所占據(jù)的內(nèi)存大小是已知的,為size_t類型的長(zhǎng)度,然后返回ret_ptr。當(dāng)需要釋放內(nèi)存的時(shí)候,ret_ptr被傳給內(nèi)存管理程序。通過ret_ptr,程序可以很容易的算出real_ptr的值,然后將real_ptr傳給free釋放內(nèi)存。Redis通過定義一個(gè)數(shù)組來記錄所有的內(nèi)存分配情況,這個(gè)數(shù)組的長(zhǎng)度為ZMALLOC_MAX_ALLOC_STAT。數(shù)組的每一個(gè)元素代表當(dāng)前程序所分配的內(nèi)存塊的個(gè)數(shù),且內(nèi)存塊的大小為該元素的下標(biāo)。在源碼中,這個(gè)數(shù)組為zmalloc_allocations。zmalloc_allocations[16]代表已經(jīng)分配的長(zhǎng)度為16bytes的內(nèi)存塊的個(gè)數(shù)。zmalloc.c中有一個(gè)靜態(tài)變量used_memory用來記錄當(dāng)前分配的內(nèi)存總大小。所以,總的來看,Redis采用的是包裝的mallc/free,相較于Memcached的內(nèi)存管理方法來說,要簡(jiǎn)單很多。3、數(shù)據(jù)持久化支持Redis雖然是基于內(nèi)存的存儲(chǔ)系統(tǒng),但是它本身是支持內(nèi)存數(shù)據(jù)的持久化的,而且提供兩種主要的持久化策略:RDB快照和AOF日志。而memcached是不支持?jǐn)?shù)據(jù)持久化操作的。1)RDB快照Redis支持將當(dāng)前數(shù)據(jù)的快照存成一個(gè)數(shù)據(jù)文件的持久化機(jī)制,即RDB快照。但是一個(gè)持續(xù)寫入的數(shù)據(jù)庫(kù)如何生成快照呢?Redis借助了fork命令的copyonwrite機(jī)制。在生成快照時(shí),將當(dāng)前進(jìn)程fork出一個(gè)子進(jìn)程,然后在子進(jìn)程中循環(huán)所有的數(shù)據(jù),將數(shù)據(jù)寫成為RDB文件。我們可以通過Redis的save指令來配置RDB快照生成的時(shí)機(jī),比如配置10分鐘就生成快照,也可以配置有1000次寫入就生成快照,也可以多個(gè)規(guī)則一起實(shí)施。這些規(guī)則的定義就在Redis的配置文件中,你也可以通過Redis的CONFIGSET命令在Redis運(yùn)行時(shí)設(shè)置規(guī)則,不需要重啟Redis。Redis的RDB文件不會(huì)壞掉,因?yàn)槠鋵懖僮魇窃谝粋€(gè)新進(jìn)程中進(jìn)行的,當(dāng)生成一個(gè)新的RDB文件時(shí),Redis生成的子進(jìn)程會(huì)先將數(shù)據(jù)寫到一個(gè)臨時(shí)文件中,然后通過原子性rename系統(tǒng)調(diào)用將臨時(shí)文件重命名為RDB文件,這樣在任何時(shí)候出現(xiàn)故障,Redis的RDB文件都總是可用的。同時(shí),Redis的RDB文件也是Redis主從同步內(nèi)部實(shí)現(xiàn)中的一環(huán)。RDB有他的不足,就是一旦數(shù)據(jù)庫(kù)出現(xiàn)問題,那么我們的RDB文件中保存的數(shù)據(jù)并不是全新的,從上次RDB文件生成到Redis停機(jī)這段時(shí)間的數(shù)據(jù)全部丟掉了。在某些業(yè)務(wù)下,這是可以忍受的。2)AOF日志AOF日志的全稱是appendonlyfile,它是一個(gè)追加寫入的日志文件。與一般數(shù)據(jù)庫(kù)的binlog不同的是,AOF文件是可識(shí)別的純文本,它的內(nèi)容就是一個(gè)個(gè)的Redis標(biāo)準(zhǔn)命令。只有那些會(huì)導(dǎo)致數(shù)據(jù)發(fā)生修改的命令才會(huì)追加到AOF文件。每一條修改數(shù)據(jù)的命令都生成一條日志,AOF文件會(huì)越來越大,所以Redis又提供了一個(gè)功能,叫做AOFrewrite。其功能就是重新生成一份AOF文件,新的AOF文件中一條記錄的操作只會(huì)有一次,而不像一份老文件那樣,可能記錄了對(duì)同一個(gè)值的多次操作。其生成過程和RDB類似,也是fork一個(gè)進(jìn)程,直接遍歷數(shù)據(jù),寫入新的AOF臨時(shí)文件。在寫入新文件的過程中,所有的寫操作日志還是會(huì)寫到原來老的AOF文件中,同時(shí)還會(huì)記錄在內(nèi)存緩沖區(qū)中。當(dāng)重完操作完成后,會(huì)將所有緩沖區(qū)中的日志一次性寫入到臨時(shí)文件中。然后調(diào)用原子性的rename命令用新的AOF文件取代老的AOF文件。AOF是一個(gè)寫文件操作,其目的是將操作日志寫到磁盤上,所以它也同樣會(huì)遇到我們上面說的寫操作的流程。在Redis中對(duì)AOF調(diào)用write寫入后,通過appendfsync選項(xiàng)來控制調(diào)用fsync將其寫到磁盤上的時(shí)間,下面appendfsync的三個(gè)設(shè)置項(xiàng),安全強(qiáng)度逐漸變強(qiáng)。appendfsyncno當(dāng)設(shè)置appendfsync為no的時(shí)候,Redis不會(huì)主動(dòng)調(diào)用fsync去將AOF日志內(nèi)容同步到磁盤,所以這一切就完全依賴于操作系統(tǒng)的調(diào)試了。對(duì)大多數(shù)Linux操作系統(tǒng),是每30秒進(jìn)行一次fsync,將緩沖區(qū)中的數(shù)據(jù)寫到磁盤上。appendfsynceverysec當(dāng)設(shè)置appendfsync為everysec的時(shí)候,Redis會(huì)默認(rèn)每隔一秒進(jìn)行一次fsync調(diào)用,將緩沖區(qū)中的數(shù)據(jù)寫到磁盤。但是當(dāng)這一次的fsync調(diào)用時(shí)長(zhǎng)超過1秒時(shí)。Redis會(huì)采取延遲fsync的策略,再等一秒鐘。也就是在兩秒后再進(jìn)行fsync,這一次的fsync就不管會(huì)執(zhí)行多長(zhǎng)時(shí)間都會(huì)進(jìn)行。這時(shí)候由于在fsync時(shí)文件描述符會(huì)被阻塞,所以當(dāng)前的寫操作就會(huì)阻塞。所以結(jié)論就是,在絕大多數(shù)情況下,Redis會(huì)每隔一秒進(jìn)行一次fsync。在最壞的情況下,兩秒鐘會(huì)進(jìn)行一次fsync操作。這一操作在大多數(shù)數(shù)據(jù)庫(kù)系統(tǒng)中被稱為groupcommit,就是組合多次寫操作的數(shù)據(jù),一次性將日志寫到磁盤。appednfsyncalways當(dāng)設(shè)置appendfsync為always時(shí),每一次寫操作都會(huì)調(diào)用一次fsync,這時(shí)數(shù)據(jù)是最安全的,當(dāng)然,由于每次都會(huì)執(zhí)行fsync,所以其性能也會(huì)受到影響。對(duì)于一般性的業(yè)務(wù)需求,建議使用RDB的方式進(jìn)行持久化,原因是RDB的開銷并相比AOF日志要低很多,對(duì)于那些無法忍數(shù)據(jù)丟失的應(yīng)用,建議使用AOF日志。4、集群管理的不同Memcached是全內(nèi)存的數(shù)據(jù)緩沖系統(tǒng),Redis雖然支持?jǐn)?shù)據(jù)的持久化,但是全內(nèi)存畢竟才是其高性能的本質(zhì)。作為基于內(nèi)存的存儲(chǔ)系統(tǒng)來說,機(jī)器物理內(nèi)存的大小就是系統(tǒng)能夠容納的最大數(shù)據(jù)量。如果需要處理的數(shù)據(jù)量超過了單臺(tái)機(jī)器的物理內(nèi)存大小,就需要構(gòu)建分布式集群來擴(kuò)展存儲(chǔ)能力。Memcached本身并不支持分布式,因此只能在客戶端通過像一致性哈希這樣的分布式算法來實(shí)現(xiàn)Memcached的分布式存儲(chǔ)。下圖給出了Memcached的分布式存儲(chǔ)實(shí)現(xiàn)架構(gòu)。當(dāng)客戶端向Memcached集群發(fā)送數(shù)據(jù)之前,首先會(huì)通過內(nèi)置的分布式算法計(jì)算出該條數(shù)據(jù)的目標(biāo)節(jié)點(diǎn),然后數(shù)據(jù)會(huì)直接發(fā)送到該節(jié)點(diǎn)上存儲(chǔ)。但客戶端查詢數(shù)據(jù)時(shí),同樣要計(jì)算出查詢數(shù)據(jù)所在的節(jié)點(diǎn),然后直接向該節(jié)點(diǎn)發(fā)送查詢請(qǐng)求以獲取數(shù)據(jù)。相較于Memcached只能采用客戶端實(shí)現(xiàn)分布式存儲(chǔ),Redis更偏向于在服務(wù)器端構(gòu)建分布式存儲(chǔ)。最新版本的Redis已經(jīng)支持了分布式存儲(chǔ)功能。RedisCluster是一個(gè)實(shí)現(xiàn)了分布式且允許單點(diǎn)故障的Redis高級(jí)版本,它沒有中心節(jié)點(diǎn),具有線性可伸縮的功能。下圖給出RedisCluster的分布式存儲(chǔ)架構(gòu),其中節(jié)點(diǎn)與節(jié)點(diǎn)之間通過二進(jìn)制協(xié)議進(jìn)行通信,節(jié)點(diǎn)與客戶端之間通過ascii協(xié)議進(jìn)行通信。在數(shù)據(jù)的放置策略上,RedisCluster將整個(gè)key的數(shù)值域分成4096個(gè)哈希槽,每個(gè)節(jié)點(diǎn)上可以存儲(chǔ)一個(gè)或多個(gè)哈希槽,也就是說當(dāng)前RedisCluster支持的最大節(jié)點(diǎn)數(shù)就是4096。RedisCluster使用的分布式算法也很簡(jiǎn)單:crc16(key)%HASH_SLOTS_NUMBER。為了保證單點(diǎn)故障下的數(shù)據(jù)可用性,RedisCluster引入了Master節(jié)點(diǎn)和Slave節(jié)點(diǎn)。在RedisCluster中,每個(gè)Master節(jié)點(diǎn)都會(huì)有對(duì)應(yīng)的兩個(gè)用于冗余的Slave節(jié)點(diǎn)。這樣在整個(gè)集群中,任意兩個(gè)節(jié)點(diǎn)的宕機(jī)都不會(huì)導(dǎo)致數(shù)據(jù)的不可用。當(dāng)Master節(jié)點(diǎn)退出后,集群會(huì)自動(dòng)選擇一個(gè)Slave節(jié)點(diǎn)成為新的Master節(jié)點(diǎn)。關(guān)于mysql存儲(chǔ)過程集合的使用的內(nèi)容到此結(jié)束,希望對(duì)大家有所幫助。