一、NoSql(非關系型數據庫)
NoSQL:NoSQL = Not Only SQL 非關系型數據庫 ? NoSQL,泛指非關系型的數據庫。隨著互聯網web2.0網站的興起,傳統的關系數據庫在應付web2.0網站,特別是超大規模和高并發的SNS類型的web2.0純動態網站已經顯得力不從心,暴露了很多難以克服的問題,而非關系型的數據庫則由于其本身的特點得到了非常迅速的發展。NoSQL數據庫的產生就是為了解決大規模數據集合多重數據種類帶來的挑戰,尤其是大數據應用難題。
1.1 優點
-
高可擴展性
-
分布式計算
-
低成本
-
架構的靈活性,半結構化數據
-
沒有復雜的關系
1.2 缺點
-
沒有標準化
-
有限的查詢功能(到目前為止)
1.3 分類
類型 | 代表 | 特點 |
---|---|---|
列存儲 | Hbase、Cassandra、Hypertable | 顧名思義,是按列存儲數據的。最大的特點是方便存儲結構化和半結構化數據,方便做數據壓縮,對針對某一列或者某幾列的查詢有非常大的IO優勢。 |
文檔存儲 | MongoDB、CouchDB | 文檔存儲一般用類似json的格式存儲,存儲的內容是文檔型的。這樣也就有有機會對某些字段建立索引,實現關系數據庫的某些功能。 |
key-value存儲 | Berkeley DB、MemcacheDB、Redis | 可以通過key快速查詢到其value。一般來說,value可以是任何格式。 |
圖存儲 | Neo4J、FlockDB | 圖形關系的最佳存儲。使用傳統關系數據庫來解決的話性能低下,而且設計使用不方便。 |
對象存儲 | db4o、Versant | 通過類似面向對象語言的語法操作數據庫,通過對象的方式存取數據。 |
xml數據庫 | Berkeley DB XML、BaseX | 高效的存儲XML數據,并支持XML的內部查詢語法,比如XQuery,Xpath。 |
二、Redis與網站架構
2.1什么是Redis?
-
Remote Dictionary Server 縮寫 是個基于內存的網絡存儲系統
-
豐富的數據結構(sets, sorted sets,hashes, list ...)
-
本質是key-value,但是與memcached不同的是,value的類型得到了擴展
一個普通的問題列表需求
-
問題本身的數據(標題,投票等等)
-
問題的作者數據(另 張單獨的 張數據表,通過某個鍵值關聯)
-
問題的標簽(本身單獨一張數據表,通過一個中間關系表與問題產生 對多的關系)
?
一條sql語句解決問題 too young too simple
多次查詢讓你懷疑人生
?
冗余字段過多會讓你看起來很傻
為啥不試試Redis
2.2 與sql比較
大大減少了查詢數量,提高了效率 redis的API更加人性化,再也不需要構建SQL語句,節省了SQL的解析時間
三、Redis
3.1簡介
Redis 是完全開源免費的,遵守BSD協議,是一個高性能的key-value數據庫。
Redis 與其他 key - value 緩存產品有以下三個特點:
-
Redis支持數據的持久化,可以將內存中的數據保存在磁盤中,重啟的時候可以再次加載進行使用。
-
Redis不僅僅支持簡單的key-value string類型的數據,同時還提供list,set,zset,hash等數據結構的存儲。
-
Redis支持數據的備份,即master-slave模式的數據備份。
3.2 優勢
-
性能極高?– Redis能讀的速度是110000次/s,寫的速度是81000次/s 。
-
豐富的數據類型 – Redis支持二進制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 數據類型操作。
-
原子 – Redis的所有操作都是原子性的,同時Redis還支持對幾個操作全并后的原子性執行。
-
豐富的特性?– Redis還支持通知, key過期等等特性。
3.3和其他的key-value存儲有什么不同
-
Redis有著更為復雜的數據結構并且提供對他們的原子性操作,這是一個不同于其他數據庫的進化路徑。Redis的數據類型都是基于基本數據結構的同時對程序員透明,無需進行額外的抽象。
-
Redis運行在內存中但是可以持久化到磁盤,所以在對不同數據集進行高速讀寫時需要權衡內存,因為數據量不能大于硬件內存。在內存數據庫方面的另一個優點是,相比在磁盤上相同的復雜的數據結構,在內存中操作起來非常簡單,這樣Redis可以做很多內部復雜性很強的事情。同時,在磁盤格式方面他們是緊湊的以追加的方式產生的,因為他們并不需要進行隨機訪問。
3.4 redis 為什么能夠持久化存儲 ?
因為 RDB 和 AOF
-
RDB [RDB 將數據庫的快照(snapshot)以二進制的方式保存到磁盤中。]
在運行情況下, Redis 以數據結構的形式將數據維持在內存中, 為了讓這些數據在 Redis 重啟之后仍然可用, Redis 分別提供了 RDB 和 AOF 兩種持久化模式。
在 Redis 運行時, RDB 程序將當前內存中的數據庫快照保存到磁盤文件中, 在 Redis 重啟動時, RDB 程序可以通過載入 RDB 文件來還原數據庫的狀態。
RDB 功能最核心的是 rdbSave 和 rdbLoad 兩個函數, 前者用于生成 RDB 文件到磁盤, 而后者則用于將 RDB 文件中的數據重新載入到內存中:
RDB 本質上是個文件 每隔一段時間 在redis配置文件中進行設置 將內存中的數據存入文件中 如果數據過大 也容易造成數據丟失
-
AOF [ 則以協議文本的方式,將所有對數據庫進行過寫入的命令(及其參數)記錄到 AOF 文件,以此達到記錄數據庫狀態的目的。]
AOF 將命令追加到文件中 將原有的內容替換掉 記錄到 AOF 文件, 以此達到記錄數據庫狀態的目的, 為了方便起見, 我們稱呼這種記錄過程為同步。
3.5 安裝redis
sudo apt-get install redis-server 安裝完成后,Redis服務器會自動啟動,我們檢查Redis服務器程序 ps -aux|grep redis 或者 netstat -nlt | grep 6379 ? #看見 port 6379 就成功啟動了redis服務
文件名稱 | 作用 |
---|---|
redis-server | redis 服務端 |
redis-cli | redis 客戶端 |
redis-benchmark | redis性能測試工具 |
redis-check-aof | aof修復工具 |
redis-check-rdb | rdb |
redis-sentinel | 哨兵服務器 2.8版本之后才有 |
【redis-sentinel】監控你管理的作用來提高集群的高可用性
redis-cli客戶端使用方式: redis-cli -p ?#端口 -h ?#主機 鏈接上 ? redis-cli -p 6379 127.0.0.1:6379> ping PONG 127.0.0.1:6379> ? #ping之后 pong來了就是成功了 離開客戶端請輸入quit ? 服務管理 啟動/停止/重啟redis有三種方式 1) systemctl start/stop/restart redis-server.service 2) service redis-server start|restart|stop 3) cd /etc/init.d./redis-server ?start/stop/restart
【redis的配置文件】
配置文件在/etc/redis/redis.conf
sudo vim /etc/redis/redis.conf # 常用配置項 requirepass 你的密碼 ? # 服務器遠程連接密碼 bind 127.0.0.1 ? ? # 綁定ip port 5379 # 指定端口 daemonize yes # 是否以守護進程執行,如果以守護進程執行,不會在命令行下阻塞 dbfilename dump.rdb ? #數據文件 dir /var/lib/redis ? #數據文件存儲路徑 ? ? #如果指定了密碼,啟用客戶端時需要加上-a 密碼 redis-cli -a 密碼
?
四、redis數據類型
Redis支持五種數據類型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。
-
redis常用命令請參考:http://redis.cn/commands.html
4.1 string
是最簡單的類型,你可以理解為一個key 對應一個value。string 類型是二進制安全的。意思是redis 的string 可以包含任何數據,比如jpg 圖片或者序列化的對象。string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。
-
設置鍵
命令:SET key value #設置單鍵值對 >set h1 100 #設置h1的值為100 ? 命令:mset key value [key value] #設置多個鍵值對 >mset name '王寶強' age 30 gender '男' ? 命令:setex ? key seconds value #設置鍵值及過期時間(秒單位) >setex age 100 20 #設置年齡的值為20,過期時間100秒
-
獲取鍵
命令:get key #獲取單個鍵 >get h1 ? 命令:mget key1 key2 key3 #獲取多個鍵 >mget name age sex
-
查看過期時間
命令:ttl key >ttl a1 #查看a1的過期時間
-
運算
原來的值必須是數值字符串 命令:incr key #將對應的key 加1 命令:decr key #將對應的key值減1 命令:incrby key num ? #將對應的key加指定值 命令:decrby key num ? #將對應的key的值減去指定值
-
其它操作
命令:append key value #追加值,redis中值都是字符串,追加就是字符拼接 >append name 'hello' #如果原來的值是tom,那么現在就是tomhello ? 命令:strlen key #獲取值得長度
4.2 hash
Redis hash 是一個鍵值(key=>value)對集合。Redis hash是一個string類型的field和value的映射表,hash特別適合用于存儲對象。每個 hash 可以存儲 2的32次方 -1 鍵值對(40多億)。存儲形式:
key = {name:'tom',age: 18}
-
設置值
命令:hset key field ? value #設置key所指對象的指定屬性的值 命令:hmset key field ? value [field value] #設置key所指對象的多個屬性值 命令:hsetnx key field value #當field字段不存在時 設置key所指對象的field屬性值 ? hset person name '二狗子' hmset person age 20 sex '男' hsetnx person maried '未婚'
-
獲取值
命令: hget key field #獲取key指定的對象的屬性值 命令: hmget key field [field] #獲取key指定對象的多個屬性值 命令: hgetall key ? #獲取key所指對象的所有屬性的名稱和值 命令: hkeys ? key ? #獲取key所指對象的所有屬性名 命令: hvals ? key ? #獲取key所指對象是的所有屬性值 命令: hlen key ? ? #獲取key所指對象的屬性個數
-
其它操作
命令:hincrby key ? field ? increment #為key所指對象的指定字段的整數值加上increment 命令:hincrbyfloat key field increment #為key所指對象的指定字段的實數值加上increment 命令:hexists key field #判斷當前的字段是否存在在(在返回1 否則返回0) 命令:hdel key field [field] #刪除字段和值
4.3 list
redis 列表是簡單的字符串列表,按照插入順序排序。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)。列表最多可存儲 2的32次方 - 1 元素 (4294967295, 每個列表可存儲40多億)。
常應用于:1、對數據量大的集合數據刪減 2、任務隊列
?
-
添加數據
命令:lpush key ? value [value] ? #頭部插入數據 命令:lpushx key value ? ? ? ? ? #如果列表存在則在列表頭部插入數據 命令:rpush key value [value] ? #在列表尾部添加數據 命令:rpushx key value ? ? ? ? ? #如果列表存在,則在尾部添加數據 命令:linsert key before|after value value #在指定值前或后插入數據 命令:lset key index value ? ? ? #設定指定索引元素的值 注意:索引的值從左邊開始,向右增加,左邊第一個是0,從右邊向左索引編號為:-1 -2...
-
獲取數據
命令:lpop key ? ? ? ? ? ? ? #左側出隊并返回出隊元素 命令:rpop key ? ? ? ? ? ? ? #右側出隊并返回出隊元素 命令:lindex key ? index ? #返回指定索引的值 命令:lrange key start end #返回存儲列表中的指定范圍的元素[start,end] 命令:lrem?key count value ? ? #從列表里移除前 count 次出現的值為 value 的元素count > 0: 從頭往尾移除值為 value 的元素。count < 0: 從尾往頭移除值為 value 的元素。count = 0: 移除所有值為 value 的元素。
-
其它操作
命令:llen key #獲取列表長度 命令:ltrim key start stop #裁剪列表 保留start到stop之間的元素,其它都刪除ltrime mylist -3 -1 #從索引為-3到-2的保留, 以外的全部刪除
4.4 set 無序的集合
Redis的Set是string類型的無序集合,元素具有唯一性 不重復。集合是通過哈希表實現的,所以添加,刪除,查找的復雜度都是O(1)。
常應用于:對兩個集合間的數據進行交集、并集、差集運算
-
添加元素
sadd key member [member] #添加多個元素
-
獲取元素
smembers key #獲取集合中所有的元素scard key #返回集合元素的個數srandmember key [count] #返回集合中隨機元素的值,可以返回count個
-
其它操作
spop key [count] #移除集合中隨機的count個元素,并返回 srem key member1 [member2] #移除集合中 一個或者 多個 成員 sismember key member #判斷元素是否在集合中 存在返回1 不在返回0
-
集合操作
求多個集合的交集: sinter key [key...] 求多個集合的差集 (注意比較順序):sdiff key [key...] 求 多個集合的并集: sunion key [key....]
4.5 zset 有序從大到小排序
Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員。不同的是每個元素都會關聯一個double類型的分數。redis正是通過分數來為集合中的成員進行從小到大的排序。zset的成員是唯一的,但分數(score)卻可以重復。
常應用于:排行榜
-
添加元素
zadd key score member [score member] #添加多個元素 zincrby key increment member #對指定的成員增加權重increment
-
獲取元素
zrange key start end #返回指定范圍的元素 zcard key #返回元素的個數 zcount key min max #返回有序集合中權重在min和max之間的元素的個數 zscore key member #返回有序集合中 member(元素) 的權重(score) zrange key start end withscores #返回當前key中 所有的權重(score)和元素(member)
4.6 數據庫切換
redis默認帶有16個數據庫,編號從0-15。進入redis后默認數據庫是0,可以使用select num進行切換 客戶端不顯示中文的處理:打開客戶端的時候添加參數:--raw redis-cli --raw
4.7 其他
keys * #查看所有的key keys u* #查以u開始的key keys n??? 查找以n為開頭長度為4個的key keys n 查找 包含 n 的所有的key支持的正則表達式: - h?llo 匹配第二位為任意的字符 - h*llo 匹配第二位為任意字符 0個 或多個 - h[ab]llo 匹配第二位為 a或者b的字符的key - hello 匹配第二位除了e字符以外的任意的key - h[a-z]llo 匹配第二位為a-z的小寫字母的keyexists key #判斷鍵是否存在 type key #查看key對應的value的類型 del key #刪除指定key expire key 10 #設置過期時間,秒 persist key #移除key的過期時間 rename key newkey #修改key的名稱(如果新的key的名字存在 則會把存在的key的值 覆蓋掉) randomkey #隨機返回一個 key move key db 將鍵移動到指定庫flushdb #清空當前庫所有key flushall #清空所有庫里的keyexit #退出redis客戶端 quit 退出客戶端查看服務器信息 info dbsize 當前庫中有多少key
?
五、redis備份和還原
redis支持持久化的方式有兩種:RDB和AOF
-
RDB備份
-
查看備份目錄
#1查看配置文件 cd /etc/redis vim redis.conf# 當后臺進程執行save出錯時,停止redis的寫入操作。 stop-writes-on-bgsave-error yes rdbcompression yes # 將rdb文件進行壓縮 rdbchecksum yes # 對rdb文件進行校驗 dbfilename dump.rdb # rdb文件命名 dir /var/lib/redis # rdb文件備份存儲目錄#使用命令查看 進入redis客戶端 127.0.0.1:6379> config get dir 1) "dir" 2) "/var/lib/redis" #備份目錄
-
備份
-
命令行下執行:redis-cli save 阻塞主進程
-
命令行下執行:redis-cli bgsave 不阻塞主進程
-
查看備份時間,命令行下執行 time redis-cli save
-
-
還原
-
只要將備份的dump.rdb文件覆蓋原來的文件就可以還原
-
-
六、主從復制
當數據量變得龐大的時候,讀寫分離還是很有必要的。同時避免一個redis服務宕機,導致應用宕機的情況,我們啟用sentinel(哨兵)服務,實現主從切換的功能。redis提供了一個master,多個slave的服務。
角色 | ip |
---|---|
master(主) | 10.20.100.186 |
slave(從) | 10.20.100.106 |
-
master主配置
sudo vim /etc/redis/redis.conf #找到# bind 127.0.0.1 修改為 bind 127.0.0.1 10.20.100.186#找到# requirepass 將其修改為 這是修改的是服務器遠程連接密碼 requirepass 123
-
slave從配置
bind 127.0.0.1 10.20.100.106 #10.20.100.106從服務器網絡地址 daemonize yes #是否是守護進程 slaveof 10.20.100.186 6379 #主服務器的ip和端口 masterauth 123 # 主服務器的密碼
重啟master和slave的服務,然后登錄從服務器,執行:
python@ubuntu:/etc/redis$ redis-cli -p 6380 -a 123 127.0.0.1:6380> info replication # Replication role:slave master_host:10.20.100.186 master_port:6379 master_link_status:up master_last_io_seconds_ago:0 master_sync_in_progress:0 slave_repl_offset:1444 slave_priority:100 slave_read_only:1 connected_slaves:0 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:1048576 repl_backlog_first_byte_offset:0 repl_backlog_histlen:0