2013-12-31

SSDB 支持 Redis 协议!

Views: 45090 | 67 Comments

终于, SSDB 支持 Redis 协议了! 这表示, 你可以用目前所有成熟的 Redis 客户端来连接 SSDB 服务器, 包括 hiredis, phpredis, redigo 等等.

SSDB 支持 Redis 网络协议, 既是一个技术问题, 也有技术之外的考虑.

首先, Redis 的网络协议对手工输入不够友好. 它采用的是前置长度(块数量)信息的报文格式, 这种数据格式是比较原始的 Linux 配置文件的格式. 相比较, SSDB 采用的是类似 HTTP 报头与报体分隔的方式 - 空白行, 这种方式在输入的时候十分自然, 按两次回车表示请求结束, 并且和响应的输出也能在视觉上分开.

其次, Redis 的网络协议不干净, 也就是不透明. Redis 将报文分为请求和响应两种, 如果仅有这两种, 那也就算了. 要命的是, 它的响应竟然分了5种类型, 导致协议的实现者要做许多的 if-else 判断. 在实现 Redis 协议的过程, 发现这种划分根本没有任何实际意义, 还不如改成统一协议(unified protocol).

所以, SSDB 的网络协议在设计过程中避免了这些繁琐的细节. 这种设计的结果是, 即使用 C 语言来实现一个 SSDB 协议的解析器, 也只有区区不到 100 行代码!

另外, SSDB 在以前不支持 Redis 协议, 也是因为两者实现的原理不同, 有些操作是无法共通的.

最近在 3W 咖啡和大家交流时, 大家纷纷表示希望 SSDB 能支持 Redis 协议, 以便能降低他们试用 SSDB 的门坎. 从这个角度来看, SSDB 确实应该支持 Redis 协议. 所以, SSDB 就支持 Redis 协议了!

当然, 不是所有的命令都支持, 完整的列表见这里: http://www.ideawu.com/ssdb/docs/zh_cn/redis-to-ssdb.html

目前, redis-cli 和 phpredis 已经经过测试, 其它的语言和 Redis 客户端还没有测试, 欢迎大家使用并反馈.

Related posts:

  1. 性能超越 Redis 的 NoSQL 数据库 SSDB
  2. 从 Redis 迁移到 SSDB
  3. 使用 Twemproxy 来做 SSDB 负载均衡
  4. SSDB 采用里程碑式版本发布机制
  5. SSDB 增加了 Compaction 限速功能
Posted by ideawu at 2013-12-31 00:37:38 Tags:

67 Responses to "SSDB 支持 Redis 协议!"

  • 您好,请问一下,ssdb支持redis内嵌的eval操作吗,我在使用ssdb替换redis,导致有些redis使用eval执行的脚本报错,没有eval命令,请问ssdb有类似支持脚本操作的命令吗,谢谢 Reply
    @Sinjon: 追加一下,redis使用eval可以保证原子性操作,ssdb中有类似的操作吗? Reply
  • FLUSHDB 有没有对应的ssdb命令?
    删除整个db Reply
    @yiqing-95: 好的, 我看看. Reply
    @yiqing-95:
    想在yii项目中使用ssdb 这个吴兄能不能实现一个 由你实现最好啦 ^-^
    只要支持这些对应的redis命令就可以了:
    https://github.com/yiisoft/yii2/blob/master/extensions/redis/Cache.php Reply
    @yiqing-95: 不过, 你可能要做一些取舍. 怎么说, 这也是技术能力的一部分, 相信自己, 做吧. Reply
    @yiqing-95: 我看了下, 删除注释后, 代码再弄紧凑一些, 真正的代码就是 70 行. 我相信你完全可以花 10 分钟实现一下.

    你搭建一个 ssdb 来测试只需要 1 分钟, 而我搭一个 yii 的测试环境可能要半个小时. 所以, 这个工作交给你来实现最好. 而且, 我对 yii 的代码协作方式不了解, 不愿意把时间放在这上面. 所以, 还是你来吧. Reply
    @ideawu: 好吧 感谢回复!10分钟是搞不定的 我ssdb的所有命令还不了解
    以前也是听说 最近想试试而以。
    祝此项目越来越好! Reply
  • SSDB轻量、高效,非常棒!感谢作者的贡献!
    SSDB支持Redis协议后,用Perl的Redis模块调用,绝大部分命令正常运行,但用zrangebyscore命令时遇到问题,运行正常,没有报错,返回值总是空数组,而zremrangebyscore命令正常,查看作者Blog中的文章,似乎是命令参数规格问题,SSDB provides zscan, which is similar to zRangeByScore.
    Redis:zRangeByScore(name, score_start, score_end, options);SSDB:zscan(name, key_start, score_start, score_end, limit);依此各种参数方式都试过,Perl Redis模块试过Redis、redis::Client、Mojo::Redis,结果一样。使用的SSDB版本是ssdb-server-1.6.8.6,Window XP。 Reply
    @david: 多谢支持! 你能把重现方式描述一下吗? 比如, 如何 生成一个zset, 如果查询 zrangebyscore, 第一步操作的过程都贴上来. 建议到 github 上提 issue. Reply
  • redis协议里不支持expire么?从redis移植到ssdb的过程中目前就遇到这一个问题 Reply
    @wangdy: 已经加上了, 更新下代码吧. Reply
    @ideawu: nice! Reply
    @wangdy: 还没有支持, 目前支持 setex, ttl. 我会尽快加上 expire 命令. Reply
  • 还有另外一个问题,我用ssdb用的是java的api,我看这个api的实现很简单,就是打开一个socket,写入ssdb协议,然后获得response,这在多线程环境是否会有问题。

    麻烦给予答复,谢谢! Reply
    @内存溢出: 会有问题. 所以, 需要为每个线程创建一个独立的连接. 创建多个连接不会对 ssdb 的性能产生影响. Reply
  • 用jedis客户端直接连接ssdb,连不上,但是通过ssdb提供的java api是可以正常连的。

    jedis连接的代码如下:

    package com.jxx.coo;

    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisShardInfo;

    /**
    * Created by xx on 2014/5/21.
    */
    public class SSDBJedis {
    public static void main(String[] args) {
    String testKey = "hello";
    String value = "redis";
    JedisShardInfo jedisShardInfo = new JedisShardInfo("192.168.193.247",8888);
    Jedis jedis = new Jedis(jedisShardInfo);
    String jedisSetResult = jedis.set(testKey, value);
    System.out.println("jedisSetResult = " + jedisSetResult);
    }
    }

    连不上出现的异常信息如下:

    Exception in thread "main" redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: connect timed out
    at redis.clients.jedis.Connection.connect(Connection.java:134)
    at redis.clients.jedis.BinaryClient.connect(BinaryClient.java:69)
    at redis.clients.jedis.Connection.sendCommand(Connection.java:79)
    at redis.clients.jedis.BinaryClient.set(BinaryClient.java:86)
    at redis.clients.jedis.Client.set(Client.java:21)
    at redis.clients.jedis.Jedis.set(Jedis.java:50)
    at com.jd.coo.SSDBJedis.main(SSDBJedis.java:15)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
    Caused by: java.net.SocketTimeoutException: connect timed out
    at java.net.PlainSocketImpl.socketConnect(Native Method)
    at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
    at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
    at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
    at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366)
    at java.net.Socket.connect(Socket.java:529)
    at redis.clients.jedis.Connection.connect(Connection.java:129)
    … 11 more

    用jedis连接需要做别的特殊配置吗? Reply
    @内存溢出: 是不是配置文件绑定的ip是 127.0.0.1? 我认为你对比时没有使用相同的配置, 确认下你用ssdb java api时连接的ip也是 192.168.193.247! 否则问题就显而易见了. Reply
  • 请问,ssdb的zset怎么根据score倒序排列? Reply
    @soullifepan: zrscan Reply
    @ideawu: 建议把一些help命令里没有列出的命令也加入到help里面吧…才发现原来是支持zrscan的~ Reply
    @ideawu: 赞~!!可以添加到help提示里面么。help的命令里面没有,我还以为不支持呢。 Reply
  • 大牛好,请问client命令未来可否支持binary格式的key和value?感觉上如果同时有一个较低层次的api,ssdb的使用范围可以更广,特别是在value为比较大的blob的时候,就不需要做类似base64的转换。例如我的一个项目只需要直接存blob对象,有直接支持binary的接口的话会更方便高效。 Reply
    @Jason Xu: 你好, 请问你用的是哪个语言的API? SSDB所有的客户端API都是二进制的, 文本只是二进制数据的一种. Reply
    @ideawu: LevelDB是支持任意bytearray作为key和value的,但在目前的通信协议层看似乎是不支持的。如果要从网络读取任意blob,协议中应该先读出串长度,然后读取准确长度的blob。目前“set ‘key’ ‘value’”的方式支持不了任意blob,一般只能先base64或自定义escape的方法才能读写任意blob,但这样也增加了不必要的转格式的overhead,体积也增大不少。如果能新增命令支持简单的bset,bget那是最理想的。 Reply
    @Jason Xu: 请你认真看看SSDB的网络协议: http://www.ideawu.com/ssdb/docs/protocol.html 你如果还是胡言乱语我真的没法再回复你了. 你既然已经用了"似乎", 那就先把这个"似乎"确认了, 再进行后面的逻辑推论. Reply
    @Jason Xu: Hi, SSDB 的客户端 API 支持二进制数据, key和value都可以是二进制数据, 不需要base64等转成文本. 请问你的问题是你的臆断, 还是基于事实的观察? http://www.ideawu.com/ssdb/docs/clients.html Reply
    @ideawu: 恩,我看了一下源码,string是用size取的大小,而不是用的length,那应该就没问题了。 PHP的接口也是这样子的么? 我建议文档里可以加上些二进制流存储的例子,有助于SSDB的推广。 Reply
    @bgsky: 这是因为你不懂编程语言的原因. c/php 的 string 本来就是二进制流, 不是文本.
    @ideawu: hi,其实我也有同样的疑问,我看了一下C++的API是这样定义:virtual Status set(const std::string &key, const std::string &val),我也很想知道怎么能把byte数据存到string里,是一个字节用2个十六进制字符表示,还是直接assign,如果是这样,中间如有个0x00怎么办,望赐教 Reply
    @bgsky: 可以调用 std::string 的 push_back() 方法, 具体你可以找 C++ STL 的 API 文档看看.
    @ideawu: 抱歉啊,的确没有看到这一层。感谢指正。 Reply
  • 我在Nginx中,通过“redis2-nginx-module”模块,获取SSDB数据(缩略图)时,发现总会多出来11个字节,不知道问题出现在哪里? Reply
    @phpcleps: 获取文本数据时有问题吗? 如果连接的是 Redis 有问题吗? 麻烦把你的 nginx 配置贴上来我看看. Reply
    @ideawu: 我试了下, 应该是 redis2-nginx-module-0.10 这个模块有问题, 它没有解析网络数据, 就直接把响应全部 dump 出来了. Reply
    @ideawu: 查看log,提示“[WARN ] ssdb-server.cpp(234): fd: 18, link parse error, delete link” Reply
    @ideawu: 使用HttpRedis模块访问Redis一切正常,访问SSDB时,报502错误,求答案。 Reply
    @phpcleps: Hi, HttpRedis 模块使用的是 redis 0.x 的老版本协议, ssdb 不支持老版本的 redis 协议, 仅支持 redis 1.2+ 协议. Reply
    @ideawu: 好的,已经解决,多谢!
    @ideawu: 哇,回复太快了!多谢! Reply
  • 今天晚上测试了qfront有个bug,无法返回;另外一个建议,能否增加 qdel 的功能?

    最近一直在选型,从原postgres转KVS, 参考了TT-TC /KT-KC(只能千万级别,胜在主主模式) ,Redis(复制机制蛋痛),mongoDB(传闻丢数据),HyperDex(有点自吹自擂)……

    然后发现了SSDB !! very good Reply
    @xianzi25 wu: 多谢支持! 那个 qfront 的 bug, 你升级到最新的代码了吗? 升级后, 如果还有问题, 在 ssdb-cli 执行一下 qfix queue_name. Reply
    @ideawu: 我一直在ssdb-cli的子shell中,用qfix之后再执行qfront 就没有问题了。谢谢 Reply

« [1][2][3] » 1/3

Leave a Comment