存檔

‘redis’ 分類的存檔

Redis協議詳細規范

2019年6月29日 沒有評論

Redis客戶端和服務器端通信使用名為 RESP (REdis Serialization Protocol) 的協議。雖然這個協議是專門為Redis設計的,它也可以用在其它 client-server 通信模式的軟件上。

RESP 是下面條件的折中:

  • 實現起來簡單。
  • 解析速度快。
  • 有可讀性。

RESP 能序列化不同的數據類型,例如整型(integers)、字符串(strings)、數組(arrays)。額外還有特殊的錯誤類型。請求從客戶端以字符串數組的形式發送到redis服務器,這些字符串表示要執行的命令的參數。Redis用特定于命令的數據類型回復。

RESP 是二進制安全的,并且不需要處理從一個進程發到另外一個進程的批量數據,因為它使用前綴長度來傳輸批量數據。 注意:這里概述的協議僅用于客戶機-服務器通信。Redis集群使用不同的二進制協議在節點之間交換消息。

網絡層

連到Redis服務器的客戶端建立了一個到6379端口的TCP連接。

雖然RESP在技術上不特定于TCP,但是在Redis的上下文中,該協議僅用于TCP連接(或類似的面向流的連接,如unix套接字)。

請求-響應模型

Redis接受由不同參數組成的命令。一旦收到命令,就會對其進行處理,并將應答發送回客戶端。

這是最簡單的模型,但是有兩個例外:

  • Redis 支持管道pipelining。所以,客戶端可以一次發送多個命令,然后再等待應答。
  • 當一個Redis客戶端訂閱一個頻道,那么協議會改變語義并變成pushprotocol, 也就是說,客戶客戶端不再需要發送命令,因為服務器端會一收到新消息,就會自動發送給客戶端。

除了上面兩個例外情況,Redis協議是一個簡單的請求-響應協議。

RESP 協議解釋

RESP 協議在Redis1.2被引入,直到Redis2.0才成為和Redis服務器通信的標準。這個協議需要在你的Redis客戶端實現。

RESP 是一個支持多種數據類型的序列化協議:簡單字符串(Simple Strings),錯誤( Errors),整型( Integers), 大容量字符串(Bulk Strings)和數組(Arrays)。

RESP在Redis中作為一個請求-響應協議以如下方式使用:

  • 客戶端以大容量字符串RESP數組的方式發送命令給服務器端。
  • 服務器端根據命令的具體實現返回某一種RESP數據類型。

在 RESP 中,數據的類型依賴于首字節:

  • 簡單字符串(Simple Strings): 響應的首字節是 “+”
  • 錯誤(Errors): 響應的首字節是 “-“
  • 整型(Integers): 響應的首字節是 “:”
  • 大容量字符串(Bulk Strings): 響應的首字節是“$”
  • 數組(Arrays): 響應的首字節是 “*

另外,RESP可以使用大容量字符串或者數組類型的特殊變量表示空值,下面會具體解釋。RESP協議的不同部分總是以 “\r\n” (CRLF) 結束。

RESP 簡單字符串

簡單字符串編碼方法: 加號后面跟著一個不包含回車或換行字符的字符串 (不允許出現換行),以CRLF(“\r\n”)結尾。

簡單字符串通常被用來傳輸非二進制安全字符串并且消耗極小。例如,許多redis命令在成功時回復“OK”,即簡單字符串用以下5個字節編碼:

"+OK\r\n"

為了發送二進制安全的字符串,需要使用RESP的大容量字符串(Bulk Strings)替代。

當Redis返回簡單字符串(Simple String)時,客戶端lib應該返回去掉首字符加號和結尾CRLF字符的字符串給調用者。

RESP Errors

RESP 有特殊類型來處理錯誤。errors類型除了首字符是減號 ‘-‘不是加號以外,其它跟簡單字符串一樣。RESP中簡單字符和錯誤的真正區別是:錯誤被客戶端當作異常處理,組成錯誤類型的字符串是錯誤消息自身。

基本格式如下:

"-Error message\r\n"

錯誤應答只在發生異常時發送,例如,要執行命令的參數數據類型不匹配或者命令不存在等。當收到錯誤返回時,客戶端lib應該拋出一個異常。

錯誤返回例子:

-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value

從”-“后面第一個單詞起,直到第一個空格或者換行,表示返回的錯誤類型。這是Redis的一種約定,并不是RESP協議的要求。

ERR 是一個通用錯誤, 而 WRONGTYPE 是表示更具體的錯誤,意味著客戶端在錯誤的數據類型上執行操作。這被叫做錯誤前綴(Error Prefix), 使客戶端不用依賴具體錯誤消息就知道返回的錯誤類型,錯誤消息可能會隨著時間而變化。

客戶端實現可能會對不同異常返回不同類型的錯誤,或者可能提供一種通用的方式來捕獲錯誤,通過以字符串的形式直接返回錯誤名給調用者。

盡管如此,這種特性不能認為很重要,因為它很少被使用。一小部分客戶端的實現可能會返回通用錯誤條件,例如false。

RESP 整型

整型類型是由以冒號開頭,CRLF結尾,中間是字符串形式表示的數字。 例如 “:0\r\n”, 或 “:1000\r\n” 都是整型回復。

很多Redis命令返回RESP整數,像 INCRLLEN 和 LASTSAVE.

返回的整數并沒有特別的意義, INCR 返回的是一個遞增的數字, LASTSAVE 返回的是Unix時間戳等。返回的整數有效值需要在有符號64位整數范圍內。

整型返回也被廣泛的用來返回 true 或 false。比如 EXISTS 或 SISMEMBER 命令返回1表示true,返回0表示false。

其它命令像 SADDSREM 和 SETNX 如果操作被執行則返回1,否則返回0。

返回整型回復的命令: SETNXDELEXISTSINCRINCRBYDECRDECRBYDBSIZELASTSAVERENAMENXMOVELLENSADDSREMSISMEMBERSCARD.

RESP 大容量字符串

大容量字符串被用來表示最大512MB長的二進制安全字符串。

大容量字符串編碼方式:

  • 美元符 “$” 后面跟著組成字符串的字節數(前綴長度),并以 CRLF 結尾。
  • 實際的字符串數據。
  • 結尾是 CRLF。

所以,字符串 “foobar” 編碼如下:

"$6\r\nfoobar\r\n"

空字符串編碼格式:

"$0\r\n\r\n"

RESP 大容量字符串(Bulk Strings) 也可以使用一個特殊的用來表示空值的格式表示不存在的值。在這種格式里長度值為-1,數據部分不存在,所以空(Null)用如下方式表示:

"$-1\r\n"

叫做空的大容量字符串Null Bulk String。

客戶端API庫不應該返回空串,當服務器端響應一個空的大容量字符串時,API庫可以返回一個空對象給調用者。例如,Ruby庫應該返回 ‘nil’ ,而C庫應該返回NULL。 

RESP 數組

客戶端使用 RESP 數組發送命令到 Redis 服務端。同樣地,某些使用 RESP 數組返回元素集合給客戶端的 Redis 命令是應答類型。 LRANGE 命令返回元素列表就是一個例子。

RESP 數組使用如下格式發送:

  • 以星號* 為首字符,接著是表示數組中元素個數的十進制數,最后以 CRLF 結尾。
  • 外加數組中每個 RESP 類型的元素。

空數組表示:

"*0\r\n"

有兩個 RESP 大容量字符串”foo” 和”bar”元素的 RESP 數組 :

"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

在前綴 *<count>CRLF 的后面,組成數組的其它數據類型一個接在另一個后面。 例如包含三個整數的數組編碼方式:

"*3\r\n:1\r\n:2\r\n:3\r\n"

數組可以包含混合類型,不一定必須是同一種類型。例如,4個整型和1個大容量字符串編碼方式:

*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n

(為了方便閱讀,應答分成多行來展示)

第一個行表示 *5\r\n 說明后面有5個應答。這些應答組成一個大的應答一起發送。

空數組的概念也是存在的,另一個表示空值的方式(通常使用大容量空字符串,歷史遺留導致有這兩種格式)。

例如,當 BLPOP 命令超時,它會返回一個空數組,數組的計數器是-1 :

"*-1\r\n"

當 Redis 返回一個空數組的時候,Redis客戶端庫API應該返回一個空對象而不是返回一個空數組。 這對區分空列表和其它不同情況(像 BLPOP 命令超時情況)是必要的。

數組的數組也是可行的。例如,一個含有兩個數組元素的數組編碼方式:

*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n

(為了方便閱讀,分成多行來展示).

上面的 RESP 數據類型包含兩個數組,一個數組包含三個整數1, 2, 3 ,另一個是簡單字符串和一個錯誤類型。

數組中的空元素

數組中可以有為空的元素。主要使用在Redis應答中,為了表示這個元素丟失并且不是一個空的字符串。當SORT命令使用GET 模式選項,并且特定的key丟失的時會出現這種應答。 含有有空元素的應答數組例子:

*3\r\n
$3\r\n
foo\r\n
$-1\r\n
$3\r\n
bar\r\n

第二個元素是空,客戶端庫應該返回像下面這樣的數據:

["foo",nil,"bar"]

這不是前面提到的異常情況,這只是說明協議的一個例子。

發送命令到Redis服務器

至此,我們已經很熟悉RESP序列化格式,寫一個Redis客戶端庫的實現會變得很容易。我們可以進一步說明客戶端和服務端如何交互工作:

  • 客戶端發送包含只有大容量字符串的數組給Redis服務器。
  • Redis 服務器給客戶端發送任意有效的 RESP 數據類型作為應答。

下面是一個典型的交互過程例子:

客戶端發送命令 LLEN mylist 來獲取存儲在 mylist 鍵中列表的長讀,然后服務器端返回整數應答(C: 代表客戶端, S: 代表服務器端).

C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n

S: :48293\r\n

為了方便理解我們用換行把協議分成不同部分,實際上客戶端發送的是一個整體沒有換行:*2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n as a whole.

管道和多個命令

客戶端可以使用同一個連接發送多個命令。通過管道客戶端可以一次寫操作發送多個命令,發送下一個命令前不需要等待前一個命令的應答。所有應答可以在最后被讀取。

關于管道詳細參考 page about Pipelining.

內聯命令

有時你手邊只能操作telnet 并且需要給Redis 服務器端發送命令。雖然Redis協議是容易實現的,但并不適合用在交互會話。redis-cli 也不是隨時都能可用。因此,redis還以一種特殊的方式接受為人類設計的命令,稱為內聯命令格式。 以下是使用內聯命令進行服務器/客戶端聊天的示例(服務器聊天以s開頭,客戶端聊天以c開頭)。

C: PING
S: +PONG

以下是返回整數的內聯命令的另一個示例:

C: EXISTS somekey
S: :0

基本上,您只需在telnet會話中編寫空格分隔的參數。由于統一請求協議中沒有以*開頭的命令,因此Redis能夠檢測到這種情況并解析您的命令。

Redis 協議的高性能解析器

雖然redis協議是非常容易被人閱讀和實現的,但是它可以以類似于二進制協議的性能來實現。

RESP 使用帶前綴的長度來傳輸批量數據,因此不需要像使用json那樣掃描有效負載以查找特殊字符,也不需要引用需要發送到服務器的有效負載。

批量和多批量長度可以使用代碼進行處理,代碼對每個字符執行單個操作,同時掃描CR字符,如以下C代碼:

RESP 使用帶前綴的長度來傳輸大容量數據,因此不需要像使用json那樣掃描有效負載以查找特殊字符,也不需要引用需要發送到服務器的有效負載。

大容量和多個大容量長度可以使用代碼進行處理,代碼對每個字符執行單個操作,同時掃描CR字符,如以下C代碼:

#include <stdio.h>

int main(void) {
    unsigned char *p = "$123\r\n";
    int len = 0;

    p++;
    while(*p != '\r') {
        len = (len*10)+(*p - '0');
        p++;
    }

    /* Now p points at '\r', and the len is in bulk_len. */
    printf("%d\n", len);
    return 0;
}

在識別出第一個CR之后,可以跳過它和下面的LF,而不需要任何處理。然后,可以使用不以任何方式檢查有效負載的單個讀取操作讀取大容量數據。最后,剩余的CR和LF字符將被丟棄,而不進行任何處理。

Redis協議有著與二進制協議可比的性能,更重要的是易于在大多數高級語言中實現,從而減少了客戶端軟件中的錯誤數量。

分類: redis 標簽:

redis常用命令

2015年1月9日 2 條評論

1. redis查看當前所有的key

2. 查看當前redis的配置信息

3. MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error.

強制停止redis快照導致,redis運行用戶沒有權限寫rdb文件或者磁盤空間滿了,解決辦法:

例如:

閱讀全文...

分類: redis 標簽: ,

動態更新運行中程序的配置信息

2014年10月18日 3 條評論

一個程序投產線上使用基本不會停下來,一旦業務需求改變或者增加需求,需要修改配置文件時,往往需要停機修改配置后重新啟動服務。

這個過程進程少還可以接受,如果停一次機要很長時間而且需要授權更新,這個是難以接受的方法。

想了幾個辦法
1.放到內存,例如redis這種字典,這樣可以動態修改redis的值來實現動態更新,問題是如何保證redis出問題不影響原程序呢?
重redis里讀到map,如果需要的配置不在,到內存里去讀,這樣只能增加配置,想要刪除配置好像不理想。

2.定時load配置文件,

3.通過信號load,

2.和3.不好協調多個進程服務一致性問題。

真傷腦筋啊。

有人知道好方法,告訴我一下。

memcache和redis區別

2014年4月27日 沒有評論

memcache官方定義

Free & open source, high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load.

redis官方定義
Redis is an open source, BSD licensed, advanced key-value store. It is often referred to as a data structure server since keys can contain strings, hashes, lists, sets and sorted sets.

版權相同

它們都是使用的bsd協議,使用它的項目可以用于商業用戶,不必發布二次修改的代碼,可以修改源代碼。

數據類型

redis數據類型豐富,支持set liset等類型
memcache支持簡單數據類型,需要客戶端自己處理復雜對象

持久性

redis支持數據落地持久化存儲
memcache不支持數據持久存儲

分布式存儲

redis支持master-slave復制模式
memcache可以使用一致性hash做分布式

value大小不同

memcache是一個內存緩存,key的長度小于250字符,單個item存儲要小于1M,不適合虛擬機使用

數據一致性不同

redis使用的是單線程模型,保證了數據按順序提交。
memcache需要使用cas保證數據一致性。CAS(Check and Set)是一個確保并發一致性的機制,屬于“樂觀鎖”范疇;原理很簡單:拿版本號,操作,對比版本號,如果一致就操作,不一致就放棄任何操作

cpu利用

redis單線程模型只能使用一個cpu,可以開啟多個redis進程

參考

http://www.cnblogs.com/qunshu/p/3196972.html
http://www.blogjava.net/chhbjh/archive/2012/02/21/370472.html
http://maoyidao.iteye.com/blog/1846089

分類: redis 標簽: ,

redis和redis php擴展安裝

2013年5月29日 1 條評論

redis是一個內存數據庫,比memcache支持更豐富的value類型,新浪微博就使用redis來做緩存。

redis的源碼安裝

1.make時可能會報如下錯誤:

解決辦法:
編輯src/.make-settings里的OPT,改為OPT=-O2 -march=i686。

2.make test報錯:

解決辦法安裝tcl

redis命令介紹

Redis 由四個可執行文件:redis-benchmark、redis-cli、redis-server、redis-stat 這四個文件,加上一個redis.conf就構成了整個redis的最終可用包。它們的作用如下:

redis-server:Redis服務器的daemon啟動程序
redis-cli:Redis命令行操作工具。當然,你也可以用telnet根據其純文本協議來操作
redis-benchmark:Redis性能測試工具,測試Redis在你的系統及你的配置下的讀寫性能
redis-stat:Redis狀態檢測工具,可以檢測Redis當前狀態參數及延遲狀況
現在就可以啟動redis了,redis只有一個啟動參數,就是他的配置文件路徑。

啟動redis

復制源碼包里的redis.conf到/etc
# cd redis-stable
# cp redis.conf /etc/redis.conf

編輯/etc/redis.conf ,修改
daemaon no 為daemaon yes ,以守護進程方式啟動進程。

# redis-server /etc/redis.conf

關閉redis
# redis-cli shutdown //關閉所有
關閉某個端口上的redis
# redis-cli -p 6397 shutdown //關閉6397端口的redis
說明:關閉以后緩存數據會自動dump到硬盤上,硬盤地址見redis.conf中的dbfilename dump.rdb

redis配置

注意,默認復制過去的redis.conf文件的daemonize參數為no,所以redis不會在后臺運行,這時要測試,我們需要重新開一個終端。修改為yes則為后臺運行redis。另外配置文件中規定了pid文件,log文件和數據文件的地址,如果有需要先修改,默認log信息定向到stdout.

下面是redis.conf的主要配置參數的意義:

daemonize:是否以后臺daemon方式運行
pidfile:pid文件位置
port:監聽的端口號
timeout:請求超時時間
loglevel:log信息級別
logfile:log文件位置
databases:開啟數據庫的數量
save * *:保存快照的頻率,第一個*表示多長時間,第三個*表示執行多少次寫操作。在一定時間內執行一定數量的寫操作時,自動保存快照。可設置多個條件。
rdbcompression:是否使用壓縮
dbfilename:數據快照文件名(只是文件名,不包括目錄)
dir:數據快照的保存目錄(這個是目錄)
appendonly:是否開啟appendonlylog,開啟的話每次寫操作會記一條log,這會提高數據抗風險能力,但影響效率。
appendfsync:appendonlylog如何同步到磁盤(三個選項,分別是每次寫都強制調用fsync、每秒啟用一次fsync、不調用fsync等待系統自己同步)
這時你可以打開一個終端進行測試了,配置文件中默認的監聽端口是6379

redis開機自動啟動

用這個腳本管理之前,需要先配置下面的內核參數,否則Redis腳本在重啟或停止redis時,將會報錯,并且不能自動在停止服務前同步數據到磁盤上:

# vi /etc/sysctl.conf

vm.overcommit_memory = 1

然后應用生效:

# sysctl –p

建立redis啟動腳本:

# vim /etc/init.d/redis

然后增加服務并開機自啟動:

redis php擴展安裝

wget https://github.com/nicolasff/phpredis/zipball/master -O php-redis.zip
unzip php-redis.zip
cd nicolasff-phpredis-2d0f29b/
/usr/local/php/bin/phpize
./configure --with-php-config=/usr/local/php/bin/php-config
make && make install

完成后redis.so被安裝到
/usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/

vi /usr/local/php/lib/php.ini

添加
extension=redis.so

重啟php-fpm即可。

configure時可能會遇到,添加--with-php-config參數可以解決。

configure: error: Cannot find php-config. Please use --with-php-config=PATH

./configure --with-php-config=/usr/local/php/bin/php-config

分類: redis 標簽: , , ,
网球冠军