一步一步学习redis3.2.8
一步一步学习redis3.2.81、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命令持久化数据到磁盘
或者
# redis-cli set> OK
# redis-cli get> "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
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单线程的内存字典服务器。。。 过期时间=》 kv结构。
SET key value
缓存,和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
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
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 => 几M就搞定了。。。
C#: BitArray [位数组]
Redis位运算:
SETBIT key offset value=> String的value大小是512M 【数据传输太慢了】 【多而小
的数据】
String的value大小是512M
static int checkStringLength(client *c, long long> if (size > 512*1024*1024) {
addReplyError(c,"string exceeds maximum allowed> 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 => 获取1的个数
BITOP operation destkey key => AND OR XOR NOT
对一个或多个保存二进制位的字符串 key 进行位元操作,并将结果保存到 destkey 上。
00000001 => 1
& 00000010 => 2
--------------
00000000 => 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双向结构
一:ListJAVA,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 【redis做催付订单,卖家发货,签收提醒】
LPOP key
RPUSH key 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 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 stopO(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 regularIDregularEntity>
regularIDregularEntity> 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. 短信通道
sellernickchannel1
sellernickchannel2
HDEL key 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 批量的执行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: 看一下集合中是否有命中该customeridO(1)
“上海” areaid: 看一下集合中是否包含。。。
如果两项都命中,那么我们直接发送“推荐”的彩信和邮件。。。。h5。
1. query,我们基本上做到了O(1)cluster集群
2. maintain 维护
二:常见命令
1. SADD
SADD key 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
并集: SUNION key
差集: SDIFF key
4. SCARD key获取Set的元素个数
5. SPOP key 随机弹出一个元素并且移除。。
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 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 根据
优先级队列:
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数字。。。
set2016-12-26 192.168.10.121 192.168.10.122 192.168.10.123192.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
pfcount: PFCOUNT key
pfmerge:
2. 弊端:有一定的错误率。。。 用错误率换取空间。。。0.81% 。。。
二:Sort 【一个排序】 对key进行操作的。。
SORT key
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
uidusername_{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_*->namedesc
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的一些特性。。。弱化。。。
create
commit
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
multi
incr num
exec【取消】
client incr num
《1》不用watch
incr :生成订单号。。。。 discard。。。
watch的本意就是要保证在mutli的过程中,数据必须是干净的。。。。
redisDb中有一个watched_keys
10、pub与sub
一:发布订阅模式
1. 观察者模式 【设计模式中的一种】.netWPF 中就有一种MVVM模式。。
js knockoutjs mvvm模式。。。
subject
subscribesubcribesubcribesubcribe
SUBSCRIBE 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.itornew.sport
*:正则字符
PSUBSCRIBE pattern => p 模式。。。
MQ: Rabbitmq 【发布订阅模式】
client ->mq->server 【长连接】
# 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端推送大量的消息,,, 1s100
这时候server并不能快速的处理,,,, logic process..... 而且读取db,soa webapi...
这时候server不能及时处理,导致大量积压。。。 【1:memory挂掉。。。
2:cpu 100%
3:容易丢失消息】
二:源码
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....
2.第一种,初始化设置。。。set
第二种:后期更改
第三种:过期变成持久。。。
SET key value
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 设置最大的内存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监控
# redis-cli --stat
------- data ------ --------------------- load -------------------- - child -
keys mem clients blocked requests connections
5 843.38K3 0 52 (+0) 6
5 843.38K3 0 53 (+1) 6
5 843.38K3 0 54 (+1) 6
5 843.38K3 0 55 (+1) 6
5 843.38K3 0 56 (+1) 6
5 843.38K3 0 57 (+1) 6
5 843.38K3 0 58 (+1) 6
5 843.38K3 0 59 (+1) 6
12、batchcommit性能优化
一:redis 两点性能优化。。。
1. 批量提交
mset 。。。。 驱动,。。。。
千人千面的时候,需要有一个数据初始化。。。
400w - 500w customerid
customerid_122
customerid_221
customerid_314
操作400w- 500wtcp链接。。。。 几个G。。。【1h】
mset
mset customerid_1 22customerid_221....
网络卡死 +超时。。。。
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 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.toArray(strlist);
redis.mset(strlist); //batch
System.out.println("success");
}
2. 多命令
msetstring的批量
hmset hash的批量
saddset的批量
如果做到三种命令的混合呢???
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> 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 usernamejack
=>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
(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有密码,可以在这里配置。。。
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-1192.168.23.158 master
2. centos-2192.168.23.152 slave1
3. centos-3192.168.23.145 slave2
4. centos-4192.168.23.154放三台 sentinel。。。。
《1》 sentinel:
port
monitor masterhost masterip
客观下线: quorum[阈值]
主观下线: 下线的标准 【】 15s,30s。1min。。。
其余的采用默认配置。。。
sentinel auth-pass =》 master 有密码,在这地方设置。。。
sentinel monitor
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-sentinelsentinel.conf
./redis-sentinelsentinel.conf
./redis-sentinelsentinel.conf
ps -ef | grepredis
当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
redisclient-win32.x86.2.0.exe
有了可视化工具,就不用每次都输入命令去查看。。。
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
# python
Python 2.7.5 (default, Nov 20 2015, 02:00:19)
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
1083mkdir /usr/local/python27
1084cd Python-2.7.5
1085ll
1086./configure --prefix=/usr/local/python27
1087make
1088make install
1089python
1090mv /usr/bin/python /usr/bin/python2.6.6
1091ln -s /usr/local/python27/bin/python /usr/bin/python
1132tar zxvf setuptools-0.6c11.tar.gz
1133cd setuptools-0.6c11
1134python setup.py build
1135python setup.py install
1136cd ../pip-8.1.2
1137python setup.pybuild
1138python setup.pyinstall
# 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 脚本。。。
我的配置文件如下:
# 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
# ./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):
# ./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
root@localhost s1]# ./redis-cli -c
127.0.0.1:6379> set username jack
-> Redirected to slot located at 192.168.23.145:6379
OK
192.168.23.145:6379> set password 12345
-> Redirected to slot located at 192.168.23.152:6379
OK
192.168.23.152:6379> set email 3234234@qq.com
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
##########################################################################################################################
# ./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
All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
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"
# 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
################
# pwd
/root/soft/7000/redis/sbin
# ./redis-cli-c -p 7000
127.0.0.1:7000>
# ./redis-cli--help
redis-cli 3.2.6
Usage: redis-cli ]]
-h Server hostname (default: 127.0.0.1).
-p Server port (default: 6379).
-s Server socket (overrides hostname and port).
-a Password to use when connecting to the server.
-r Execute specified command N times.
-i When -r is used, waitsseconds per command.
It is possible to specify sub-second times like -i 0.1.
-n Database number.
-x Read last argument from STDIN.
-d 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-historyLike --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 Simulate a cache workload with an 80-20 distribution.
--slave Simulate a slave showing commands received from the master.
--rdb Transfer an RDB dump from remote server to local file.
--pipe Transfer raw Redis protocol from stdin to server.
--pipe-timeoutIn --pipe mode, abort with error if after sending all data.
no reply is received withinseconds.
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 Useful with --scan to specify a SCAN pattern.
--intrinsic-latencyRun a test to measure intrinsic system latency.
The test will run for the specified amount of seconds.
--eval Send an EVAL command using the Lua script at .
--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.
页:
[1]