美文网首页
Redis 功能入门大全和基于scala实现示例(2)

Redis 功能入门大全和基于scala实现示例(2)

作者: 小赵营 | 来源:发表于2019-03-06 22:14 被阅读10次
redis-scala.PNG

概要

  • 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方法会出现异常。

相关文章

网友评论

      本文标题:Redis 功能入门大全和基于scala实现示例(2)

      本文链接:https://www.haomeiwen.com/subject/yraouqtx.html