Redis 功能入门大全和基于scala实现示例(2)
概要
- Redis server 基于5.0.0的stable版本
- Client基于 Jedis 2.9.0
- Scala 基于 2.11.X
文章链接:
Redis 功能入门大全和基于scala的应用实现(1)
本文内容:
- 使用scala实现redis数据的读写。具体:使用Redis提供Hash表的API来对数据进行读写,提供redis对数据访问的基本思路。redis不同模式下访问方式,后面文章会专门描述。
- 读写性能对比
- scala 编码和环境搭建遇到的问题
如何访问Redis数据?
Redis基础功能是数据读写和数据复制机制,除此之外包含运维工具、性能提升pipeline、事务于Lua脚本等。'Redis服务读写是主体功能。'
使用Hash散列表对数据进行读写,结合jedis 和 scala代码说明不同读写方式方法。
本节描述使用jedis对redis服务进行读写操作,不同模式下Redis读写API基本相同,因此后面不在说明。
Redis服务端只提供读写服务,访问数据则需要客户端。开源组件有多款软件支持redis访问,Jedis
是我们访问redis服务的客户端。
scala是如何现实不同方式的读写哪?下面逐步说明:
- Jedis读操作实现API
在数据操作上,Redis服务端hash类型数据处理API是统一的,即不同的服务类型对数据操作API一致。因此,scala
实现读写操作所有模式都相同,不同模式编码层面的差异在于redis连接创建和释放。
-
读操作
事务和pipeline是redis提供提升读写性能方法,各有特点根据需要使用。
//using 功能是获取连接,执行完成后,关闭连接
trait Using{
type Close = {def close():Unit} //定义新的类型
def using[T <: Close,M](pa: T)(f:T => M): Unit = {
f(pa)
pa.close()
}
}
//按照key读取数据
def readHGet(keys: List[String]) = {
using(connection) {
conn =>
keys.foreach {
el => conn.hgetAll(el)
}
}
}
//读取所有key
def readKeys = {
using(connection) {
conn =>
conn.keys("*")
}
}
//使用pipeline的方式对数据进行读写
def readPipeline(keys: List[String]): Unit = {
using(connection) {
conn =>
val p = conn.pipelined()
keys.foreach {
el => p.hgetAll(el)
}
p.sync()
}
}
- 写入操作
//对数据的写入操作,获取的jedis连接没有关闭连接
trait RedisAction {
//多个hash数据写入
def writeHMset(data: List[(String, util.HashMap[String, String])], conn: Jedis) = {
data.foreach {
case (key, data) =>
conn.hmset(key, data)
}
}
//使用pipeline方式写入数据
def pipelineHash(data: List[(String, util.HashMap[String, String])], conn: Jedis) = {
val p = conn.pipelined()
data.foreach {
case (key, dt) =>
p.hmset(key, dt)
}
p.sync() //without response
}
//without watch/unwatch
//使用事务方式写数据
def transactionHash(data: List[(String, util.HashMap[String, String])], conn: Jedis) = {
val t: Transaction = conn.multi()
data.foreach {
case (key, data) =>
t.hmset(key, data)
}
t.exec()
}
}
jedis操作没有保证数据数据一致,因此以上redis数据读写接口在单一的客户端使用正常。多客户端并发读写会存在数据不一致的情况。这需要 Redis分布式锁解决,见后面章节。
-
测试性能数据
写入的类型是Hash,每个Key包含多个field。测试数据来自主从模式下,受网卡带宽制约。
操作方式 \读写 数据数量 耗时(秒) 速度 其它 逐条插入 写 13983 21 665 pcs pipeline 批量写 19698 0.35 56280pcs 100mbs网卡出现瓶颈,写入慢 事务 批量写 19698 0.36 56280pcs 100mbs网卡出现瓶颈,写入慢 逐条读 读 19698 32.74 615 pcs pipeline 批量读 52386 0.33 158745 pcs 事务 批量读 52386 0.35 158745 pcs -
Jedis连接遇到的问题列表
- [ src]# ./redis-server ../redis_6380.conf slaveof 127.0.0.1 6380
1410:C 05 Nov 2018 15:54:06.132 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1410:C 05 Nov 2018 15:54:06.132 # Redis version=5.0.0, bits=64, commit=00000000, modified=0, pid=1410, just started
1410:C 05 Nov 2018 15:54:06.132 # Configuration loaded
1410:S 05 Nov 2018 15:54:06.133 # Creating Server TCP listening socket 127.0.0.1:6380: bind: Address already in use
rebind port
原因
: redis.conf中存在bind
参数,指定能够访问本机的IP.在创建实例是不是绑定的127.0.01
导致异常,改成绑定IP即可。
- 创建连接池失败 默认密码不能为空,否则 使用该接口创建失败
jedis Caused by: java.net.SocketTimeoutException: Read timed out
原因
:
JedisPool(conf, host, port, timeOut, password, database, clientName, true)
ssh 安全连接设置不能为true, 密码不能为空.
redis.clients.jedis.exceptions.JedisDataException: Please close pipeline or multi block before calling this method.
原因
:Redis事务的执行结果是在exec之后才统一返回,所以Jedis会用一个Response对象最为事务对象transaction的执行放回值。如果我们在transaction执行exec方法之前调用response对象的get方法会出现异常。