查看redis有哪些客户端连接

查看redis有哪些客户端连接,第1张

redis允许客户端以TCP方式连接,默认6379端口。传输数据都以\r\n结尾。请求格式<number of arguments>\r\n$<number of bytes of argument 1>\r\n<argument data>\r\n例:1\r\n$4\r\nINFO\r\n响应格式1:简单字符串,非二进制安全字符串,一般是状态回复。 +开头,例:+OK\r\n 2: 错误信息。-开头, 例:-ERR unknown command 'mush'\r\n3: 整型数字。 :开头, 例::1\r\n4:大块回复值,最大512M。 $开头+数据长度。 例:$4\r\mush\r\n5:多条回复。 开头, 例:2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n基础通信定义配置类: public class Configuration { public string Host { get; set; } public int Port { get; set; } /// <summary> /// Socket 是否正在使用 Nagle 算法。 /// </summary> public bool NoDelaySocket { get; set; }public Configuration() { Host = "localhost"; Port = 6379; NoDelaySocket = false; } }实现socket连接:public class RedisBaseClient { //配置文件 private Configuration configuration; //通信socket private Socket socket; //接收字节数组 private byte[] ReceiveBuffer = new byte[100000]; public RedisBaseClient(Configuration config) { configuration = config; } public RedisBaseClient() : this(new Configuration()) { } public void Connect() { if (socket != null && socketConnected) return; socket = new Socket(AddressFamilyInterNetwork, SocketTypeStream, ProtocolTypeTcp) { NoDelay = configurationNoDelaySocket }; socketConnect(configurationHost, configurationPort); if (socketConnected) return; Close(); } /// <summary> /// 关闭client /// </summary> public void Close() { socketDisconnect(false); socketClose(); } }调用:RedisBaseClient redis = new RedisBaseClient(); redisConnect();服务端成功响应:状态命令定义Redis命令枚举:public enum RedisCommand { GET, //获取一个key的值 INFO, //Redis信息。 SET, //添加一个值 EXPIRE, //设置过期时间 MULTI, //标记一个事务块开始 EXEC, //执行所有 MULTI 之后发的命令 }发送命令构建:public string SendCommand(RedisCommand command, params string[] args) { //请求头部格式, <number of arguments>\r\n const string headstr = "{0}\r\n"; //参数信息 $<number of bytes of argument N>\r\n<argument data>\r\n const string bulkstr = "${0}\r\n{1}\r\n"; var sb = new StringBuilder(); sbAppendFormat(headstr, argsLength + 1); var cmd = commandToString(); sbAppendFormat(bulkstr, cmdLength, cmd); foreach (var arg in args) { sbAppendFormat(bulkstr, argLength, arg); } byte[] c = EncodingUTF8GetBytes(sbToString()); try { Connect(); socketSend(c); socketReceive(ReceiveBuffer); Close(); return ReadData(); } catch (SocketException e) { Close(); } return null; } private string ReadData() { var data = EncodingUTF8GetString(ReceiveBuffer); char c = data[0]; //错误消息检查。 if (c == '-') //异常处理。 throw new Exception(data); //状态回复。 if (c == '+') return data; return data; }

1、引用驱动\x0d\代码如下:\x0d\using ServiceStackRedis;\x0d\2、数据库连接\x0d\代码如下:\x0d\RedisClient client;\x0d\//连接服务器 6379是redis的默认端口\x0d\client = new RedisClient("127001", 6379);\x0d\clientPassword = "";//设置密码 没有可以注释\x0d\//10万条数据测试,我发现使用set的效率明显比使用store的效率高,而且在测试过程中我发现store会丢失7-80条左右的数而set却一条都没有丢\x0d\Stopwatch sw = new Stopwatch();\x0d\swStart();\x0d\for (int i = 0; i (GuidNewGuid()ToString(), new GPS\x0d\{\x0d\direction = 287,\x0d\gps_time = "1417622213418",\x0d\lati = 29310586,\x0d\longi = 120125143,\x0d\pla_no = "浙A12345",\x0d\pla_type = 1,\x0d\speed = 235,\x0d\state = 0,\x0d\carstate = 0,\x0d\upload_time = "1417622088418"\x0d\});\x0d\clientStore(\x0d\new GPS\x0d\{\x0d\direction = 287,\x0d\gps_time = "1417622213418",\x0d\lati = 29310586,\x0d\longi = 120125143,\x0d\pla_no = "浙A12345",\x0d\pla_type = 1,\x0d\speed = 235,\x0d\state = 0,\x0d\carstate = 0,\x0d\upload_time = "1417622088418"\x0d\});\x0d\}\x0d\swStop();\x0d\ConsoleWriteLine(swElapsedMilliseconds);\x0d\decimal price = clientGet("price");//获取数据

Redis Cluster设计要点:

架构:无中心

Redis Cluster采用无中心结构,每个节点都保存数据和整个集群的状态

每个节点都和其他所有节点连接,这些连接保持活跃

使用gossip协议传播信息以及发现新节点

node不作为client请求的代理,client根据node返回的错误信息重定向请求

数据分布:预分桶

预分好16384个桶,根据 CRC16(key) mod 16384的值,决定将一个key放到哪个桶中

每个Redis物理结点负责一部分桶的管理,当发生Redis节点的增减时,调整桶的分布即可

例如,假设Redis Cluster三个节点A/B/C,则

Node A 包含桶的编号可以为: 0 到 5500

Node B 包含桶的编号可以为: 5500 到 11000

Node C包含桶的编号可以为: 11001 到 16384

当发生Redis节点的增减时,调整桶的分布即可。

预分桶的方案介于“硬Hash”和“一致性Hash”之间,牺牲了一定的灵活性,但相比“一致性Hash“,数据的管理成本大大降低

可用性:Master-Slave

为了保证服务的可用性,Redis Cluster采取的方案是的Master-Slave

每个Redis Node可以有一个或者多个Slave。当Master挂掉时,选举一个Slave形成新的Master

一个Redis Node包含一定量的桶,当这些桶对应的Master和Slave都挂掉时,这部分桶对应的数据不可用

Redis Cluster使用异步复制

一个完整的写 *** 作步骤:

1client写数据到master

2master告诉client "ok"

3master传播更新到slave

存在数据丢失的风险:

1 上述写步骤1)和2)成功后,master crash,而此时数据还没有传播到slave

2 由于分区导致同时存在两个master,client向旧的master写入了数据。

当然,由于Redis Cluster存在超时及故障恢复机制,第2个风险基本上不可能发生

数据迁移

Redis Cluster支持在线增/减节点。

基于桶的数据分布方式大大降低了迁移成本,只需将数据桶从一个Redis Node迁移到另一个Redis Node即可完成迁移。

当桶从一个Node A向另一个Node B迁移时,Node A和Node B都会有这个桶,Node A上桶的状态设置为MIGRATING,Node B上桶的状态被设置为IMPORTING

当客户端请求时:

所有在Node A上的请求都将由A来处理,所有不在A上的key都由Node B来处理。同时,Node A上将不会创建新的key

多key *** 作

当系统从单节点向多节点扩展时,多key的 *** 作总是一个非常难解决的问题,Redis Cluster方案如下:

1 不支持多key *** 作

2 如果一定要使用多key *** 作,请确保所有的key都在一个node上,具体方法是使用“hash tag”方案

hash tag方案是一种数据分布的例外情况

使用Redis的脚本功能实现Redis中数据简单查询,有需要的朋友可以参考下。

在Redis的设计中,key是一切,对于Redis是可见的,而value对于Redis来说就是一个字节数组,Redis并不知道你的value中存储的是什么,所以要想实现比如

‘select from users where userlocation="shanghai"’

这样的查询,在Redis是没办法通过value进行比较得出结果的。但是可以通过不同的数据结构类型来做到这一点。比如如下的数据定义

users:1 {name:Jack,age:28,location:shanghai} users:2 {name:Frank,age:30,location:beijing} users:location:shanghai [1]

其中users:1 users:2 分别定义了两个用户信息,通过Redis中的hash数据结构,而users:location:shanghai 记录了所有上海的用户id,通过集合数据结构实现。这样通过两次简单的Redis命令调用就可以实现我们上面的查询。

Jedis jedis = jedisPoolgetResource(); Set<String> shanghaiIDs = jedissmembers("users:location:shanghai"); //遍历该set // //通过hgetall获取对应的user信息 jedishgetAll("users:" + shanghaiIDs[0]);

通过诸如以上的设计,可以实现简单的条件查询。但是这样的问题也很多,首先需要多维护一个ID索引的集合,其次对于一些复杂查询无能为力(当然也不能期望Redis实现像关系数据库那样的查询,Redis不是干这的)。

但是Redis26集成了Lua脚本,可以通过eval命令,直接在RedisServer环境中执行Lua脚本,并且可以在Lua脚本中调用Redis命令。其实,就是说可以让你用Lua这种脚本语言,对Redis中存储的key value进行 *** 作,这个意义就大了,甚至可以将你们系统所需的各种业务写成一个个lua脚本,提前加载进入Redis,然后对于请求的响应,只需要调用一个个lua脚本就行。当然这样说有点夸张,但是意思就是这样的。

比如,现在我们要实现一个‘所有age大于28岁的user’这样一个查询,那么通过以下的Lua脚本就可以实现

public static final String SCRIPT = "local resultKeys={};" + "for k,v in ipairs(KEYS) do " + " local tmp = rediscall('hget', v, 'age');" + " if tmp > ARGV[1] then " + " tableinsert(resultKeys,v);" + " end;" + "end;" + "return resultKeys;";

执行脚本代码 Jedis jedis = jedisPoolgetResource(); jedisauth(auth); List<String> keys = ArraysasList(allUserKeys); List<String> args = new ArrayList<>(); argsadd("28"); List<String> resultKeys = (List<String>)jedisevalsha(funcKey, keys, args); return resultKeys;

注意,以上的代码中使用的是evalsha命令,该命令参数的不是直接Lua脚本字符串,而是提前已经加载到Redis中的函数的一个SHA索引,通过以下的代码将系统中所有需要执行的函数提前加载到Redis中,我们的系统维护一个函数哈希表,后续需要实现什么功能,就从函数表中获取对应功能的SHA索引,通过evalsha调用就行。

String shaFuncKey = jedisscriptLoad(SCRIPT);//加载脚本,获取sha索引 funcTableput(funcName_age, shaFuncKey);//添加到函数表中

通过以上的方法,便可以使较为复杂的查询放到Redis中去执行,提高效率。

我是通过这个方法来判断是否连通的private static bool Ping(RedisClient client){try{if (clientPing()){return true;}else {return false;}}catch{return false;}}如果连接不同 Ping() 会有一点延迟,好像是内部已经实现了重连的判断,如果连接通是没有延迟直接过的。

Redis是内存数据库,数据存储在内存中,所以Redis相对于传统磁盘数据库来说具有更快的读写速度,查询响应时间不会受到数据量的影响。但如果数据量非常大,内存不足的情况下,Redis可能会因为需要使用繁重的数据替换和其他 *** 作降低读写效率,影响查询和整个系统的性能。

以上就是关于查看redis有哪些客户端连接全部的内容,包括:查看redis有哪些客户端连接、c#怎么连接Redis,Get和Set数据、如何查看redis cluster等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/9796990.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-02
下一篇 2023-05-02

发表评论

登录后才能评论

评论列表(0条)

保存