一步一步学习redis3.2.8

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了一步一步学习redis3.2.8相关的知识,希望对你有一定的参考价值。

一步一步学习redis3.2.8

1、redis安装

官网地址为:https://redis.io/download

$ wget http://download.redis.io/releases/redis-3.2.8.tar.gz

$ tar xzf redis-3.2.8.tar.gz

$ cd redis-3.2.8

$ make


启动服务

$ src/redis-server

redis-server /root/soft/redis/sbin/redis.conf &


查看进程

ps -ef | grep 6379


交互式命令

$ src/redis-cli

redis> set foo bar

OK

redis> get foo

"bar"


bgsave  命令持久化数据到磁盘


或者

[[email protected] redis]# redis-cli set id 1

OK

[[email protected] redis]# redis-cli get id

"1"


redis-cli  -h 192.168.175.29 -p 6379


2、redis.conf配置文件

#bind 127.0.0.1


关闭保护模式 远程可以连接

protected-mode no


port 6379


日志隔离级别

loglevel notice


#log文件名称

logfile "mylog.txt"


默认数据库个数

databases 16


#   In the example below the behaviour will be to save:

#   after 900 sec (15 min) if at least 1 key changed

#   after 300 sec (5 min) if at least 10 keys changed

#   after 60 sec if at least 10000 keys changed


快照

save 900 1

save 300 10

save 60 10000


#DB文件名字

# The filename where to dump the DB

dbfilename dump.rdb


#目录

# Note that you must specify a directory here, not a file name.

dir /root/soft/redis/sbin/db

3、String 结构

Java String

C#   String   => char[]的封装。。。

Redis C语言实现  char[] 进行了封装。。。   append,length,substring,set, 

        get。。。。setrange => replace...


二: 最常用命令。。。

官网学习地址 http://www.redis.cn/documentation.html  翻译比较全,比较新


《1》 set/get 命令    [对string进行赋值]  时间复杂度:O(1)

SET key value [EX seconds] [PX milliseconds] [NX|XX]

GET key   【nil】 =>lua 


应用场景分布式锁。。。。【zookeeper】 相对来说重量级。

通过对username的赋值的返回值来判断是否获取到了一个分布式锁。。。

set username jack NX =》 如果返回ok,说明获得到了锁。。。

set username mary NX =》 如果返回nil,说明没有获取到锁。。。

《2》 Incr,Decr,    =>自增或者自减1     【 i++, i-- 】

127.0.0.1:6379> set mykey "10"

OK

127.0.0.1:6379> object encoding mykey

"int"

127.0.0.1:6379> 

127.0.0.1:6379> incr mykey

(integer) 11

127.0.0.1:6379> get mykey

"11"


127.0.0.1:6379> get mykey

"11"

127.0.0.1:6379> 

127.0.0.1:6379> decr mykey 

(integer) 10

127.0.0.1:6379> get mykey

"10"


IncrBy,DecrBy =>自增或者自减去指定的值 【 i=i + xx,  i=i - xx 】

127.0.0.1:6379> get mykey

"10"

127.0.0.1:6379> incrby mykey 6

(integer) 16

127.0.0.1:6379> get mykey

"16"


127.0.0.1:6379> get mykey

"16"

127.0.0.1:6379> decrby mykey 9

(integer) 7

127.0.0.1:6379> get mykey

"7"

127.0.0.1:6379> 


Redis中的String不是string类型。。。   如果存放到string中的value是int,那么其实在内

        部还是用int的。。。

从encoding可以看出。。。       


RedisObject中有一个type属性,

有一个encoding属性。。。

有一个ptr属性。 => SDS


查看类型 OBJECT ENCODING

127.0.0.1:6379> object encoding username

"embstr"


127.0.0.1:6379> set mykey "10"

OK

127.0.0.1:6379> object encoding mykey

"int"

从一个简单的String类型中,我们发现有int,embstr.... 【性能优化】

三、String过期操作

一:String 过期操作  一些 工具函数

Redis  单线程的内存字典服务器。。。 过期时间  =》 [mamcache]  kv结构。

SET key value [EX seconds] [PX milliseconds] [NX|XX]

缓存,和memcache做一样的功能。。。

ttl username 用于查看当前还剩多少秒。。。 NativeCache


EX seconds – Set the specified expire time, in seconds.

PX milliseconds – Set the specified expire time, in milliseconds.

NX – Only set the key if it does not already exist.

XX – Only set the key if it already exist.

EX seconds – 设置键key的过期时间,单位时秒

PX milliseconds – 设置键key的过期时间,单位时毫秒

NX – 只有键key不存在的时候才会设置key的值

XX – 只有键key存在的时候才会设置key的值


设置一个key mykey1值为"hello" 过期时间为5s

127.0.0.1:6379> set mykey1 "hello" ex 5

OK

127.0.0.1:6379> get mykey1

"hello"

查看用于查看当前还剩多少秒

127.0.0.1:6379> set mykey1 "hello" ex 5

OK

127.0.0.1:6379> ttl mykey1

(integer) 4


PSETEX key milliseconds value  《=》 Set key value [PX milliseconds]  

PSETEX和SETEX一样,唯一的区别是到期时间以毫秒为单位,而不是秒


127.0.0.1:6379> PSETEX mykey 10000 "Hello"

OK

127.0.0.1:6379> get mykey

"Hello"

127.0.0.1:6379> pttl mykey

(integer) 2189


SETEX key seconds value   《=》   Set key value [EX seconds]


127.0.0.1:6379> setex mykey 10 "hello"

OK

127.0.0.1:6379> get mykey

"hello"

一样用法 


二:String  

1. len => StrLen   时间复杂度:O(1)

返回key的string类型value的长度。如果key对应的非string类型,就返回错误

127.0.0.1:6379> set mykey "abcdef"

OK

127.0.0.1:6379> get mykey

"abcdef"

127.0.0.1:6379> STRLEN mykey

(integer) 6


2. substring => GetRange   => getRange username 0 2

时间复杂度:O(N) N是字符串长度,复杂度由最终返回长度决定,但由于通过一个字符串创建

        子字符串是很容易的,它可以被认为是O(1)。

127.0.0.1:6379>  SET mykey "This is a string"

OK

127.0.0.1:6379> getrange mykey 0 3

"This"

127.0.0.1:6379> 

127.0.0.1:6379> 

127.0.0.1:6379> getrange mykey -3 -1

"ing"

127.0.0.1:6379> getrange mykey 0 -1

"This is a string"

127.0.0.1:6379> getrange mykey 10 100

"string"

127.0.0.1:6379> 


3. replace => SetRange 



SETRANGE key offset value  => 

127.0.0.1:6379> SET key1 "Hello World"

OK

127.0.0.1:6379> SETRANGE key1 6 "Redis"

(integer) 11

127.0.0.1:6379> 

127.0.0.1:6379> get key1

"Hello Redis"




127.0.0.1:6379> get username

"jack"

127.0.0.1:6379> setRange username 4 "12345"

(integer) 9

127.0.0.1:6379> get username

"jack12345"


Append命令

127.0.0.1:6379> set mykey a

OK

127.0.0.1:6379> APPEND mykey bbbb

(integer) 5

127.0.0.1:6379> get amykey

(nil)

127.0.0.1:6379> get mykey

"abbbb"


exists判断一个key是否存在 1表示存在 0表示不存在


127.0.0.1:6379> EXISTS mykey

(integer) 1

127.0.0.1:6379> 

127.0.0.1:6379> 

127.0.0.1:6379> get mykey

"abbbb"

127.0.0.1:6379> exists sss

(integer) 0


###########非常重要############################################

四、String 4

一:位运算

SDS => char[]   xxxx xxxx    char

xxxx xxxx    char

xxxx xxxx    char


1. 百雀林:500w左右的用户  => customerid  


  比如给某一批用户发送短信【营销】。。。 下午10点。。。  上午创建


  【交易金额大于50的,上海地区的,购买过某一个商品】


customerid,customerid,cutomerid,customerid。


table: customerid,customerid,cutomerid,customerid。  【300w】  Max:500w


10,20,30,31,32,33,999,1222,......   【几百M】


【customerid不重复】 我们customerid上限。



SDS => char[]   0000 0000    char

0100 0000    char

0001 0000    char


 char[375000]                        => 几M就搞定了。。。



C#: BitArray   [位数组]    

Redis位运算:


SETBIT key offset value  =>   String的value大小是512M   【数据传输太慢了】 【多而小

        的数据】


String的value大小是512M

static int checkStringLength(client *c, long long size) {

if (size > 512*1024*1024) {

addReplyError(c,"string exceeds maximum allowed size (512MB)");

return C_ERR;

}

return C_OK;

}


01234567



char  => 从左到右   0000 0000   => offset = 7, set=1   => 0000 0001   => offset = 

        6, set=1   => 0000 0011


SDS => char[]   0000 0000    char

0100 0000    char

0001 0000    char

。。。


customerid:10,20,

 


127.0.0.1:6379> SETBIT num 7 1

(integer) 0

127.0.0.1:6379> get num

"\x01"

127.0.0.1:6379> SETBIT num 6 1

(integer) 0

127.0.0.1:6379> get num

"\x03"

 

查看数量BITCOUNT

127.0.0.1:6379> SETBIT num 10 1

(integer) 0

127.0.0.1:6379> SETBIT num 20 1

(integer) 0

127.0.0.1:6379> BITCOUNT num

(integer) 4



GETBIT key offset


127.0.0.1:6379> GETBIT num 6

(integer) 1

127.0.0.1:6379> GETBIT num 7

(integer) 1

127.0.0.1:6379> GETBIT num 10

(integer) 1

127.0.0.1:6379> GETBIT num 5

(integer) 0

127.0.0.1:6379> GETBIT num 20

(integer) 1


BITCOUNT key [start end]  => 获取1的个数


BITOP operation destkey key [key ...]  => AND OR XOR NOT  [JAVA,C#]


对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。


 0000  0001   => 1


& 0000  0010   => 2

--------------

 0000  0000   => 0


1 & 2 = 0



BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN ,对一个或多个 key 求逻辑并,

        并将结果保存到 destkey 。

BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN,对一个或多个 key 求逻辑或,并

        将结果保存到 destkey 。

BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN,对一个或多个 key 求逻辑异

        或,并将结果保存到 destkey 。

BITOP NOT destkey srckey,对给定 key 求逻辑非,并将结果保存到 destkey 



127.0.0.1:6379> setbit num1 7 1

(integer) 0

127.0.0.1:6379> setbit num2 6 1

(integer) 0

127.0.0.1:6379> get num1

"\x01"

127.0.0.1:6379> get num2

"\x02"

127.0.0.1:6379> bitop and num3 num1 num2

(integer) 1

127.0.0.1:6379> get num3

"\x00"

127.0.0.1:6379> 



4、list双向结构

一:List  JAVA,C# 【Array】形式来实现的。。。

双向链表,[单链表,单向循环链表,双向。。。十字链表]  

[队列 和 栈]  queue,  stack

二:从源代码中了解List是如何构造的。。。



typedef struct listNode {

struct listNode *prev;

struct listNode *next;

void *value;

} listNode;



//迭代一个中间变量

typedef struct listIter {

listNode *next;

int direction;

} listIter;


typedef struct list {

listNode *head;

listNode *tail;

void *(*dup)(void *ptr);

void (*free)(void *ptr);

int (*match)(void *ptr, void *key);

unsigned long len;

} list;


为了方便对listNode进行管理,redis中使用list进行包装。。。 

len:统计当前双向链表中的listnode的个数。。。 O(1)


list在redis中存放的形式:

redisObject

 

 type:    (0,1,2,3,4)  1

 encoding:

 ptr      


ptr => string   sds

prtr =>list      list -> listNode 

RedisDb => Dict => key: redisObject    value:redisObject


ptr =>  list[双向链表]



/* Object types */

#define OBJ_STRING 0

#define OBJ_LIST 1

#define OBJ_SET 2

#define OBJ_ZSET 3

#define OBJ_HASH 4


时间复杂度都是:O(1)

LPUSH key value [value ...]  【redis做催付订单,卖家发货,签收提醒】

LPOP key

RPUSH key value [value ...]

RPOP key

LLEN key


例子LPUSH:

127.0.0.1:6379> LLEN mylist

(integer) 0

127.0.0.1:6379> lpush mylist "world"

(integer) 1

127.0.0.1:6379> LLEN mylist

(integer) 1

127.0.0.1:6379> lpush mylist "hello"

(integer) 2

127.0.0.1:6379> LLEN mylist

(integer) 2

127.0.0.1:6379> lrange mylist 0 -1

1) "hello"

2) "world"


#####RPOP用法 

127.0.0.1:6379> lpush order "1001"

(integer) 1

127.0.0.1:6379> lpush order "1002"

(integer) 2

127.0.0.1:6379> lpush order "1003"

(integer) 3

127.0.0.1:6379> LRANGE order 0 -1

1) "1003"

2) "1002"

3) "1001"

127.0.0.1:6379> rpop order

"1001"

127.0.0.1:6379> LRANGE order 0 -1

1) "1003"

2) "1002"

127.0.0.1:6379> 


client     redis:list      server


orderid:  1001

orderid:  1002

orderid:  1003


一:list 阻塞版本


client  ->   list    -> server


while(true){

try{

  var info= list.Rpop();

  

  ....process.... 

}

catch{


}

finally{

Thread.Sleep(1000);


}


没有数据的情况下,我们还是一直的轮询redis。。。


while(true){

try{

  var info= list.BRpop();   => 阻塞

  

  ....process.... 

}

catch{


}

finally{

Thread.Sleep(1000);


}


BRpop,BLpop  两种方式

BRPOP key [key ...] timeout 【s为单位】   


timeout: 0 表示永远等待 【connection被阻塞】

timeout:10 表示10s过期

MSMQ,RabbitMQ 都有这种等待。。。


例子:

127.0.0.1:6379> rpush orders 1001

(integer) 1

127.0.0.1:6379> rpush orders 1002

(integer) 2

127.0.0.1:6379> rpush orders 1003

(integer) 3

127.0.0.1:6379> rpush orders 1004

(integer) 4

127.0.0.1:6379> rpush orders 1005

(integer) 5


现象

127.0.0.1:6379> BRPOP orders 0

1) "orders"

2) "1004"

127.0.0.1:6379> BRPOP orders 0

1) "orders"

2) "1003"

127.0.0.1:6379> BRPOP orders 0

1) "orders"

2) "1002"

127.0.0.1:6379> BRPOP orders 0

1) "orders"

2) "1001"

127.0.0.1:6379> BRPOP orders 0

.......

这里在等待,阻塞


因为 BRPOP 和 BLPOP 基本是完全一样的,除了它们一个是从尾部弹出元素,而另一个是从头

        部弹出元素。


将当前的key和 timeout给了client struct。。。

c->bpop.timeout = timeout;

c->bpop.target = target;


在生产环境中使用的比较多的。。。


二:工具函数


LINDEX key index  获取index位置的数组。。。O(N)


 if (quicklistIndex(o->ptr, index, &entry)) 


head -> tail 进行遍历



127.0.0.1:6379> lindex orders 2

"10001"

127.0.0.1:6379> lrange orders 0 5

1) "10007"

2) "10008"

3) "10001"

4) "10002"

5) "10003"

127.0.0.1:6379> 


LRANGE key start stop   O(N+M)



LINDEX用法:(生产环境少用,因为数据不断变化)

127.0.0.1:6379> lpush a 1

(integer) 1

127.0.0.1:6379> lpush a 2

(integer) 2

127.0.0.1:6379> lpush a 3

(integer) 3

127.0.0.1:6379> lpush a 4

(integer) 4

127.0.0.1:6379> LINDEX a 0

"4"

127.0.0.1:6379> LINDEX a -1

"1"



start: 可以是+,-  

stop :结束

js: substr 


LRANGE key start stop  O(N)


redis> RPUSH mylist "one"

(integer) 1

redis> RPUSH mylist "two"

(integer) 2

redis> RPUSH mylist "three"

(integer) 3

redis> LRANGE mylist 0 0

1) "one"

redis> LRANGE mylist -3 2

1) "one"

2) "two"

3) "three"


LINSERT key BEFORE|AFTER pivot value


value插入到pivot之前还是之后。。。


LSET key index value   => 找index需要时间的。。。


5、hash结构

1. 催付规则    [商品价格>30 ,上海地区的,不是黑名单用户,购买过某个商品]


  符合就发催付。。。


  联合利华:

  施华蔻: 

  都市大药房旗舰店: 【商品维度】

 hash: 


 shopid    regularID  regularEntity   ID=1

regularID  regularEntity   ID=2


trade:  hgetall  获取所有的hash表内容 【共享内存】  ,避免每次来trade都要读取mysql



2. 分库分表:【shopid 都有一个DB】

hash:

  shopalloc 

  shopid   dbconnection

  shopid   dbconnection

  

3. 策略使用 【复杂均衡】   hget,hkeys,hvals

logicserver

  

 client  ->  sellernick    ->   router         logicserver


logicserver


hash:  routeralloc   

  sellernick logicserverIP

  sellernick logicserverIP



Monitor => 用于给指定的sellernick分配logicserver   


db中的sellernickList 和 redis中的sellernickList进行比较。。。。 


从redis中一次性把所有的sellernick捞出来,,, hkeys



HGETALL key  获取hash中的所有数据


127.0.0.1:6379> hset shopid_1 regularID_1 entity

(integer) 1

127.0.0.1:6379> hset shopid_1 regularID_2 entity2

(integer) 1

127.0.0.1:6379> hset shopid_1 regularID_3 entity3

(integer) 1

127.0.0.1:6379> hgetAll shopid_1

1) "regularID_1"

2) "entity"

3) "regularID_2"

4) "entity2"

5) "regularID_3"

6) "entity3"

127.0.0.1:6379> 


例子:

127.0.0.1:6379> hset persons username "jack"

(integer) 1

127.0.0.1:6379> hset persons password "123456"

(integer) 1

127.0.0.1:6379> hget persons username

"jack"

127.0.0.1:6379> hget persons password

"123456"

127.0.0.1:6379> HGETALL persons

1) "username"

2) "jack"

3) "password"

4) "123456"


4. 短信通道


 sellernick  channel1

 sellernick  channel2

 


HDEL key field [field ...]    用于删除hash表。。。


HEXISTS key field             O(1)


hash:用于定值查找,时间复杂度永远都是O(1)   => hashfunction



127.0.0.1:6379> hset shopalloc 1 www.baidu.com

(integer) 1

127.0.0.1:6379> hset shopalloc 2 www.google.com

(integer) 1

127.0.0.1:6379> hlen shopalloc

(integer) 2

127.0.0.1:6379> hexists shopalloc 1

(integer) 1

127.0.0.1:6379> hexists shopalloc 1

(integer) 1

127.0.0.1:6379> hexists shopalloc 2

(integer) 1

127.0.0.1:6379> hexists shopalloc 3

(integer) 0

127.0.0.1:6379> hexists shopalloc 3



HINCRBY key field increment  


对field中的value进行递增,递增的值就是increment。。。。    String: incr



HKEYS key 所有hashtable中的所有keys。。。


127.0.0.1:6379> hkeys shopalloc

1) "1"

2) "2"


127.0.0.1:6379> hvals shopalloc

1) "www.baidu.com"

2) "www.google.com"



HLEN key


HMSET key field value [field value ...]  批量的执行mset。。。 通过一次tcp操作全部塞

       入到key中。。。


HSETNX key field value 【NX】 =>  【Not Exists】   做分布式锁【轻量级】


HSTRLEN key field 获取field中的value的长度


127.0.0.1:6379> hstrlen shopalloc 1

(integer) 13

127.0.0.1:6379> hstrlen shopalloc 2

(integer) 14

6、set结构

一:Set 

Set => 没有value的Hash


hash 


k, v



Set   【空间要节省的多】

k


二:应用场景 用户画像

ShopID: 旗舰店下面


Trade 


商品维度:

productid_1: customerid,customerid ...........    Set

productid_2: customerid,customerid .......         Set



交易维度

customerid_1: 总交易金额,平均交易金额


地区维度:


shanghai: customerid,customerid..... Set

beijing:  customerid,customerid.... Set



购买 “洗发水” 上海地区的。。。     【关联推荐】

“洗发水”的productid:   看一下集合中是否有命中该customerid  O(1)

“上海” areaid:     看一下集合中是否包含。。。

如果两项都命中,那么我们直接发送“推荐”的彩信和邮件。。。。h5。

1. query,我们基本上做到了O(1)  cluster集群


2. maintain 维护 



二:常见命令


1. SADD      

  SADD key member [member ...]     单个或者批量添加,节省的是我们tcp的传输量。。。

  

2. SISMEMBER  

  SISMEMBER key member   用于判断制定的member是否是set中的成员。。。



旗舰店基本上商品数都在1w之内。。。。 遍历1w次redis耗费的时候也就在5s内。。。。 【局

        域网】


例子 

127.0.0.1:6379> sadd product_2 11 21 31 41

(integer) 4

127.0.0.1:6379> SMEMBERS product_2

1) "11"

2) "21"

3) "31"

4) "41"

127.0.0.1:6379> SISMEMBER product_2 11

(integer) 1

127.0.0.1:6379> 



3.交集,差集,并集

交集: SINTER key [key ...]   后面都是要比较的key

并集: SUNION key [key ...]

差集: SDIFF key [key ...]

 

4. SCARD key  获取Set的元素个数


5. SPOP key [count] 随机弹出一个元素并且移除。。

  Removes and returns one or more random elements from the set value store at key.


6. SMEMBERS key  【查看所有的成员数据】


共享内存,强大的redis set集合。。。

7、sorted set 结构

一:SortedSet   Java,C# 【SortDictinory 有序字典=> 红黑树(很复杂一种树结构,减少

           旋转)】

redis:skiplist 【跳跃表】 90年   【链表 来达到树的一个效果】  AVL,RedBlackTree  


严格的Log2N复杂度。。。  


1. 如何更快的时间,经过更少的城市达到目标城市


《1》到达北京: 直接飞机 一站达到  O(1)


《2》天津:     四个节点到天津。



【层次链表】 达到均摊的log2N 的时间复杂度。。。



2. 添加数据到sortedset中。。。。 


《1》 优先级队列


《2》 top10的操作 【top N 大根堆,小根堆】


ZADD key [NX|XX] [CH] [INCR] score member [score member ...]


k:score      【权重,优先级】

v:member



127.0.0.1:6379> zadd trades 10 trade_10

(integer) 1

127.0.0.1:6379> zadd trades 20 trade_20

(integer) 1

127.0.0.1:6379> zadd trades 30 trade_30

(integer) 1

127.0.0.1:6379> zadd trades 40 trade_40

(integer) 1

127.0.0.1:6379> zadd trades 50 trade_50

(integer) 1

127.0.0.1:6379> 



1.如果获取所有的数据


127.0.0.1:6379> zrange trades 0 -1    【从小到大的排序】

1) "trade_10"

2) "trade_20"

3) "trade_30"

4) "trade_40"

5) "trade_50"

127.0.0.1:6379> 


###反向

127.0.0.1:6379> zrevrange trades 0 -1

1) "trade_50"

2) "trade_40"

3) "trade_30"

4) "trade_20"

5) "trade_10"



127.0.0.1:6379> zrange trades 0 -1 withscores

1) "trade_10"

2) "10"

3) "trade_20"

4) "20"

5) "trade_30"

6) "30"

7) "trade_40"

8) "40"

9) "trade_50"

10) "50"

127.0.0.1:6379> 


ZREVRANGE key start stop [WITHSCORES] 根据


优先级队列:


1. 先获取最大值:


127.0.0.1:6379> zrevrange trades 0 0

1) "trade_50"


2. 删除最大值

 

127.0.0.1:6379> zremrangebyrank trades -1 -1

(integer) 1


127.0.0.1:6379> zrevrange trades 0 -1

1) "trade_50"

2) "trade_40"

3) "trade_30"

4) "trade_20"

5) "trade_10"

127.0.0.1:6379> zrevrange trades 0 0

1) "trade_50"

127.0.0.1:6379> zremrangebyrank trades -1 -1

(integer) 1

127.0.0.1:6379> zrevrange trades 0 -1

1) "trade_40"

2) "trade_30"

3) "trade_20"

4) "trade_10"

127.0.0.1:6379> 


一般来说做两次操作。。。 【redis】 做优先级队列面临的一些问题。。。

Rabbitmq 专业级别的MQ产品。

8、HyperLogLog

一:hyperloglog  【算法】


1. distinct + count 



我们计算某一台的独立ip。。。。



《1》 使用set来保存某一天的所有ip数字。。。


 set  2016-12-26    192.168.10.121 192.168.10.122 192.168.10.123  192.168.10.121

  独立IP是多少呢?  3个。。。


  这时候,如果ip有1kw。。1ww。。。  【耗费巨大的内存】



《2》 hyperloglog 需要解决这种问题。。。

 

 1. 节省内存 每个HyperLogLog结构需要12K字节再加上key本身的几个字节  


hyperloglog + len(key)   最多也就是几十k

                 能够解决别人几百M所能解决的问题。。。

hyperloglog不存储value,只是计算基数值。。。


 pfadd:   PFADD key element [element ...]


 pfcount: PFCOUNT key [key ...]


 pfmerge:


 2. 弊端:  有一定的错误率。。。   用错误率换取空间。。。  0.81% 。。。



二:Sort 【一个排序】 对key进行操作的。。

SORT key [BY pattern] [LIMIT offset count] [GET pattern] [ASC|DESC] [ALPHA] 

        destination

更适合的去模仿sql。。。


如何让redis 模仿sql的一些语法

1. 直接sort key


sort uid


127.0.0.1:6379> sort uid

1) "1"

2) "2"

3) "3"

127.0.0.1:6379> sort uid desc

1) "3"

2) "2"

3) "1"

127.0.0.1:6379> 


2. sort limit


select uid from users limit 0 1 desc


127.0.0.1:6379> sort uid limit 0 1 desc

1) "3"

127.0.0.1:6379> sort udi limit 0 1 asc

(empty list or set)

127.0.0.1:6379> sort uid limit 0 1 asc

1) "1"



3. sort [BY pattern]


uid  username_{0}  age_{1}


1    jack          30


2    mary          15


3    john          20


select usename from users order by age desc


jack

john

mary


上面这种场景该如何实现???



127.0.0.1:6379> sort uid by age_* get username_* desc

1) "jack"

2) "john"

3) "mary"


4. 我在获取usename的时候,想把uid也捞出来。。。

select uid,username from users order by age desc。。。

sort uid by age_* get username_* get #  desc



5. 获取所有。。。


select uid,username,age from users order by age desc....


127.0.0.1:6379> sort uid by age_* get username_* get # get age_*  desc

1) "jack"

2) "1"

3) "30"



127.0.0.1:6379>  HMSET user_info_1 name admin level 9999

OK

127.0.0.1:6379> HMSET user_info_2 name jack level 10

OK

127.0.0.1:6379>  HMSET user_info_3 name peter level 25

OK

127.0.0.1:6379>  HMSET user_info_4 name mary level 70

OK

127.0.0.1:6379> sort uid

1) "1"

2) "2"

3) "3"

127.0.0.1:6379> rpush uid 4

(integer) 4

127.0.0.1:6379> sort uid

1) "1"

2) "2"

3) "3"

4) "4"

127.0.0.1:6379> sort uid by user_info_*->level get user_info_*->name 

1) "jack"

2) "peter"

3) "mary"

4) "admin"

127.0.0.1:6379> sort uid by user_info_*->level get user_info_*->name  desc

1) "admin"

2) "mary"

3) "peter"

4) "jack"

127.0.0.1:6379> 

4) "john"

5) "3"

6) "20"

7) "mary"

8) "2"

9) "15"

127.0.0.1:6379> 


复杂度不低的。。而且能不用就不用。。。毕竟以性能为代价。。。

9、transaction事务

一:transaction 


mysql,sqlserver。。。【复杂的机制】


nosql:为了保持简洁性,或多或少的砍掉了一些transaction的一些特性。。。弱化。。。


<1> create


<2> commit 


<3> rollback


multi


xxxxxxx


exec 【提交】


discard 【取消】


watch,unwatch 【监测或者取消】


127.0.0.1:6379> flushall

OK

127.0.0.1:6379> multi

OK

127.0.0.1:6379> set useranme jack

QUEUED

127.0.0.1:6379> set password 12345

QUEUED

127.0.0.1:6379> exec

1) OK

2) OK

127.0.0.1:6379> keys *

1) "password"

2) "useranme"

127.0.0.1:6379> 



127.0.0.1:6379> multi

OK

127.0.0.1:6379> set username jack

QUEUED

127.0.0.1:6379> set password 123456

QUEUED

127.0.0.1:6379> discard

OK

127.0.0.1:6379> keys *

(empty list or set)

127.0.0.1:6379> 


二:watch

mysql,sqlserver。。


watch num

multi  【在事务执行的过程中,我不希望被别人修改】

incr num   【0,1  ,2】  本来你想从0 -> 1  结果,看到的效果就是 0 -> 2 了。。。

exec [discard]


multi


incr num


exec  【取消】


client incr num  


《1》不用watch


incr :生成订单号。。。。   discard。。。

watch的本意就是要保证在mutli的过程中,数据必须是干净的。。。。


redisDb中有一个watched_keys


10、pub与sub

一:发布订阅模式

1. 观察者模式 【设计模式中的一种】  .net  WPF 中就有一种MVVM模式。。

       js    knockoutjs mvvm模式。。。

subject


subscribe  subcribe  subcribe  subcribe


SUBSCRIBE channel [channel ...]


channel:就是subject 【频道】    收音机



PUBLISH channel message   用于更新。。。


##发送端

127.0.0.1:6379> PUBLISH 188.12 "hello"

(integer) 1

127.0.0.1:6379> PUBLISH new.* "hello"

(integer) 1

127.0.0.1:6379>


##接受端1

127.0.0.1:6379> subscribe new.*

Reading messages... (press Ctrl-C to quit)

1) "subscribe"

2) "new.*"

3) (integer) 1

1) "message"

2) "new.*"

3) "hello"


##接受端2

127.0.0.1:6379> SUBSCRIBE 188.12

Reading messages... (press Ctrl-C to quit)

1) "subscribe"

2) "188.12"

3) (integer) 1

1) "message"

2) "188.12"

3) "hello"


直接订阅特定的频道,一对一的关系。。。


如果订阅一个类别。。。 【模式匹配】  new.*   => new.it  or  new.sport


*:正则字符


PSUBSCRIBE pattern [pattern ...]  => p[pattern] 模式。。。


MQ: Rabbitmq   【发布订阅模式】


client ->  mq  ->  server     【长连接】


[[email protected] Desktop]# redis-cli

127.0.0.1:6379> subscribe 188.12

Reading messages... (press Ctrl-C to quit)


127.0.0.1:6379> psubscribe news.*

Reading messages... (press Ctrl-C to quit)



如果client端推送大量的消息,,, 1s  100


这时候server并不能快速的处理,,,, logic process..... 而且读取db,soa webapi...  


这时候server不能及时处理,导致大量积压。。。 【1:memory挂掉。。。

  2:cpu 100%   

  3:容易丢失消息[server挂掉]】

二:源码 [RedisClient]


1. 非模式       dict *pubsub_channels;  /* channels a client is interested in 

            (SUBSCRIBE) */   字典

 key           value

subject1        client1 -> client2  -> client3  -> 

            client4


subject2        client1 -> client9  


publish subject1 helloworld   所以查找key的复杂度是O(1)


2. 模式         list *pubsub_patterns;  /* patterns a client is interested in 

       (SUBSCRIBE) */   链表

pubsubPattern   ->  pubsubPattern           

c1                  c3

pattern= news.*    pattern= trip.*


使用redis,定义的模式匹配的频道不会特别多。。。肯定不会超过100个。。。  遍历的复杂

        度O(N)

11、过期键EXPIRE

1. redis 作为Cache使用。。。

set username jack  ....[ms] [ms]


2.第一种,初始化设置。。。  set

 第二种:后期更改

 第三种:过期变成持久。。。


SET key value [EX seconds] [PX milliseconds] [NX|XX]


1、EXPIRE key seconds  将一个key变为过期键。。。   【以s为单位】

2、PEXPIRE key milliseconds  将一个key变成过期键, 【以ms为单位】


3、以某一个时间点为过期键,比如说,2016-12-27 9:07   想 2016-12-27 10:00 过

         期。。。。

EXPIREAT key timestamp  


127.0.0.1:6379> set a a

OK

127.0.0.1:6379> EXPIRE a 10

(integer) 1

127.0.0.1:6379> ttl a

(integer) 7

127.0.0.1:6379> 

127.0.0.1:6379> 

127.0.0.1:6379> 

127.0.0.1:6379> ttl a

(integer) -2

 


Cache  


redis作为一个Cache。。。   memcache 真的是一样的。。。


# maxmemory <bytes>   设置最大的内存  byte为单位。。。


server:100M


maxmemory: 50M



如果数据大于50M我该怎么办???


# volatile-lru -> remove the key with an expire set using an LRU algorithm

# allkeys-lru -> remove any key according to the LRU algorithm

# volatile-random -> remove a random key with an expire set

# allkeys-random -> remove a random key, any key

# volatile-ttl -> remove the key with the nearest expire time (minor TTL)

# noeviction -> don‘t expire at all, just return an error on write operations



lru => leaset recently used  【最久未使用的】


volatile-lru:  从过期键中去找最久未使用的数据。。。


allkeys-lru:    从所有的keys中通过lru算法去删除。。。


volatile-ttl:  redisObject  找到马上要过期的lru时间  


# maxmemory-policy noeviction


redis监控  

[[email protected] ~]# redis-cli --stat

------- data ------ --------------------- load -------------------- - child -

keys       mem      clients blocked requests            connections          

5          843.38K  3       0       52 (+0)             6           

5          843.38K  3       0       53 (+1)             6           

5          843.38K  3       0       54 (+1)             6           

5          843.38K  3       0       55 (+1)             6           

5          843.38K  3       0       56 (+1)             6           

5          843.38K  3       0       57 (+1)             6           

5          843.38K  3       0       58 (+1)             6           

5          843.38K  3       0       59 (+1)             6

12、batchcommit性能优化

一:redis 两点性能优化。。。

1. 批量提交


<1> mset 。。。。 驱动,。。。。


  千人千面的时候,需要有一个数据初始化。。。

400w - 500w customerid


customerid_1  22


customerid_2  21


customerid_3  14


操作400w  - 500w  tcp链接。。。。 几个G。。。  【1h】


<2> mset


mset customerid_1 22  customerid_2  21  ....   


网络卡死 +  超时。。。。


1w条提交一次。。。


jedis来演示一下。

public static void main(String[] args) {

Jedis redis=new Jedis("192.168.23.155",6379);

// String[] strlist=

     {"customerid_1","22","customerid_2","21","customerid_3","14"};

ArrayList<String> arrayList=new ArrayList<>();

arrayList.add("customerid_1");

arrayList.add("22");

arrayList.add("customerid_2");

arrayList.add("21");

arrayList.add("customerid_3");

arrayList.add("14");

String[] strlist=new String[arrayList.size()];

arrayList.toArray(strlist);

redis.mset(strlist);   //batch

  System.out.println("success");

}



2. 多命令

mset  string的批量

hmset hash的批量

sadd  set的批量



如果做到三种命令的混合呢???

set name jack

hset person name jack

sadd tags china


这样的三条混合命令,如果一次性提交???  【节省的网络的轮回】

pipeline 【管道】  redis。。。


jedis来实现。。。


package mytest2;

import java.util.ArrayList;


import redis.clients.jedis.Jedis;

import redis.clients.jedis.Pipeline;


public class Program {


public static void main(String[] args) {

Jedis redis=new Jedis("192.168.23.155",6379);

//start pipeline

Pipeline pipeline=redis.pipelined();

pipeline.set("name","jack");

pipeline.hset("person","name","mary");

pipeline.sadd("tags", "china");

pipeline.sync();   //execute....

  System.out.println("success");

}

}

13、aof rdb 持久化

redis默认是rdb模式

一:redis序列化。

memcached 没有序列化。。。

1. rdb

  快照的模式。 mongodb。。。  【定点保存】如果重启会丢掉一些数据。。。。

flush data to disk。。。 

redis默认就是rdb模式。。。

  触发机制:  

  save time changes

  

save 900 【15min】 1

save 300 【3min】 10

save 60 【1min】 10000


在Redis中使用serverCron来实现这个检测。。。


定期检测 三个save是否满足,如果满足,调用bgsave。。。



手工进行save,bgsave 保存。。。


######非常重要#########################################

save:同步保存,保存期间,client是被阻塞的。。。  #####

 #####

int rdbSave(char *filename);                      #####

 #####

bgsave:  开启子进程来保存。。。                  #####

 #####

#######################################################


2. aof  

来一条命令,保存一次。。。。 aof文件是保存我们的 。。。文本协议。。。

默认是不启用的。

如果开启:

1. appendonly yes


# appendfsync always     => 来一条保存一条。。 强制的执行fsync命令。。。  告诉操作系统强制flush到disk。    【slow,safe】 最多丢失一条数据


appendfsync everysec     => 1秒 flush 一次。。。。  fsync命令  【折中】 最多丢失1s数据


# appendfsync no         => flush。。。           fsync命令。。等待操作系统将自己缓冲区中的数据flush到硬盘。。。  【unsafe】  不知道。。。



=> select 0   


=>  set username  jack


=>  set password 12345



/* Trigger an AOF rewrite if needed */

if (server.rdb_child_pid == -1 &&

server.aof_child_pid == -1 &&

server.aof_rewrite_perc &&

server.aof_current_size > server.aof_rewrite_min_size)

{

long long base = server.aof_rewrite_base_size ?

server.aof_rewrite_base_size : 1;

long long growth = (server.aof_current_size*100/base) - 100;

if (growth >= server.aof_rewrite_perc) {

serverLog(LL_NOTICE,"Starting automatic rewriting of AOF on %lld%% growth",growth);

rewriteAppendOnlyFileBackground();

}

}


rewriteAppend:   如果db暴涨。。。redis命令是不是特别多。。。


CURD操作。。。 


set username jack


set username mary


set username peter


set username asdfasdf



如果对username进行了100w操作。。。那命令多的吓人。。。


所以redis做了一个机制,如果达到某一个阈值,会进行rewrite


auto-aof-rewrite-percentage 100

auto-aof-rewrite-min-size 64mb 


1. 如果你的文件有128M。。。   64 x 2 = 128 


生成快照 -> 生成命令到aof文件中。。。【缩小了文件的尺寸】

14、master-slave

一:redis:多机操作

master - slave

1. 数据的热备份

  如果master宕机了,slave还是有完整的备份。。。。 【热备份】

2. 分解读写压力

  如果你的业务读写特别大。。。 【分流】

  分而治之。。。

一般来说, 读写8:2   10个操作中有8个读,2个写。。。

这时候,就有一个集群来抗读写操作。。。


3. 可以在slave上做冷备份

  防止程序员,运维的误操作。。。比如说我做了flushall的操作。。。

  直接copy一个slave3 的rdb文件。。。 

mysql,sqlserver中 master - slave 概念 

nosql:基本上都有。。。


二:实践

用3台 Centos去做

centos1: 192.168.23.158   master

centos2: 192.168.23.152   slave1

centos3: 192.168.23.145   slave2


######################


配置非常简单,只要在从库设置如下内容即可 设置主库的ip及端口即可

slaveof <masterip> <masterport>


(1)master主要配置如下:

#bind 127.0.0.1

protected-mode no

port 6379

#其他不用配置也可以


(2)slave1配置如下:

#bind 127.0.0.1

protected-mode no

port 6379

slaveof 192.168.175.29 6379

(3)salve2配置如下

#bind 127.0.0.1

protected-mode no

port 6379

slaveof 192.168.175.29 6379


注意:这里具体的ip看你自己的了哦!!!!!


redis-cli slaveof 命令


修改配置文件 slaveof命令。。。


# masterauth <master-password>   如果master有密码,可以在这里配置。。。


3257:M 28 Dec 06:28:53.339 * Slave 192.168.23.152:6379 asks for synchronization

3257:M 28 Dec 06:28:53.339 * Full resync requested by slave 192.168.23.152:6379

3257:M 28 Dec 06:28:53.339 * Starting BGSAVE for SYNC with target: disk

3257:M 28 Dec 06:28:53.340 * Background saving started by pid 3376

3376:C 28 Dec 06:28:53.349 * DB saved on disk

3376:C 28 Dec 06:28:53.350 * RDB: 6 MB of memory used by copy-on-write

3257:M 28 Dec 06:28:53.445 * Background saving terminated with success

3257:M 28 Dec 06:28:53.446 * Synchronization with slave 192.168.23.152:6379 

        succeeded



三:验证


# Replication

role:master

connected_slaves:2

slave0:ip=192.168.23.152,port=6379,state=online,offset=127,lag=0

slave1:ip=192.168.23.145,port=6379,state=online,offset=141,lag=0

master_repl_offset:141

repl_backlog_active:1

repl_backlog_size:1048576

repl_backlog_first_byte_offset:2

repl_backlog_histlen:140



# Keyspace

127.0.0.1:6379> info Replication

# Replication

role:slave

master_host:192.168.23.158

master_port:6379

master_link_status:up

master_last_io_seconds_ago:5

master_sync_in_progress:0

slave_repl_offset:211

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

127.0.0.1:6379> 


四:落地实践

1.redis-cli

通过验证,没有问题。。。

2. C# client  =>  master - slave。。。。

static void Main(string[] args)

{

//创建链接

ConnectionMultiplexer redis = 

      Connect("192.168.23.158:6379,192.168.23.152:6379,192.168.23.145:6379"

       );


//获取db

var database = redis.GetDatabase();


//database.StringSet("username", "hellworld");


var str = database.StringGet("username");

}

15、redis sentinel【哨兵】

一:sentinel  【哨兵】

master -> slave 

如果master挂掉了,,,程序只能读取,不能写入了。。。


info:命令获取master集群的所有信息,比如说 slave的ip地址等信息。。。。


主观: 个人的想法 【不一定真的下线】


客观: 基本事实   【如果有某几个人都说master挂掉了,才是事实】


二:搭建

1. centos-1  192.168.23.158    master      

2. centos-2  192.168.23.152    slave1

3. centos-3  192.168.23.145    slave2

4. centos-4  192.168.23.154  放三台 sentinel。。。。


《1》 sentinel:

port

monitor masterhost masterip

客观下线: quorum  [阈值]

主观下线: 下线的标准 【】 15s,30s。1min。。。

其余的采用默认配置。。。

 

sentinel auth-pass <master-name> <password>   =》 master 有密码,在这地方设置。。。

sentinel monitor <master-name> <ip> <redis-port> <quorum>

port 26379

sentinel down-after-milliseconds mymaster 30000


protected-mode no  一定要关掉


高可用的模式。。。你可以down 掉任何一台机器。。。sentinel会给我们重新选举select。。。


C#,Java连接一下。。。  塞几个ip地址就ok了。。。


一主2从搭建我就不说了


下面说一下

sentinel.conf


只要配置如下内容

(1)配置文件1

protected-mode no

port 26382

sentinel monitor mymaster 192.168.23.158 6379 2


(2)配置文件12

protected-mode no

port 26383

sentinel monitor mymaster 192.168.23.158 6379 2


(3)配置文件12

protected-mode no

port 26384

sentinel monitor mymaster 192.168.23.158 6379 2


分别在3台机器启动:

./redis-sentinel  sentinel.conf

./redis-sentinel  sentinel.conf

./redis-sentinel  sentinel.conf



ps -ef | grep  redis

当kill -9 master进程

然后启动redis server时

以前的master角色变成了slave角色

sentinel【哨兵】从2个slave当中选一个当做master角色


具体日志信息如下:


10294:X 08 Mar 03:33:24.533 # +sdown master mymaster 192.168.175.29 6379

10294:X 08 Mar 03:33:24.605 # +odown master mymaster 192.168.175.29 6379 #quorum 3/2

10294:X 08 Mar 03:33:24.605 # +new-epoch 1

10294:X 08 Mar 03:33:24.605 # +try-failover master mymaster 192.168.175.29 6379

10294:X 08 Mar 03:33:24.624 # +vote-for-leader 3da9f7fdfda091e1d443fd5bbd8d77f3ac312016 1

10294:X 08 Mar 03:33:24.624 # 38e1ed45641a1479dece7f06105be01246e694e1 voted for 38e1ed45641a1479dece7f06105be01246e694e1 1

10294:X 08 Mar 03:33:24.633 # 1449d4f234e10a642c1155a68412e4ce529ba92f voted for 38e1ed45641a1479dece7f06105be01246e694e1 1

10294:X 08 Mar 03:33:25.223 # +config-update-from sentinel 38e1ed45641a1479dece7f06105be01246e694e1 192.168.175.29 26384 @ mymaster 192.168.175.29 6379

10294:X 08 Mar 03:33:25.223 # +switch-master mymaster 192.168.175.29 6379 192.168.175.29 6381

10294:X 08 Mar 03:33:25.223 * +slave slave 192.168.175.29:6380 192.168.175.29 6380 @ mymaster 192.168.175.29 6381

10294:X 08 Mar 03:33:25.223 * +slave slave 192.168.175.29:6379 192.168.175.29 6379 @ mymaster 192.168.175.29 6381

10294:X 08 Mar 03:33:55.268 # +sdown slave 192.168.175.29:6379 192.168.175.29 6379 @ mymaster 192.168.175.29 6381



这里的ip看你自己的ip   

16、redis监控

一:redis的监控 【可视化的工具】

学习连接

http://www.cnblogs.com/huangxincheng/archive/2016/06/08/5571185.html



winform

web

1. 程序员要经常用到的一个可视化监控工具。。。。

  mysql,sqlserver 都有一个可视化界面。。。

Redis Desktop Manager


Redis Client   【国人开发】  https://github.com/caoxinyu/RedisClient

<a href="https://raw.githubusercontent.com/caoxinyu/RedisClient/windows/release/redisclient-win32.x86.2.0.exe">redisclient-win32.x86.2.0.exe</a>

有了可视化工具,就不用每次都输入命令去查看。。。


Redis Studio



二:web监控。。【redislive】

github 源码地址如下:

https://github.com/nkrode/RedisLive


http://www.cnblogs.com/huangxincheng/archive/2016/06/08/5571185.html

python 写的一个web监控。。。

1. 安装pip =>  python的安装工具包。。。 C# nuge, java maven。。。


 


下载:https://pypi.python.org/pypi/pip


[[email protected] Desktop]# python

Python 2.7.5 (default, Nov 20 2015, 02:00:19) 

[GCC 4.8.5 20150623 (Red Hat 4.8.5-4)] on linux2

Type "help", "copyright", "credits" or "license" for more information.

>>> 


2.python setup.py install  安装pip工具包

3.pip install tornado   python server :【java tomcat,.net IIS】

4. pip install redis    python redis驱动 【java jedis,.net StackExchange】

5. pip install python-dateutil --upgrade   # python dateutil类库。。。 【java 工具类jar】



6. 获取redislive的源代码  python的应用程序

RedisServers: 你需要监控的redis server。。。。

DataStoreType: RedisLive  【sqlite,redis】  专门开一台redis存放RedisLive的统计信息

RedisStatsServer: 统计信息存放的Redis地址。。。


7. 开启统计的redis 

8. 开启监控脚本  ./redis-monitor.py --duration=120

9. 开启web站点   ./redis-live.py


1083  mkdir /usr/local/python27

1084  cd Python-2.7.5

1085  ll

1086  ./configure --prefix=/usr/local/python27

1087  make

1088  make install

1089  python

1090  mv /usr/bin/python /usr/bin/python2.6.6

1091  ln -s /usr/local/python27/bin/python /usr/bin/python

 

1132  tar zxvf setuptools-0.6c11.tar.gz

1133  cd setuptools-0.6c11

1134  python setup.py build

1135  python setup.py install

1136  cd ../pip-8.1.2

1137  python setup.py  build

1138  python setup.py  install

 

 

[[email protected] soft]# find / -name python2.6

/usr/include/python2.6

/usr/lib64/python2.6

/usr/lib/python2.6

/usr/bin/python2.6


三:怎么实现的。。

RedisLive : monitor,info。。。。来构建一个趋势图。。。

Redis Live is a dashboard application with a number of useful widgets. At it‘s heart is a monitoring script that periodically issues INFO and MONITOR command to the redis instances and stores the data for analytics.

monitor.py 脚本。。。



我的配置文件如下:

[[email protected] RedisLive-master]# vim src/redis-live.conf


{

"RedisServers":

[

{

"server": "192.168.175.29",

"port" : 6379

},


{

"server": "192.168.175.29",

"port" : 6380

},

{

"server": "192.168.175.29",

"port" : 6381

}

],


"DataStoreType" : "redis",


"RedisStatsServer":

{

"server" : "192.168.175.30",

"port" : 6379

}

}


17、redis cluster

一: redis cluster 3.0 出来的

1. 为什么集群:

  master -slave 

  sentinel 

如果我的数据有1T。。。那如何存放到redis中。。。

去重新化的方式

mongodb

 monogd

client       mongos    mongod

 mongod

中心化




redis: p2p的方法 【去重新化】

1. 首先redis集群使用16384个slot。。。


由三台机器承载16384个slot... 

client -> hash(username)   


0< hash(username) < 16383

eg: hash(username)=100 


  redis

client   hash     redis

  redis



这个hash(username)函数实在各自的client端。。。【驱动中内置的】


2. cluster 内置了sentinel + master/slave + partition...



3.


4台centos


 centos1:  192.168.23.158  

 centos2:  192.168.23.152

 centos3:  192.168.23.145 

 centos4:  192.168.23.154     三台slave




三:操作步骤:


1. 开启cluster模式


cluster-enabled yes                    开启集群状态

cluster-config-file nodes-6379.conf    集群的节点文件

./redis-server ./redis.conf



2. 找到一个叫做 redis-trib.rb 的文件 rb=>  ruby

  centos 没有ruby的环境。。。

  安装一系列的依赖包。。。

//通过第三方工具进行安装

./redis-trib.rb create --replicas 1 192.168.23.158:6379 192.168.23.152:6379 192.168.23.145:6379 192.168.23.154:6379 192.168.23.154:6380 192.168.23.154:6381


《1》 ruby环境

《2》 ruby的redis驱动安装    gem install redis


[[email protected] redis]# ./redis-trib.rb create --replicas 1 192.168.23.158:6379 192.168.23.152:6379 192.168.23.145:6379 192.168.23.154:6379 192.168.23.154:6380 192.168.23.154:6381

>>> Creating cluster

>>> Performing hash slots allocation on 6 nodes...

Using 3 masters:

192.168.23.158:6379

192.168.23.152:6379

192.168.23.145:6379

Adding replica 192.168.23.154:6379 to 192.168.23.158:6379

Adding replica 192.168.23.154:6380 to 192.168.23.152:6379

Adding replica 192.168.23.154:6381 to 192.168.23.145:6379

M: cbfadb06673f7eb69483aa2031cb60fc4251fb7a 192.168.23.158:6379

  slots:0-5460 (5461 slots) master

M: 2160b439f59fafc3bb02fe920933284d5df3f39e 192.168.23.152:6379

  slots:5461-10922 (5462 slots) master

M: 38a05510f8014d7fdf7b9c606461ecaae5a47b2a 192.168.23.145:6379

  slots:10923-16383 (5461 slots) master

S: 2628c7fa7630d544b7d4a727d563a49c68578240 192.168.23.154:6379

  replicates cbfadb06673f7eb69483aa2031cb60fc4251fb7a

S: 30c4755c49b228af5e111baa74dbebb85c4185c8 192.168.23.154:6380

  replicates 2160b439f59fafc3bb02fe920933284d5df3f39e

S: 75a81dbaeb8d46b0783adb3ab8aeec405608ca18 192.168.23.154:6381

  replicates 38a05510f8014d7fdf7b9c606461ecaae5a47b2a

Can I set the above configuration? (type ‘yes‘ to accept): 



[[email protected] s1]# ./redis-cli

127.0.0.1:6379> cluster nodes

2628c7fa7630d544b7d4a727d563a49c68578240 192.168.23.154:6379 myself,slave cbfadb06673f7eb69483aa2031cb60fc4251fb7a 0 0 4 connected

38a05510f8014d7fdf7b9c606461ecaae5a47b2a 192.168.23.145:6379 master - 0 1483019113842 3 connected 10923-16383

75a81dbaeb8d46b0783adb3ab8aeec405608ca18 192.168.23.154:6381 slave 38a05510f8014d7fdf7b9c606461ecaae5a47b2a 0 1483019115859 6 connected

30c4755c49b228af5e111baa74dbebb85c4185c8 192.168.23.154:6380 slave 2160b439f59fafc3bb02fe920933284d5df3f39e 0 1483019114335 5 connected

cbfadb06673f7eb69483aa2031cb60fc4251fb7a 192.168.23.158:6379 master - 0 1483019114840 1 connected 0-5460

2160b439f59fafc3bb02fe920933284d5df3f39e 192.168.23.152:6379 master - 0 1483019110809 2 connected 5461-10922

127.0.0.1:6379> 


redis-cli做一个演示。。。  set username jack


[email protected] s1]# ./redis-cli -c

127.0.0.1:6379> set username jack

-> Redirected to slot [14315] located at 192.168.23.145:6379

OK

192.168.23.145:6379> set password 12345

-> Redirected to slot [9540] located at 192.168.23.152:6379

OK

192.168.23.152:6379> set email [email protected]

OK

192.168.23.152:6379> 



总结:学到这里算入门了!其他看个人修行了!!


(1)机器准备

机器            端口

192.168.175.30 7000(主)

192.168.175.30 7001(主)

192.168.175.30 7002(主)



192.168.175.30 7003(从)

192.168.175.30 7004(从)

192.168.175.30 7005(从)


(2)6台配置如下:

cluster-enabled yes                    开启集群状态

cluster-config-file nodes-6379.conf    集群的节点文件

并且改相应的端口。


安装依赖

yum install ruby 

 

 

(3)启动服务

./redis-server ./redis.conf &

 

./redis-trib.rb create --replicas 1 192.168.175.35:7000 192.168.175.35:7001 192.168.175.35:7002 192.168.175.35:7003 192.168.175.35:7004 192.168.175.35:7005


http://www.iyunv.com/thread-18781-1-1.html

https://rubygems.org/pages/download

 

yum install -y rubygems

 

gem install redis

具体看官网

https://redis.io/topics/cluster-tutorial


http://blog.csdn.net/u013820054/article/details/51354189


./configure -prefix=/usr/local/ruby


##########################################################################################################################

[[email protected] sbin]# ./redis-trib.rb create --replicas 1 192.168.175.35:7000 192.168.175.35:7001 192.168.175.35:7002 192.168.175.35:7003 192.168.175.35:7004 192.168.175.35:7005>>> Creating cluster

>>> Performing hash slots allocation on 6 nodes...

Using 3 masters:

192.168.175.35:7000

192.168.175.35:7001

192.168.175.35:7002

Adding replica 192.168.175.35:7003 to 192.168.175.35:7000

Adding replica 192.168.175.35:7004 to 192.168.175.35:7001

Adding replica 192.168.175.35:7005 to 192.168.175.35:7002

M: 01c5a90a07bb271d47e8845f3952f0b16743cecd 192.168.175.35:7000

  slots:0-5460 (5461 slots) master

M: 09f977342c6b09ed038522923b823676972418f2 192.168.175.35:7001

  slots:5461-10922 (5462 slots) master

M: acb67e8e1473caccde89e3262900997e83d27d8a 192.168.175.35:7002

  slots:10923-16383 (5461 slots) master

S: 7b544a3dbf307e0bc3be7bfd6b2a77369dd1a186 192.168.175.35:7003

  replicates 01c5a90a07bb271d47e8845f3952f0b16743cecd

S: 0c591fed13413dbb7987025f75ff43c0db32ff17 192.168.175.35:7004

  replicates 09f977342c6b09ed038522923b823676972418f2

S: bb2d0f0434ffa5e9b8cb8faed0d86d2d4b25a5ab 192.168.175.35:7005

  replicates acb67e8e1473caccde89e3262900997e83d27d8a

Can I set the above configuration? (type ‘yes‘ to accept): yes

>>> Nodes configuration updated

>>> Assign a different config epoch to each node

>>> Sending CLUSTER MEET messages to join the cluster

Waiting for the cluster to join....

>>> Performing Cluster Check (using node 192.168.175.35:7000)

M: 01c5a90a07bb271d47e8845f3952f0b16743cecd 192.168.175.35:7000

  slots:0-5460 (5461 slots) master

  1 additional replica(s)

M: acb67e8e1473caccde89e3262900997e83d27d8a 192.168.175.35:7002

  slots:10923-16383 (5461 slots) master

  1 additional replica(s)

M: 09f977342c6b09ed038522923b823676972418f2 192.168.175.35:7001

  slots:5461-10922 (5462 slots) master

  1 additional replica(s)

S: 0c591fed13413dbb7987025f75ff43c0db32ff17 192.168.175.35:7004

  slots: (0 slots) slave

  replicates 09f977342c6b09ed038522923b823676972418f2

S: bb2d0f0434ffa5e9b8cb8faed0d86d2d4b25a5ab 192.168.175.35:7005

  slots: (0 slots) slave

  replicates acb67e8e1473caccde89e3262900997e83d27d8a

S: 7b544a3dbf307e0bc3be7bfd6b2a77369dd1a186 192.168.175.35:7003

  slots: (0 slots) slave

  replicates 01c5a90a07bb271d47e8845f3952f0b16743cecd

[OK] All nodes agree about slots configuration.

>>> Check for open slots...

>>> Check slots coverage...

[OK] All 16384 slots covered.


redis 192.168.175.35:7000> cluster info

"cluster_state:ok\r\ncluster_slots_assigned:16384\r\ncluster_slots_ok:16384\r\ncluster_slots_pfail:0\r\ncluster_slots_fail:0\r\ncluster_known_nodes:6\r\ncluster_size:3\r\ncluster_current_epoch:6\r\ncluster_my_epoch:1\r\ncluster_stats_messages_sent:256\r\ncluster_stats_messages_received:256\r\n"


redis 192.168.175.35:7000> cluster nodes

"acb67e8e1473caccde89e3262900997e83d27d8a 192.168.175.35:7002 master - 0 1489409919371 3 connected 10923-16383\n09f977342c6b09ed038522923b823676972418f2 192.168.175.35:7001 master - 0 1489409918315 2 connected 5461-10922\n0c591fed13413dbb7987025f75ff43c0db32ff17 192.168.175.35:7004 slave 09f977342c6b09ed038522923b823676972418f2 0 1489409915217 5 connected\nbb2d0f0434ffa5e9b8cb8faed0d86d2d4b25a5ab 192.168.175.35:7005 slave acb67e8e1473caccde89e3262900997e83d27d8a 0 1489409917264 6 connected\n7b544a3dbf307e0bc3be7bfd6b2a77369dd1a186 192.168.175.35:7003 slave 01c5a90a07bb271d47e8845f3952f0b16743cecd 0 1489409921497 4 connected\n01c5a90a07bb271d47e8845f3952f0b16743cecd 192.168.175.35:7000 myself,master - 0 0 1 connected 0-5460\n"



[[email protected] sbin]# redis-cli -p 7000 cluster nodes | grep master

acb67e8e1473caccde89e3262900997e83d27d8a 192.168.175.35:7002 master - 0 1489414087200 3 connected 10923-16383

09f977342c6b09ed038522923b823676972418f2 192.168.175.35:7001 master - 0 1489414088131 2 connected 5461-10922

01c5a90a07bb271d47e8845f3952f0b16743cecd 192.168.175.35:7000 myself,master - 0 0 1 connected 0-5460



################

[[email protected] sbin]# pwd

/root/soft/7000/redis/sbin

[[email protected] sbin]# ./redis-cli  -c -p 7000

127.0.0.1:7000>


[[email protected] sbin]# ./redis-cli  --help

redis-cli 3.2.6


Usage: redis-cli [OPTIONS] [cmd [arg [arg ...]]]

 -h <hostname>      Server hostname (default: 127.0.0.1).

 -p <port>          Server port (default: 6379).

 -s <socket>        Server socket (overrides hostname and port).

 -a <password>      Password to use when connecting to the server.

 -r <repeat>        Execute specified command N times.

 -i <interval>      When -r is used, waits <interval> seconds per command.

It is possible to specify sub-second times like -i 0.1.

 -n <db>            Database number.

 -x                 Read last argument from STDIN.

 -d <delimiter>     Multi-bulk delimiter in for raw formatting (default: \n).

 -c                 Enable cluster mode (follow -ASK and -MOVED redirections).

 --raw              Use raw formatting for replies (default when STDOUT is

not a tty).

 --no-raw           Force formatted output even when STDOUT is not a tty.

 --csv              Output in CSV format.

 --stat             Print rolling stats about server: mem, clients, ...

 --latency          Enter a special mode continuously sampling latency.

 --latency-history  Like --latency but tracking latency changes over time.

Default time interval is 15 sec. Change it using -i.

 --latency-dist     Shows latency as a spectrum, requires xterm 256 colors.

Default time interval is 1 sec. Change it using -i.

 --lru-test <keys>  Simulate a cache workload with an 80-20 distribution.

 --slave            Simulate a slave showing commands received from the master.

 --rdb <filename>   Transfer an RDB dump from remote server to local file.

 --pipe             Transfer raw Redis protocol from stdin to server.

 --pipe-timeout <n> In --pipe mode, abort with error if after sending all data.

no reply is received within <n> seconds.

Default timeout: 30. Use 0 to wait forever.

 --bigkeys          Sample Redis keys looking for big keys.

 --scan             List all keys using the SCAN command.

 --pattern <pat>    Useful with --scan to specify a SCAN pattern.

 --intrinsic-latency <sec> Run a test to measure intrinsic system latency.

The test will run for the specified amount of seconds.

 --eval <file>      Send an EVAL command using the Lua script at <file>.

 --ldb              Used with --eval enable the Redis Lua debugger.

 --ldb-sync-mode    Like --ldb but uses the synchronous Lua debugger, in

this mode the server is blocked and script changes are

are not rolled back from the server memory.

 --help             Output this help and exit.

 --version          Output version and exit.


Examples:

 cat /etc/passwd | redis-cli -x set mypasswd

 redis-cli get mypasswd

 redis-cli -r 100 lpush mylist x

 redis-cli -r 100 -i 1 info | grep used_memory_human:

 redis-cli --eval myscript.lua key1 key2 , arg1 arg2 arg3

 redis-cli --scan --pattern ‘*:12345*‘


 (Note: when using --eval the comma separates KEYS[] from ARGV[] items)


When no command is given, redis-cli starts in interactive mode.

Type "help" in interactive mode for information on available commands

and settings.


本文出自 “梁小明的博客” 博客,请务必保留此出处http://7038006.blog.51cto.com/7028006/1913214

以上是关于一步一步学习redis3.2.8的主要内容,如果未能解决你的问题,请参考以下文章

一步一步学习大数据系列

一步一步学习Vue

一步一步学习SignalR进行实时通信_7_非代理

一步一步学习JNI

一步一步学习JNI

一步一步学习Vue