文章目录
redis详细介绍
简单介绍
中文网
英文网
redis是单线程/单进程/单实例的,所谓单线程指的是对数据的处理是“顺序执行”的,但redis可以同时多线程处理不同的业务。
redis底层kenrel采用的是epoll(有关epoll的发展历程后续会更新)。
redis类似于mysql的数据库,默认有16个库,分别为0-15,每个库中的数据是相互隔离的。
基础知识
以下先介绍redis相关的基础知识:
- 常识 ,磁盘的寻址是ms级别的,内存的寻址是ns级别的,redis是基于内存级别的数据库,所以很快;OS无论读多少,都是最少4K从磁盘中拿出来的,所以读出来的大小一定是4K的倍数。
- 关系型数据库,建表时,需要给出schema,字段需要给出数据类型及字节宽度;存储时,是按照行级存储的;关系型数据库的索引,在磁盘中是B+树的结构,在表很大时,增删改查会变慢,从查询的角度来说,单个或少量的查询依旧会很快,但是,并发量很大时磁盘带宽会成为瓶颈。
- 缓存,memcached的value没有类型的区分,都是string型的,若要存储对象,可以用json字符串,但是,取单个元素时需要把整个json字符串获取回来,然后在IO层面用代码实现;redis的value值有不同的类型,每个类型都带有自己的实现方法;实现了计算向数据移动。
redis的安装
前提
- OS的版本需要与redis匹配,否则会出现make安装不成功的问题
- 安装wget,
yum install wget
- 需要安装gcc,因为redis时C实现的,
yum install gcc
- 为了方便管理,安装后最好把可执行程序迁出。
安装步骤
1.yum install wget
2.cd #回到家目录
3.mkdir soft #创建soft文件夹,将redis安装在此文件夹中
4.cd soft #进入此文件夹
5.wget redis路径 #下载redis压缩包
6.tar xf xxx.tar.gz #解压下载的压缩包
7.cd redis/src #查看src下目录结构
8.vi README.md #查看README文件,基本了解相关信息
9.make #编译redis用
#需要先安装
yum install gcc
make disclean #make安装有问题时,先clean,再重新安装
10.make #重新安装make
11.cd src #生成可执行文件
12.cd ..
13.make install PREFIX=/opt/redis/redis5
14.vi /etc/profile #配置环境变量
export REDIS_HOME=/opt/redis/redis5
export PATH=$PATH:$REDIS_HOME/bin
15.source /etc/profile #执行配置文件
16.cd utils
17../ install_server.sh #运行redis
redis数据类型
二进制安全,redis是二进制安全的,具体的编码类型需要事先外界定义好,redis中存储的是字节流/字符流;若是utf-8格式的,可以用redis-cli --raw
查看中文字样。
索引,redis中有正向索引/负向索引,正向索引从左至右为0,1,2,……,负向索引从右至左为-1,-2,-3,……。
key的操作,查看value的类型,type:value
;查看value的编码,object encoding
String
1.字符串角度
命令 | 描述 | 返回值 |
---|---|---|
set key value | 设置指定 key 的值 | SET 在设置操作成功完成时,才返回 OK |
get key | 获取指定 key 的值 | 返回 key 的值,如果 key 不存在时,返回 nil。 如果 key 不是字符串类型,那么返回一个错误。 |
getrange key start end | 返回 key 中字符串值的子字符 | 截取得到的子字符串 |
getset key value | 将给定 key 的值设为 value ,并返回 key 的旧值(old value) | 返回给定 key 的旧值。 当 key 没有旧值时,即 key 不存在时,返回 nil |
mget key [key …] | 获取所有(一个或多个)给定 key 的值 | 返回 一个包含所有给定 key 的值的列表 |
mset key value [key value …] | 同时设置一个或多个 key-value 对 | 设置成功返回ok |
strlen key | 返回 key 所储存的字符串值的长度 | 字符串值的长度。 当 key 不存在时,返回 0 |
setnx key value | 指定的 key 不存在时,为 key 设置指定的值 | 设置成功,返回 1 。 设置失败,返回 0 |
msetnx key value [key value …] | 所有给定 key 都不存在时,同时设置一个或多个 key-value 对 | 当所有 key 都成功设置,返回 1 。 如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0 |
2.数值角度
命令 | 描述 | 返回值 |
---|---|---|
incr key | 将 key 中储存的数字值+1 | 返回old值+1之后的值 |
incrby key +count | 将key中的value值+count | 返回old值+1之后的值 |
incrbyfloat key +count | 将key中的value值+count(浮点数) | 返回的值的类型是float |
数值使用场景
在并发场景下,为了规避对数据库的事务操作,可以使用redis内存代替,例如:商品秒杀,商品详情页的点赞数,评论数等数据准确性要求不那么高的可以使用。
3.位图角度
命令 | 描述 | 返回值 |
---|---|---|
setbit key offset | 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit) | 指定偏移量原来储存的位 |
bitcount key start end | 从start到end设为1的个数 | 设为1的个数 |
bitop operation destkey key [key …] | 对一个或多个key进行位元操作(and、or、xor、not) | 保存到destkey的字符串长度 |
bitpos key bit [start] [end] | 返回key中第一个被设为1或0的位 | value中第一个被设为1或0的位 |
位图说明
位图每一位非0即1;setbit k1 1 1
,长度为1;setbit k1 8 1
,长度为2;
位图使用场景
- 用户系统,统计随即窗口用户的登录天数(用户为key)
setbit sean 1 1 #sean第一天登录
setbit sean 7 1 #sean第7天登录
setbit sean 364 1 #sean第364天登录
strlen sean #sean总共登录的天数
bitcount sean -2 -1 #sean最后两天登录的次数
- 电商系统做活动送礼,统计随即窗口的活跃用户数(时间为key)
setbit 20200603 1 1 #用户1在20200603登录
setbit 20200604 1 1 #用户1在20200604登录
setbit 20200604 7 1 #用户7在20200604登录
bitop or destkey 20200603 20200604 #20200603与20200604登录的用户记录
bitcount destkey 0 -1 #返回20200603与20200604登录的用户数
list
list是有序的,这里的有序指的是按插入顺序有序。
指令
指令 | 描述 | 返回值 |
---|---|---|
lpop/rpop key | 移除并返回列表左边/右边的第一个元素 | 列表左边/右边的第一个元素,key不存在时返回nil |
lpush/rpush key v1 v2 … | 给列表中插入一个或多个元素,key不存在时报错 | 列表元素的个数 |
ltrim key start end | 删除start — end范围外的元素 | 执行成功返回true |
lrange key start end | 取出start — end之间的元素 | 列表,区间的元素 |
lindex key index | 通过索引获取列表中的元素 | 下标为index的元素 |
linsert key before/after oldV newV | 在oldV之前/后插入newV | 若插入成功,返回list大小;若未找到oldV,返回-1;若未找到key,返回0 |
blpop/brpop list1 list 2 … listn timeout | 移除并获取列表的第一个元素 | 若列表中有元素,则返回第一个元素,若没有元素,则阻塞直至有元素,或等待时间超过timeout返回nil |
使用场景
- 作为栈使用,用
lpush/lpop
或者rpush/rpop
同向指令,实现先进后出; - 作为队列使用,用
lpush/rpop
或者rpush/lpop
逆向指令,实现先进先出; - 作为数组使用,用
ltrim/lrange/lindex/linsert before/linsert after
等指令,实现数组的插入/按下标获取值; - 作为阻塞队列使用,用
blpop/brpop
实现单播阻塞队列,也是FIFO原则。
hash
hash类型的map(k,v)
的形式存储的;
也可以对filed中的数字进行计算。
指令 | 描述 | 返回值 |
---|---|---|
hmset key field1 value1 field2 value2 … fieldn valuen | 同时将多个filed value 存入hash表中 (覆盖原有值) | 若执行成功,返回ok |
hmget key field1 field2 … fieldn | 取出hash表中,一个或多个给定字段的值 | 给定字段的值,若没有则返回nil |
hset key field value | hash表中字段赋值 | 赋值成功,若原来没有则返回1,若原来有被覆盖返回0 |
hget key field | 获取执行字段的值 | 返回指定字段的值,若不存在,返回nil |
hgetall key | 返回key的所有字段和值 | 若不存在返回nil,存在返回字段和字段值 |
hexists key field | 指定字段是否存在 | 存在返回1,不存在返回0 |
hincrby(float) key field increment | 字段加上指定值 | 计算之后的值 |
hlen key | 获取hash表中字段的数量 | 返回数量,不存在时返回0 |
hdel key field1 … fieldn | 删除指定字段 | 删除成功的字段数量 |
hvals key | 返回所有字段的值 | 所有值的表,不存在时返回nil |
hkeys key | 返回所有字段名 | 字段名的表,不存在时返回nil |
hsetnx key field value | 为不存在的字段赋值 | 成功返回1,已存在返回0 |
指令
使用场景
- 可以用来实现电商平台的商品详情页,将商品信息(点赞数/收藏数/详细信息等)作为对象放入filed中存储,方便展示。
set
set是无序的,同时也做了去重。
指令
指令 | 描述 | 返回值 |
---|---|---|
sadd key val1 … val2 | 将元素添加到集合中 | 添加成功的数量 |
srandmember key count | 返回集合中的随机元素 | 包含count元素的数组 count为正数:去重,个数不能保证满足;count 为负数,个数保证满足,未去重; |
smembers key | 获取key中的所有元素,不推荐使用 | 返回所有元素 |
scard key | 获取集合中元素的数量 | 集合的数量,不存在时返回0 |
srem key v1 … vn | 移除集合中的指定元素 | 被成功移除的元素个数 |
sismember key value | 判断成员元素是否是集合的成员 | 是,返回1,否或不存在,返回0 |
SSCAN key cursor [MATCH pattern] [COUNT count] | 迭代集合中键的元素 | 数组列表 eg:sscan myset1 0 match h* |
spop key | 随机移除集合中的一个元素 | 被取出的随机元素,若未空,则返回nil |
smove oldkey newkey value | 将oldkey中的元素value移动到newkey的集合中 | 移动成功,返回1,未移动,返回0 |
sdiff/sdiffstore (deskey) key key1 … keyn | 获取给定集合的差集,xxxstore是将结果存储在deskey中 | 差集元素列表;xxx时返回deskey元素的个数 |
sinter/sinterstore (deskey) key key1 … keyn | 获取给定集合的交集 | 交集元素列表 |
sunion/sunionstore (deskey) key1 key2 … keyn | 获取给定集合的并集 | 并集元素列表 |
使用场景
抽奖的情况(随机):
- 礼品数少于人数的情况,用
srandmembers
实现,参数用正数,返回已经去重的结果集,且数量不会超过已有的值,实现不是所有人都可以领到奖品; - 礼品数多余人数的情况,用
strandmembers
实现,参数用负数,返回的结果有重复值,且数量一定满足,实现所有奖品都被发放; - 公司年会的抽奖活动,用
spop
实现,选中并从列表中删除该元素,实现同一员工不会重复中奖的情况。
zset(sorted set)
- zset是有序的,是按照score排序的,sorce是排序的规则。
- zset在物理内存中是左小右大的,不会随命令的执行而发生变化。
- 排序的底层是用跳跃表实现的,牺牲一定的空间换取时间,跳跃表的增删改查不一定是最优的,只是平均值相对优先,跳跃表层级的创建是随机的。
指令
指令 | 描述 | 返回值 |
---|---|---|
zadd key score1 value1 … scoren valuen | 将一个或多个成员元素及其分数值加入到有序集当中 | 添加成功数量 |
zlexcount key min max | 获取指定区间成员的数量 | 指定区间成员的数量 |
zrevrank key member | 有序集中成员的排名 | 有则返回排名(从0开始),无则返回nil |
zincrby key increment member | member的score+increment | 增加后的score |
zremrangbyrank key start stop | 移除有序集合中指定区间的元素 | 被移除成员的数量 |
zremrangbyscore key min max | 移除指定分数之间的元素 | 被移除成员的数量 |
zinterstore | 取交集 | 目标key中成员的数量 |
zunionstore | 取并集 | 目标key中成员的数量 |
使用场景
- 取出排名的前几位,后几位。
进阶使用
管道
类似于linux的管道,需要安装nc,yum install nc
;若需要将多个命令一起发给服务端时,各命令间用换行符连接。
发布/订阅
指令
publish/subscribd #有订阅才可以发布成功
使用场景
- 直播室消息聊天,可以监听聊天消息
- 实时聊天信息,对于实时性的消息,可直接用发布订阅模式;对于历史性的消息,可以用redis的缓存技术,将热数据(3天内)存储下来,可用zset存储,历史数据作为全量数据存储到数据库中。
事务
redis 的事务不同于mysql的事务,redis事务是不支持回滚的;
redis 事务的实现,是将待执行的一组命令放在同一个事务中,然后触发执行。
实现过程
multi
开启事务,然后把要执行的命令放入队列中,注意此时不是立即执行的。exec
触发事务队列中的命令执行,执行顺序不是按照开启事务的先后顺序,而是按照该指令触发的先后顺序决定的,在执行的过程中,只执行正确的指令。watch
指令可以观察key在事务执行中的变化,此处用的是乐观锁的机制。
布隆过滤器
安装
1、redis.io ——> modules #访问redis 的官网,点击modules
2、访问redisBloom的github
3、wget *.zip #下载redisBloom的压缩包
4、yum install unzip #安装解压zip文件的工具
5、unzip *.zip #解压下载后的安装包
6、cd RedisBloom-master #进入解压后的文件
7、make #编译
8、cp redisbloom.so /opt/gaoyutao/redis5/redisbloom.so #拷贝可执行文件到指定目录,方便管理
9、cd /opt/gaoyutao/redis5/ #进入可执行文件所在目录
8、redis-server --loadmodule /opt/gaoyutao/redis5/redisbloom.so #启动
--------成功--------
redis-cli #访问
实现原理
把数据库中有的数据用bitmap(位图)表示,client访问穿透了不存在的也要做标记,value值标为0,尽可能地避免再次穿透;client请求时,先经过映射函数,但是这种操作不是绝对的,是一种概率事件,有时候即使数据库有也会被误标记。
布隆过滤器是为了处理缓存穿透问题。
实现方式
- client中实现bloom,redis server不做处理
- client中包含bloom算法,bitmap存储在redis server中
- client中不做处理,redis server中集成bloom
指令
bf.add key value
插入bf.exists
判断是否存在
弊端
- 只能增加不能删除,可以设置空的key
- 可以采用布谷鸟过滤器
作为缓存和数据库的区别
缓存和数据库的侧重点
- 由于内存容量有限,缓存中存放的是热数据,随着业务的累积,缓存中的数据是变化的,缓存注重的是速度。
- 数据库中存储的是全量的数据,注重的数数据的持久性和全量。
缓存数据的清除
1.key过期策略
key过期清除的方式是由业务推导实现的。
1.1 实现方式
set key value expire xxx #设置有效期
set key value expireat xxx #定时
1.2 判定原理
判定key过期有两种方式,一种是在访问的时候,发现key已经过期,清除掉(主动判定);另一种是redis server会有轮询机制,周期性地查看key是否过期,每次查看总量的25%,也就是说,最多有25%的过期key会被清除(被动判定)。
2.内存淘汰策略,冷数据回收
内存淘汰冷数据是随着业务的运转需要做的。
在redis的配置文件中,可以配置redis内存容量,指定maxmemory,范围设为1G——10G,超出内存时,可以通过maxmemory-policy指定回收策略。
回收策略
策略 | 描述 |
---|---|
noeviction | 默认策略,内存不足时,新写入操作会报错。不推荐。 |
allkeys-lru | 内存不足时,在键空间中,移除最近最少使用的 Key。推荐 |
allkeys-random | 内存不足时,在键空间中,随机移除某个 Key。不推荐。 |
volatile-lru | 内存不足时,在设置了过期时间的键空间中,移除最近最少使用的 Key。在redis既做缓存又做持久化存储时可以采用。 |
volatile-random | 内存不足时,在设置了过期时间的键空间中,随机移除某个 Key。不推荐。 |
volatile-ttl | 内存不足时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。不推荐。如果没有对应的键,则回退到noeviction策略。 |
redis作为缓存常见问题
问题 | 描述 | 解决方案 |
---|---|---|
缓存击穿 | 在高并发的场景下,某个key过期被清理,造成同一时间大量并发到达数据库 | 使用互斥锁,用setnx设置一个key,设置成功再去操作db,失败则get key,直至获得锁。 |
缓存穿透 | client查询业务中没有的数据,直接访问数据库 | 布隆过滤器 |
缓存雪崩 | 大量的key在同一时间过期失效,间接造成该事件大量访问到达数据库 | 1.随即设置过期时间(时点性无关);2若时间要求固定时(eg:0点更新数据),业务层加判断,依赖击穿方案(分布式锁) |
互斥锁问题:若当前访问发生故障,未释放锁,会造成死锁,需要设置锁的过期时间;设置了锁的过期时间之后,若锁超时,但任务未执行完,会出现拥塞,用多线程来实现,A线程操作db,B线程监控锁是否超时,同步更新锁过期时间。
持久化(单机)
RDB
RDB是对当前数据做一个快照/副本,是具有时点性的,即保存的是某一时间点的数据;
1.实现过程
实现过程是非阻塞的,不会影响server端对外提供服务,会重新启动一个子线程来完成数据的落地,由父线程响应client。
原理是,在linux中,子线程与父线程是数据隔离的,数据不会相互影响,能够有效地保障时点的正确性。fock创建子进程,而且fock的速度快,空间小;copy on write 写时复制,在创建子进程时不会进行复制,实现数据的隔离。
实现方式是用save/bgsave
指令,save
指令一般不会使用,只有在关机时会触发。bgsave
的也是配置save
标识,配置方式为:
save 900 1
save 300 10
save 60 10000
dbfilename.dump.rdb #(文件名)
dir /var/lib/redis/6379 #(文件路径)
2.优势
- 数据恢复快,恢复的过程类似java的序列化
3.弊端
- RDB不支持拉链,只能手动维护文件,下一次备份会覆盖原文件
- RBD丢失的数据量比较多,会丢失一个时间点的数据
AOF
AOF,全称是append only file,备份的是增量数据,把redis的写操作记录到文件中。
若AOF与RDB同时开启,redis server重启后只会选择用AOF恢复数据。
1.优势
- 数据丢失少
2.弊端
- AOF文件的体量过大,恢复慢
3.发展
before 4.0,执行bgrewrite(重写),会把重复指令合并,可以抵消的指令删除,例如:
set k1 ooxx;
set k1 xxoo;
set k2 hello;
重写之后,第一条给k1赋值的指令就会被删除,最后生成的是纯指令的日志文件。
after 4.0,执行bgrewrite(重写),server中原有的老数据会触发ROB,落地到aof文件中,之后的增量指令继续存到aof文件中,此时的日志文件是aof与RDB的混合。
持久化的实现
appendonly yes
appendfilename “appendonly.aof"
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
appendfsync always
appendfsync everysec
appendfsync no
aof-use-rdb-preamble yes
此处,appendfsync
的配置有3种情况,分别是always
、everysec
、no
,第一种数据最可靠,第二种会丢失~1s的数据,第三种丢失的数据最多,为1个buf;原因是redis是内存数据库,每次写操作都会触发IO,需要执行flush把数据持久化到磁盘,alway是立刻flush,everysec是每秒flush一次,no是等缓存中数据满了一个buf才会flush。
集群
单机问题
- 会发生单点故障,若server发生故障,会造成整个业务的下线。
- 会受内存容量的影响,数据量过大,会出现内存不够的问题。
- server会存在访问压力,所有client端都会访问一台server,响应时间会非常慢。
redis模式
推导
采用一变多的形式,选择多台server,但是,多台server需要考虑CAP原则。
**数据一致性(C)**可以采用以下三种形式:
- 同步阻塞,具体是指所有节点同步阻塞,直到数据一致,这是一种强一致性,会破坏可用性。
- 异步,是弱一致性的,适用于可容忍一部分数据丢失的场景。
- 中间件同步阻塞,确保数据的最终一致性,此种方式是利用中间件(如kafka)的可靠性、高效性来实现数据的最终一致,中间过程也会有数据不一致的现象出现。
分区容忍性(P)
- 主机故障后,备机会采用投票的形式选出新主,但是,投票通过数需要过半,否则,势力范围不够,会出现脑裂即网络分区的现象。
主HA(高可用)(A)
- 给主添加备机,组成集群,主故障以后,从备机中选一台做主机,继续提供服务;集群一般会选择奇数台,因为,相比较下一个偶数来说,风险相同,但是,成本会更高。如:5台和6台的话,都是有3台投票通过,就可以选出主,很明显6台的成本高于5台。
主从复制(master/slave)
主从复制采用的是异步非阻塞的方式来实现数据一致性,从挂机后重新启动,重新追随主以后,就会自动同步主的数据;
配置
- 启动时通过
replicaof
去追随主,用replicaof none
放弃追随。 - 配置文件配置
reolica-server-stale-data yes #开启让别人查
replica-read-only yes #备机是否只支持查询(只读模式)
repl-diskkess-sync no #是否通过磁盘传输RDB文件
repl-backlog-size 1mb #no 通过网络传输
min-replicas-to-write #增量复制
min-replicas-max-lag #规定最少几个写成功
解决问题
- 可以解决单点故障的问题,也可以通过读写分离的方式,来缓解主的访问压力,但是没有解决容量问题,因为主备的数据都是全量复制的。
弊端
- 主的故障问题需要人工去维护。
哨兵(sentinel)
sentinel的作用是监控redis-server的运行状态,从而实现故障的自动转移,所谓故障自动转移是指,sentinel监测主机故障之后,从会自动通过投票方式选出新主,其他salve追随,不需要手动去维护。
sentinel之间的通信是通过redis的发布/订阅方式来实现的。
sentinel依旧没有解决内存容量的问题。
配置
redis-server ./6379.conf --sentinel
redis-sentinel #启动哨兵
psubscribe * #可查看哨兵之间发布的消息
#哨兵配置文件(redis源码目录)
port 26379
sentinel monitor mymaster 127.0.0.1 6381 2
集群
集群是redis的分布式数据库的方案。
1.数据分布
若数据可以拆分,则在client按照业务、逻辑等将数据拆分,若数据不可拆分,需要用sharding分区的方式进行拆分、共享,以此来解决容量有限的问题
sharding分片
倾向于用redis做缓存,不适用于数据库,每个节点存储的数据都是完整的。
- hash取模,用redis的台数作为模数。这种方式的弊端是,模数是固定的,若redis台数变化的话,对应数据的存放就会造成全局洗牌,非常不利于分布式下的扩展性,一般不常用。
- 随机(random)分片。可以用于消息队列的场景,指定client写数据操作同一个key,其他client消费。这种分片方式不适用于其他业务。
- hash分片(一致性hash算法(kemata))。此种方式是将data、node都参与到映射算法中。
- 实现方式是先规划一个环形hash环,然后node先进行映射算法,得到映射点,新增data时找到距离最近的node节点,hash环上被映射到的node节点是物理节点,剩下的点是虚拟节点,设定虚拟节点是为了解决环上数据倾斜的问题。
- 优点,可分担其他节点的压力,不会造成节点的全局洗牌;
- 缺点,造成一部分数据不能命中,会造成一部分请求穿透缓存直接到达数据库,针对这种问题,可以在获取数据的时候,从距离最近的两个node去取,尽可能地提高命中率。
2.代理分区
上述sharding分区方案,分区实现逻辑需要client实现,redis server 的连接成本依旧很高,可以采用proxy,来缓解连接压力。
常用的代理分区主要有,twemproxy,predixy,codis
3.查询路由方案
client随机地 请求任意一个 Redis 实例,然后由 Redis 将请求 重定向 到 正确 的 Redis 节点。Redis Cluster 实现了一种 混合形式 的 查询路由,但并不是 直接 将请求从一个 Redis 节点 转发 到另一个 Redis 节点,而是在 客户端 的帮助下直接 重定向( redirected)到正确的 Redis 节点。
- 优点:无主模型,数据按照 hash槽 存储分布在多个 Redis 实例上,可以平滑的进行节点 扩容/缩容,支持 高可用 和 自动故障转移,运维成本低。
- 缺点:严重依赖 Redis-trib 工具,缺乏 监控管理,需要依赖 Smart Client (维护连接,缓存路由表,MultiOp 和 Pipeline 支持)。Failover 节点的 检测过慢,不如 中心节点 ZooKeeper 及时。Gossip 消息具有一定开销。无法根据统计区分 冷热数据。
API
SpringData Redis
前提
- 配置文件redis.conf
- 防火墙配置(默认防火墙开启,不允许外界访问端口)
vi /etc/sysconfig/iptables #修改防火墙配置文件
-A INPUT -m state --state NEW -m tcp -p tcp --dport 6379 -j ACCEPT
service iptables restart # 重启防火墙
jedis
线程不安全
lettuce
支持同步异步