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 结构
中文网学习地址 http://www.redis.cn/commands.html#string
一: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>
JS: BufferArray数组
###########非常重要#################################################################
(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结构
一:Hash Map, Dictionry
键值对 Array 关联数组
redis ,c语言中没有这种结构,,,redis自己实现了一个。。。
hash函数:
k,v => 映射到数组中 Array
index = gethashcode( k) % array.length
array[index]=[k,v];
HSET key field value
key: reidsObject ptr->sds
value:redisObject ptr->dict =[key=field,vaue=value]
Dic => Dic [key:redisObject ptr=>SDS value:redisObject ptr=>SDS]
例子#
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>
int hashTypeSet(robj *o, robj *field, robj *value) {}
Map,HashTable 原理都是一样的。。。
一: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
(5)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集合。。。
(6)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产品。
(7)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>
复杂度不低的。。而且能不用就不用。。。毕竟以性能为代价。。。
(8)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
(9)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)
(9)过期键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
(10)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");
}
}
(11)lua脚本
(12)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文件中。。。【缩小了文件的尺寸】
(13)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 = ConnectionMultiplexer.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");
}
(14)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
(15)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
}
}
(16)redis3集群
一: 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>
总结:学到这里算入门了!其他看个人修行了!!