編輯:關於Android編程
一直在使用redis,使用redis的一些簡單功能,
例如key-value的存儲一些數據,使用list記錄用戶的浏覽記錄的前100條數據,例如記錄書籍的浏覽次數
可以一直對redis沒有全面的了解,希望通過這篇博客,我能夠對redis做一個全面的總結,以後遇到redis相關的問題,能夠找到問題的解決方向。
Redis 是一個開源的使用 ANSI C 語言編寫、支持網絡、可基於內存亦可持久化的日志型、 Key-Value 數據庫,並提供多種語言的 API。
redis的類型
作為 Key-value 型數據庫,Redis 也提供了鍵(Key)和鍵值(Value)的映射關系。但是,除 了常規的數值或字符串,Redis 的鍵值還可以是以下形式之一:
string
Lists (列表)
Sets (集合)
Sorted sets (有序集合)
Hashes (哈希表)
redis的 連接
$redis = new Redis();
$host = "127.0.0.1";
$port = 6379;
$timeout = 5;
$redis->connect($host,$port,$timeout);
redis string的使用
原子操作,是每次操作都會使用一個鎖(信號量)之類的工具,其他的帶操作都加入待處理列表
//簡單的字符串操作
$key = "abc";
$val = "abcdefeag";
$key1 = "efg";
$val1 = "dddsdfasdfasdf";
//設置字符串
$redis->set($key,$val);
//設置字符串,如果key不存在
$redis->setnx($key,$val."abc123");
//$redis->set($key,$val."abc123");
//設置有效期3600秒
$redis->setex($key,3600,"axxxxooxoxoxxo");
//字符串的替換
$redis->setRange($key,12,"dddddd");
//一次給多個key賦值
$redis->mset(array($key=>$val,$key1=>$val1));
//設置新的值獲取舊的值
var_dump($redis->getSet($key,"axxxxooxoxoxxo"));
//片段獲取
var_dump($redis->getRange($key,0,5));
//追加
$redis->append($key,$val1);
var_dump($redis->get($key),$redis->get($key1));
//字符串的
$redis->set("view_book_1",100);
//原子增加
$redis->incr("view_book_1");var_dump($redis->get("view_book_1"));
$redis->incrBy("view_book_1",100);var_dump($redis->get("view_book_1"));
//原子減少
$redis->decr("view_book_1");var_dump($redis->get("view_book_1"));
$redis->decrBy("view_book_1",100);var_dump($redis->get("view_book_1"));
//字符串長度
var_dump($redis->strlen($key));
//刪除
$redis->del($key);
redis hash的使用
hash可以用於存儲一系列的數據,比如一本書的所有信息,一條微博的所有信息,
//hash串的基本操作
$key = "myhash";
//hash的設置
$redis->hSet($key,"id",12);
//如果不存在才設置
$redis->hSetNx($key,"id",13);
//批量設置
$redis->hMset($key,array("title"=>"入夢師","author"=>"八重櫻妖"));
$redis->hSet($key,"views",12);
//自增
$redis->hIncrBy($key,"views",1);
//判斷key是否存在
var_dump($redis->hExists($key,"title"));
//keys 的長度
var_dump($redis->hLen($key));
//刪除對應的字段
var_dump($redis->hDel($key,"views"));
//獲取鍵列表,獲取值列表
var_dump($redis->hKeys($key),$redis->hVals($key));
//批量獲取數據
var_dump($redis->hMget($key,array("title","author")));
//獲取單個數據
var_dump($redis->hGet($key,"id"));
//獲取所有數據
var_dump($redis->hGetAll($key));
redis list的使用
咱們可以理解成數據結構裡面的鏈表
$kl ="mylist";
//左(右)邊入隊列,左(右)邊入隊列
$redis->rPush($kl,"hello");
//$redis->rPop($kl);
$redis->lPush($kl,"php");
//$redis->lPop($kl);
$redis->rPushx($kl,"hello");
$redis->rPop($kl);
//設置0上的數據
$redis->lSet($kl,0,"c++");
//獲取0上的數據
var_dump($redis->lGet($kl,0));
//刪除數據
$redis->lrem($kl,"hello",1);
//截取數據
$redis->ltrim($kl,1,2);
var_dump($redis->lSize($kl),$redis->lrange($kl,0,-1));
$redis->del($kl);
redis set的使用
//set 不重復的集合
$sk = "myset";
//添加
$redis->sAdd($sk,12);
$redis->sAdd($sk,12);
$redis->sAdd($sk,13);
$redis->sAdd($sk,14);
//刪除
$redis->sRemove($sk,13);
//
$sk2 = "myset2";
$redis->sAdd($sk2,13);
$redis->sAdd($sk2,14);
$redis->sAdd($sk2,15);
//隨機返回一個元素
var_dump($redis->sRandMember($sk2));
//是否是裡面的數據
var_dump("contain#",$redis->sContains($sk,12));
//排序獲取數據
var_dump($redis->sSize($sk),$redis->sort($sk,array(
'sort'=>'desc',
)));
//交集
var_dump($redis->sInter($sk,$sk2));
//並集
var_dump($redis->sUnion($sk,$sk2));
//差集
var_dump($redis->sDiff($sk,$sk2));
var_dump($redis->sDiff($sk2,$sk));
$redis->del($sk);
$redis->del($sk2);
redis sorted set的使用
//zset
$key = "zs";
//添加元素,分數不能相同
$redis->zAdd($key,75,"php");
$redis->zAdd($key,85,"java");
$redis->zAdd($key,75,"c++");
$redis->zAdd($key,80,"c#");
$redis->zDelete($key,"c#");
//顯示元素
var_dump($redis->zRange($key,0,-1));
var_dump($redis->zRange($key,0,-1,true));
//zrangebyscore 可以用來分頁
var_dump($redis->zrangebyscore($key,1,100,array('limit' => array(1, 1),'withscores' => TRUE)));
//數據的數量
var_dump($redis->zCount($key,1,100));
//返回分數
var_dump($redis->zScore($key,"php"));
//加分
$redis->zIncrBy($key, 3, 'php');
var_dump($redis->zRange($key,0,-1,true));
//返回排名值
var_dump($redis->zRank($key,"php"),$redis->zRank($key,"c++"));
$key1 = "zs2";
$redis->zAdd($key1,75,"php");
$redis->zAdd($key1,85,"java1");
$redis->zAdd($key1,75,"c++1");
$redis->zAdd($key1,80,"c#1");
$redis->zDelete($key1,"c#1");
//交集,分數相加
var_dump("##",$redis->zInter("keynew",array($key,$key1)));
var_dump($redis->zRange("keynew",0,-1,true));
//並集
var_dump("##",$redis->zUnion("keynew2",array($key,$key1)));
var_dump($redis->zRange("keynew2",0,-1,true));
$redis->del($key);
$redis->del($key1);
$redis->del("keynew2");
$redis->close();
redis 使用場景
一切可以使用string,list,set ,sorted sets hash的地方都可以用到redis,關鍵是你得取捨,你的取捨就是了解redis的優缺點,你業務的特性啦
redis的數據持久化
所實話我沒有看過redis源碼,以下內容來自網絡。如果大家向我一樣,c語言不好,可以看看《redis的設計和實現》這本書
通常,Redis 將數據存儲於內存中,或被配置為使用虛擬內存。通過兩種方式可以實現數據 持久化:
使用截圖的方式,將內存中的數據不斷寫入磁盤;
或使用類似 MySQL 的日志方式, 記錄每次更新的日志。
前者性能較高,但是可能會引起一定程度的數據丟失;後者相反。
redis的數據持久化有兩種方式:
一種是 Snapshotting(快照)也是默認方式
一種是 Append-only file(縮寫 aof)的方式。下面分別介紹:
redis快照的處理過程
快照是默認的持久化方式。這種方式是就是將內存中數據以快照的方式寫入到二進制文件中, 默認的文件名為 dump.rdb。可以通過配置設置自動做快照持久化的方式。我們可以配置 redis 在 n 秒內如果超過 m 個 key 被修改就自動做快照,下面是默認的快照保存配置
save 900 1 #900 秒內如果超過 1 個 key 被修改,則發起快照保存
快照保存過程
1.redis 調用 fork,現在有了子進程和父進程。
2. 父進程繼續處理 client 請求,子進程負責將內存內容寫入到臨時文件。由於 os 的實時復 制機制(copy on write)父子進程會共享相同的物理頁面,當父進程處理寫請求時 os 會為父 進程要修改的頁面創建副本,而不是寫共享的頁面。所以子進程地址空間內的數據是 fork時刻整個數據庫的一個快照。
3.當子進程將快照寫入臨時文件完畢後,用臨時文件替換原來的快照文件,然後子進程退出
client 也可以使用 save 或者 bgsave 命令通知 redis 做一次快照持久化。save 操作是在主線程 中保存快照的,由於 redis 是用一個主線程來處理所有 client 的請求,這種方式會阻塞所有 client 請求。所以不推薦使用。另一點需要注意的是,每次快照持久化都是將內存數據完整 寫入到磁盤一次,並不是增量的只同步變更數據。如果數據量大的話,而且寫操作比較多, 必然會引起大量的磁盤 io 操作,可能會嚴重影響性能。
aof 方式
另外由於快照方式是在一定間隔時間做一次的,所以如果 redis 意外 down 掉的話,就會丟 失最後一次快照後的所有修改。如果應用要求不能丟失任何修改的話,可以采用 aof 持久化 方式。
aof 比快照方式有更好的持久化性,是由於在使用 aof 持久化方式時,redis 會將每一個收到 的寫命令都通過 write 函數追加到文件中(默認是 appendonly.aof)。當 redis 重啟時會通過重 新執行文件中保存的寫命令來在內存中重建整個數據庫的內容。當然由於 os 會在內核中緩 存 write 做的修改,所以可能不是立即寫到磁盤上。這樣 aof 方式的持久化也還是有可能會 丟失部分修改。不過我們可以通過配置文件告訴 redis 我們想要通過 fsync 函數強制 os 寫入 到磁盤的時機。有三種方式如下(默認是:每秒 fsync 一次)
appendonly yes //啟用 aof 持久化方式
# appendfsync always //收到寫命令就立即寫入磁盤,最慢,但是保證完全的持久化
#appendfsync everysec //每秒鐘寫入磁盤一次,在性能和持久化方面做了很好的折中
# appendfsync no //完全依賴 os,性能最好,持久化沒保證
aof可能帶來的問題
aof 的方式也同時帶來了另一個問題。持久化文件會變的越來越大
bgrewriteaof 處理大文件問題
為了壓縮 aof 的持久化文件。redis 提 供了 bgrewriteaof 命令。收到此命令 redis 將使用與快照類似的方式將內存 中的數據以命令 的方式保存到臨時文件中,最後替換原來的文件。具體過程如下
1、redis 調用 fork ,現在有父子兩個進程
2、子進程根據內存中的數據庫快照,往臨時文件中寫入重建數據庫狀態的命令
3、父進程繼續處理 client 請求,除了把寫命令寫入到原來的 aof 文件中。同時把收到的寫命 令緩存起來。這樣就能保證如果子進程重寫失敗的話並不會出問題。
4、當子進程把快照內容寫入已命令方式寫到臨時文件中後,子進程發信號通知父進程。然 後父進程把緩存的寫命令也寫入到臨時文件。
5、現在父進程可以使用臨時文件替換老的 aof 文件,並重命名,後面收到的寫命令也開始 往新的 aof 文件中追加。
redis的安全
redis可以設置成需要auth才能進行操作
redis的主從同步
配置好 slave 後,slave 與 master 建立連接,然後發送 sync 命令。無論是第一次連接還是重新連接,master 都會啟動一個後台進程,將數據庫快照保存到文件中,同時 master 主進 程會開始收集新的寫命令並緩存。後台進程完成寫文件後,master 就發送文件給 slave,slave 將文件保存到硬盤上,再加載到內存中,接著 master 就會把緩存的命令轉發給 slave,後續 master 將收到的寫命令發送給 slave。如果 master 同時收到多個 slave 發來的同步連接命令, master 只會啟動一個進程來寫數據庫鏡像,然後發送給所有的 slave。
redis支持簡單的事務
如題
消息的訂閱和發布
發布訂閱(pub/sub)是一種消息通信模式,主要的目的是解耦消息發布者和消息訂閱者之間的 耦合,這點和設計模式中的觀察者模式比較相似。pub/sub 不僅僅解決發布者和訂閱者直接 代碼級別耦合也解決兩者在物理部署上的耦合。redis 作為一個 pub/sub 的 server,在訂閱者 和發布者之間起到了消息路由的功能。訂閱者可以通過 subscribe 和 psubscribe 命令向 redis server 訂閱自己感興趣的消息類型,redis 將消息類型稱為通道(channel)。當發布者通過 publish 命令向 redis server 發送特定類型的消息時。訂閱該消息類型的全部 client 都會收到 此消息。這裡消息的傳遞是多對多的。一個 client 可以訂閱多個 channel,也可以向多個 channel 發送消息。
redis相當於路由器,起到了消息中轉的作用
picasso是Square公司開源的一個Android圖形緩存庫,地址http://square.github.io/picasso/,可以實現圖片下載和緩存功能。僅僅
這篇文章主要和大家一起動手編寫Android圖片加載框架,從內部原理到具體實現來詳細介紹如何開發一個簡潔而實用的Android圖片加載緩存框架,感興趣的小伙伴們可以參考一
平台: Wind7_64 + Ubuntu12_04_64 + VMware 這裡以Android5.0為例: Android5.0 可以到這
前言:好幾天電腦打不開CSDN博客,也不知道怎麼回事,今天下班回來突然能打開了,遂將周末實現的一個效果貼上。實現功能:獲取手機應用圖標,名稱,時間(安裝時間/更新時間),