reids介绍和多路复用原理

redis 有windows 版本 和linux 版本 

基础可以参考:https://www.cnblogs.com/ysocean/p/9074353.html

Redis 由四个可执行文件:redis-benchmarkredis-cliredis-serverredis-stat 这四个文件,加上一个redis.conf就构成了整个redis的最终可用包。它们的作用如下:

  • redis-server:Redis服务器的daemon启动程序
  • redis-cli:Redis命令行操作工具。当然,你也可以用telnet根据其纯文本协议来操作
  • redis-benchmark:Redis性能测试工具,测试Redis在你的系统及你的配置下的读写性能
  • redis-stat:Redis状态检测工具,可以检测Redis当前状态参数及延迟状况

如何在linux 环境用docker安装redis 前提是已经安装好docker 

直接运行命令 docker run -p 6379:6379 -d redis 可以默认安装最新版本

docker  ps -a 可以查看当前容器已经有redis

进入redis 容器 docker exec -it  xxx(容器Id) /bin/bash

如何命令 redis-cli 就可以通过命令操作redis了 

 例如 redis-cli --raw flushall  清楚redis 目前的缓存数据

如何设置redis 的登录密码 :

windows下的 找到redis 安装目录下的配置危机 redis.conf 或者redis.windows.conf 找到 requirepass 添加密码 eg: requirepass admin123

然后重启redis ,用cmd命令 redis-server.exe redis.windows.conf 重启后就要使用密码登录了

登录命令 redis-cli.exe -a admin1234

linux 下设置密码:

 第一种:永久方式

     redis设置密码访问

     你的redis在真是环境中不可以谁想访问就可以访问,所以必须要设置密码

     设置密码的流程如下:

     vim  /etc/redis.conf

     找到 #requirepass foobared去掉注释,foobared改为自己的密码,我在这里改为

    requirepass 123456

    然后保存,重启服务

     cd /usr/local/bin

     ./redis-server /etc/redis.conf

     测试连接:./redis-cli 

     输入命令config get requirepass 会提示(error) NOAUTH Authentication required. 这是属于正常现象。

 

 我们输入 auth  123456#你刚才设置的密码

 

 

第二种:临时方式

    1.开启服务端

 

2.链接客户端,使用config get requirepass查看当前redis有没有设置密码

 

 

 

3.上图表示没有设置密码,那么现在来设置密码:

   命令:config set requirepass asdfgh

 

 

 4.再次查看redis密码,则表示密码已存在

 

redis 其实也是一种数据库,它是内存数据库,然后提供了好多种数据类型,来解决我们不同业务的问题,nosql数据库的一种数据库,如果做缓存,优先选择redis;

1.为什么在大数据高并发业务中,会要有redis?

如果是在高并发的情况下 普通的关系型数据库是由IO阻塞的问题的;

BIO和NIO?===》多路复用:也就是说当多个线程过来创建多个异步线程出处理! 正式环境redis最好用linux系统下的;其实多路复用,就是把监听和阻塞

Redis 九大数据结构:

String 
这是一个简单的键值对结构,redis 本身是一个内存数据库,内存数据库越来越多就会导致内存不够用,这个可以设置过期时间 :
使用场景 : 1.session 记录 利用redis 做session共享内存
                    2.自增和自减 --做一些网站的请求数量,或者论坛的点赞数据,评论数据,不可能每次都去执行数据库;可以直接利用redis,操作内存;
 string 底层:在功能中,除了必要的情况下使用,尽量不要使用string类型,除非的不在乎内存溢出 哈,因为如果他是RAW编码,则每次开辟空间都会预留一些空间,则内存也会继续变大;
                      如果使用的是embstr编码 : 他每次最多开辟64个字节的空间,只有44个字节存储我们的数据。
                     如果你在操作的redis的时候,内容长度小于等于44,则会自动选择embstr编码开辟空间 如果你操作redis的时候,内容长度大于44的,使用raw编码,浪费 空间;
                     用 object econding key 可以查当前key的编码 哈
                     还有一个int 编码 ,但是 只是针对于写的数据是数值,才行。。切记只有整型才是int类型
                      
例子:这里的例子是用 ServiceStack.Redis包演示的
复制代码
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
{
                //删除当前数据库中的所有Key  默认删除的是select 0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();
                //统计网站访问数量、当前在线人数、微博数、粉丝数等,全局递增ID等
                // 如果你要学号redis,第一步要灵活使用,要非常非常了解各种api
                // office ,各种数据结构就是代表你是操作execl的还是word,还是ppt ..
                #region 设置key的value
                client.Set<string>("name", "拉拉");
                Console.WriteLine("错误输出");
                Console.WriteLine(client.GetValue("name"));
                Console.WriteLine(JsonConvert.DeserializeObject<string>(client.GetValue("name")));
                Console.WriteLine("正确输出");
                // 代码的底层,也是做了反序列化,只是我们看不到 
                Console.WriteLine(client.Get<string>("name"));
                //Console.WriteLine(JsonConvert.DeserializeObject<string>(client.GetValue("name")));
                #endregion
}
复制代码
复制代码
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {
                //删除当前数据库中的所有Key  默认删除的是select 0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();
                #region  设置key的value并设置过期时间
                client.Set<string>("name", "拉拉", TimeSpan.FromSeconds(1));
                Task.Delay(1 * 1000).Wait(); //等一秒后就没有数据了 
                Console.WriteLine(client.Get<string>("name"));
                #endregion
}
复制代码
复制代码
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {
                //删除当前数据库中的所有Key  默认删除的是select 0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();
                        #region 设置多个key的value
               // 批量的写入redis key

                client.SetAll(new Dictionary<string, string> { { "id", "001" }, { "name", "clay" } });
                //批量读取内存中多个key的结果 如果我们获取的key不存在,程序会返回一个空的字符串
                // 来判断当前用户是否是老用户 老师建议你们如果经济允许搞一个vpn
                var getall = client.GetAll<string>(new string[] { "id", "name", "number" });
                foreach (var item in getall)
                {
                    Console.WriteLine(item);
                }
                #endregion
}
复制代码
复制代码
            using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {
                //删除当前数据库中的所有Key  默认删除的是select 0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();
                               #region 设置key的value并设置过期时间

                client.Set<string>("name", "朝夕教育", DateTime.Now.AddSeconds(1));
                //client.Set<string>("name", "朝夕教育", DateTime.Now.AddMonths(15));
                Console.WriteLine("刚写进去的结果");
                Console.WriteLine(client.Get<string>("name"));
                Task.Delay(1 * 1000).Wait();
                Console.WriteLine("1秒钟之后的结果");
                Console.WriteLine(client.Get<string>("name"));

                client.Set<string>("class", "优秀班级", TimeSpan.FromSeconds(10));
                Task.Delay(1 * 1000).Wait();
                Console.WriteLine(client.Get<string>("class"));
                #endregion

                #region 在原有key的value值之后追加value
                client.AppendToValue("name", "I");
                client.AppendToValue("name", " ");
                client.AppendToValue("name", "LOVE YOU");
                Console.WriteLine(client.Get<string>("name"));
                #endregion

                #region 获取旧值赋上新值
                client.Set("name", "朝夕教育");
                //获取当前key的之前的值,然后把新的结果替换进入
                var value = client.GetAndSetValue("name", "clay");
                Console.WriteLine("原先的值" + value);
                Console.WriteLine("新值" + client.GetValue("name"));
                #endregion

                #region 自增1,返回自增后的值
                //给key为sid的键自增1 ,返回了自增之后的结果
                Console.WriteLine(client.Incr("sid"));
                //Console.WriteLine(client.Incr("sid"));
                //Console.WriteLine(client.Incr("sid"));
                //Console.WriteLine("华丽丽的结束");

                //Console.WriteLine(client.GetValue("sid"));
                //每次通过传递的count累计,count就是累加的值
                //client.IncrBy("sid", 2);
                //Console.WriteLine(client.Get<string>("sid"));
                //client.IncrBy("sid", 100);
                //Console.WriteLine("最后的结果***" + client.GetValue("sid"));
                #endregion

                #region 自减1,返回自减后的值
                //Console.WriteLine(client.Decr("sid"));
                //Console.WriteLine(client.Decr("sid"));
                //Console.WriteLine(client.Decr("sid"));
                //Console.WriteLine("最后的结果"+client.GetValue("sid"));
                ////通过传入的count去做减肥 之前的结果-count
                //client.DecrBy("sid", 2);
                //Console.WriteLine("最终的结果"+client.GetValue("sid"));  
                #endregion
}
复制代码
复制代码
                 #region add 和set 的区别?

                //add 只能做新增,如果已经有了key则返回失败
               // set 如果有key就替换,如果没有就写入
                //当使用add 方法去操作redis的时候,如果key存在的话,则不会再次进行操作 返回false 如果操作成功返回true

                Console.WriteLine(client.Add("name", "clay"));
                //用add的时候帮你去判断如果有则不进行操作,如果没有则写,它只能写新值,不能修改
                Console.WriteLine(client.Add("name", "你很好clay"));
                Console.WriteLine(client.Get<string>("name"));


                //使用set去操作 redis的时候,如果key不存在则写入当前值,并且返回true,通过存在,则对之前的值进行了一个替换 返回操作的结果

                Console.WriteLine(client.Set("name", "clay"));
                Console.WriteLine(client.Set("name", "你很好clay"));
                Console.WriteLine(client.Get<string>("name"));
                #endregion
复制代码
Hash
官方推荐用Hash,
复制代码
public static void Show()
        {
            using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {
                //删除当前数据库中的所有Key  默认删除的是db0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();

                ///大key
                string hashid = "mykey";

                #region  向hashid集合中添加key/value
                client.SetEntryInHash(hashid, "id", "001");
                Console.WriteLine(client.GetValuesFromHash(hashid, "id").FirstOrDefault());
                client.SetEntryInHash(hashid, "name", "clay");
                Console.WriteLine(client.GetValuesFromHash(hashid, "name").FirstOrDefault());
                client.SetEntryInHash(hashid, "socre", "100");
                Console.WriteLine(client.GetValuesFromHash(hashid, "socre").FirstOrDefault());

                #endregion

                #region 批量新增key的值
                Dictionary<string, string> pairs = new Dictionary<string, string>();
                pairs.Add("id", "001");
                pairs.Add("name", "clay");
                client.SetRangeInHash(hashid, pairs);
                //获取当前key的值
                Console.WriteLine(client.GetValueFromHash(hashid, "id"));
                Console.WriteLine(client.GetValueFromHash(hashid, "name"));
                //一次性的获取所有想要获取的小key(属性的)值  如果key不存在,则返回空,不抛出异常
                var list = client.GetValuesFromHash(hashid, "id", "name", "abc");
                Console.WriteLine("*********");
                foreach (var item in list)
                {
                    Console.WriteLine(item);
                }
                #endregion

                #region 如果hashid集合中存在key/value则不添加返回false,如果不存在在添加key/value,返回true
                Console.WriteLine(client.SetEntryInHashIfNotExists(hashid, "name", "你好美"));
                Console.WriteLine(client.SetEntryInHashIfNotExists(hashid, "name", "你好美 哈哈哈"));
                Console.WriteLine(client.GetValuesFromHash(hashid, "name").FirstOrDefault());
                #endregion

                #region 存储对象T t到hash集合中
                //urn: 类名: id的值 、、如果使用对象操作,一定要有id
                client.StoreAsHash<UserInfo>(new UserInfo() { Id = 1, Name = "clay", number = 0 });

                var olduserinfo = client.GetFromHash<UserInfo>(1);


                ////如果id存在的话,则覆盖之前相同的id 他帮助我们序列化或者反射了一些事儿
                //client.StoreAsHash<UserInfo>(new UserInfo() { Id = 2, Name = "clay2" });
                //获取对象T中ID为id的数据。 必须要有属性id,不区分大小写
                //Console.WriteLine(client.GetFromHash<UserInfo>(1).Name);
                //var olduserinfo = client.GetFromHash<UserInfo>(1);
                //olduserinfo.number = 4;
                //client.StoreAsHash<UserInfo>(olduserinfo);
                //Console.WriteLine("最后的结果"+client.GetFromHash<UserInfo>(1).number);
                //client.StoreAsHash<UserInfoTwo>(new UserInfoTwo() { Id = "001", Name = "clay2" });
                //Console.WriteLine(client.GetFromHash<UserInfoTwo>("001").Name);
                //client.StoreAsHash<UserInfoTwo>(new UserInfoTwo() { Id = "002", Name = "clay" });
                //Console.WriteLine(client.GetFromHash<UserInfoTwo>("002").Name);


                //UserInfo lisi = new UserInfo() { Id = 1, Name = "李四", number = 0 };
                //client.StoreAsHash<UserInfo>(lisi);
                //Console.WriteLine(client.GetFromHash<UserInfo>(1).number);
                ////做个自增
                //var oldzhang = client.GetFromHash<UserInfo>(1);
                //oldzhang.number++;
                //client.StoreAsHash<UserInfo>(oldzhang);
                #endregion

                #region 获取所有hashid数据集的key/value数据集合
                //Dictionary<string, string> pairs = new Dictionary<string, string>();
                //pairs.Add("id", "001");
                //pairs.Add("name", "clay");
                //client.SetRangeInHash(hashid, pairs);
                //var dics = client.GetAllEntriesFromHash(hashid);
                //foreach (var item in dics)
                //{
                //    Console.WriteLine(item.Key + ":" + item.Value);
                //} 
                #endregion

                #region 获取hashid数据集中的数据总数
                //Dictionary<string, string> pairs = new Dictionary<string, string>();
                //pairs.Add("id", "001");
                //pairs.Add("name", "clay");
                //client.SetRangeInHash(hashid, pairs);
                //你们自己做到心中有数
                //Console.WriteLine(client.GetHashCount(hashid));
                #endregion

                #region 获取hashid数据集中所有key的集合
                //Dictionary<string, string> pairs = new Dictionary<string, string>();
                //pairs.Add("id", "001");
                //pairs.Add("name", "clay");
                //client.SetRangeInHash(hashid, pairs);
                //var keys = client.GetHashKeys(hashid);
                //foreach (var item in keys)
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 获取hashid数据集中的所有value集合
                //Dictionary<string, string> pairs = new Dictionary<string, string>();
                //pairs.Add("id", "001");
                //pairs.Add("name", "clay");
                //client.SetRangeInHash(hashid, pairs);
                //var values = client.GetHashValues(hashid);
                //foreach (var item in values)
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 删除hashid数据集中的key数据
                //Dictionary<string, string> pairs = new Dictionary<string, string>();
                //pairs.Add("id", "001");
                //pairs.Add("name", "clay");
                //client.SetRangeInHash(hashid, pairs);
                //client.RemoveEntryFromHash(hashid, "id");

                //var values = client.GetHashValues(hashid);
                //foreach (var item in values)
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 判断hashid数据集中是否存在key的数据
                //Dictionary<string, string> pairs = new Dictionary<string, string>();
                //pairs.Add("id", "001");
                //pairs.Add("name", "clay");
                //client.SetRangeInHash(hashid, pairs);
                //Console.WriteLine(client.HashContainsEntry(hashid, "id")); //T  F
                //Console.WriteLine(client.HashContainsEntry(hashid, "number"));// T F
                #endregion

                #region 给hashid数据集key的value加countby,返回相加后的数据
                //Dictionary<string, string> pairs = new Dictionary<string, string>();
                //pairs.Add("id", "001");
                //pairs.Add("name", "clay");
                //pairs.Add("number", "2");
                //client.SetRangeInHash(hashid, pairs);
                //Console.WriteLine(client.IncrementValueInHash(hashid, "number", 2));
                //注意,存的值必须是数字类型,否则抛出异常
                #endregion

            }
        }
复制代码

自定义方式:

复制代码
public class UserInfo
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int number { get; set; }
    }
    public class UserInfoTwo
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }
复制代码
复制代码
public static class HashTool
    {
        public static void StoreAsHash<T>(T model) where T : class, new()
        {
            //获取当前类型的所有字段
            Type type = model.GetType();
            var fields = type.GetProperties();
            // urn: 类名: id的值
            var hashid = type.FullName;
            Dictionary<string, string> pairs = new Dictionary<string, string>();
            var IdValue = string.Empty;
            for (int i = 0; i < fields.Length; i++)
            {
                if (fields[i].Name.ToLower() == "id")
                {
                    //如果你真的把两个相同的id的对象存进去,我可能只改其中一个
                    //不可能,如果有两个相同的id的对象存进去,则后面的会把前面的替换掉
                    IdValue = fields[i].GetValue(model).ToString();
                }
                else
                {
                    // 获取字段的值
                    pairs.Add(fields[i].Name, fields[i].GetValue(model).ToString());
                }

            }
            if (IdValue == string.Empty)
            {
                IdValue = DateTime.Now.ToString("yyyyMMdd");
            }
            RedisClient client = new RedisClient("127.0.0.1");
            client.SetRangeInHash(hashid + IdValue, pairs);
        }

        public static T GetFromHash<T>(object id) where T : class, new()
        {
            //获取当前类型的所有字段
            Type type = typeof(T);
            // urn: 类名: id的值
            var hashid = type.FullName;
            RedisClient client = new RedisClient("127.0.0.1");
            var dics = client.GetAllEntriesFromHash(hashid + id.ToString());
            if (dics.Count == 0)
            {
                return new T();
            }
            else
            {
                var model = Activator.CreateInstance(type);
                var fields = type.GetProperties();
                foreach (var item in fields)
                {
                    if (item.Name.ToLower() == "id")
                    {
                        item.SetValue(model, id);
                    }
                    if (dics.ContainsKey(item.Name))
                    {
                        item.SetValue(model, dics[item.Name]);
                    }
                }
                return (T)model;
            }


        }
    }
复制代码
复制代码
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {
                //删除当前数据库中的所有Key  默认删除的是db0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();
                                 #region 自定义
                HashTool.StoreAsHash<UserInfoTwo>(new UserInfoTwo() { Id = "10001", Name = "clay" });
                var user = HashTool.GetFromHash<UserInfoTwo>("10001");
                Console.WriteLine("结束");
                #endregion
}
复制代码

 hash 底层它的数据结构式ziplist? ziplist:压缩版的list ..(动态的数组,数组的每一个元素的空间是一样的)

如果Filed的个数超过512或者Filed中的任意一个键或者值得长度大于64个字节的时候 使用得是HashTable,其他情况默认ZipList

第一问题:每次插入都有开辟空间,连续的

第二问题:你要查询的时候,你要从头来计算,--查询的速度变慢。。。

hash的数据结果,它的时间复杂度是O(1);

hash快速的查询结果,而且节省空间,一上来就是一个小量的hash。。

问题:如果hash后面链表越来越长的时候,时间复杂度是不是又变高。。。

解决了这个问题?? 扩容:是一开始的时候,redis有两个hash结构在存储数据,第一次只有一个是有长度,一个是没有长度。。

数据迁移问题来了,因为如果不小心操作的时候,刚好触发了瓶颈,要扩容,

解决迁移问题: 第一个:不是一次性迁移完成,是每一次操作只会迁移一部分。 第二个:是一个后台任务,后台任务给你偷偷摸摸的迁移数据: 非常重要:数据一致的问题,自己有机会了解一下

List
一共有三种类型:第一个是队列(先进先出) 第二个是栈:(先进后出) 第三个就是普通的集合。
使用场景: 如果你要做插队,或者做队列,遇到分页场景也可以,都可以使用list 
集合设置过期,只能给整个集合设置,不能单独给某一个元素设置,没有给单独元素设置过期时间的策略。。
复制代码
using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {   //删除当前数据库中的所有Key  默认删除的是db0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();

                string listid = "clay_list";

                #region 顺序添加

                var caocao = new UserInfo() { Id = 1, Name = "李太白" };
                client.AddItemToList(listid, JsonConvert.SerializeObject(caocao));
                var jiaxu = new UserInfo() { Id = 2, Name = "贾诩" };
                client.AddItemToList(listid, JsonConvert.SerializeObject(jiaxu));
                #endregion

                #region 从左侧向list中添加值 追加
                var liubei = new UserInfo() { Id = 1, Name = "刘备" };
                client.PushItemToList(listid, JsonConvert.SerializeObject(liubei));
                #endregion

                #region 从左侧向list中添加值,并设置过期时间
                var caocao = new UserInfo() { Id = 1, Name = "李太白" };
                client.AddItemToList(listid, JsonConvert.SerializeObject(caocao));
                var liubei = new UserInfo() { Id = 2, Name = "刘备" };
                client.PushItemToList(listid, JsonConvert.SerializeObject(liubei));
                //只在内存中存储一秒
                client.ExpireEntryAt(listid, DateTime.Now.AddSeconds(1));
                Console.WriteLine(client.GetListCount(listid));
                Task.Delay(1 * 1000).Wait();
                Console.WriteLine("1秒之后");
                Console.WriteLine(client.GetListCount(listid));
                //雪崩 问题:瞬间大量的数据消失-》大量的数据不要一下的全部消失
                #endregion

                #region 从右侧向list中添加值,并设置过期时间 插队
                var caocao = new UserInfo() { Id = 1, Name = "李太白" };
                client.AddItemToList(listid, JsonConvert.SerializeObject(caocao));
                var jiaxu = new UserInfo() { Id = 2, Name = "贾诩" };

                client.AddItemToList(listid, JsonConvert.SerializeObject(jiaxu));
                var gaunyu = new UserInfo() { Id = 3, Name = "关羽" };
                //向右追加就是插队
                client.PrependItemToList(listid, JsonConvert.SerializeObject(gaunyu));
                Console.WriteLine("ok");
                var caomegndeng = new UserInfo() { Id = 3, Name = "曹孟德" };
                client.PrependItemToList(listid, JsonConvert.SerializeObject(caomegndeng));
                client.ExpireEntryAt(listid, DateTime.Now.AddSeconds(1));
                Console.WriteLine(client.GetListCount(listid));
                Task.Delay(1 * 1000).Wait();
                Console.WriteLine("1秒之后");
                Console.WriteLine(client.GetListCount(listid));
                #endregion

                #region  为key添加多个值
                client.AddRangeToList(listid, new List<string>() { "001", "002", "003", "004" });
                //批量去读取list中的元素
                var lists = client.GetAllItemsFromList(listid);
                foreach (var item in lists)
                {
                    Console.WriteLine(item);
                }
                #endregion

                #region 获取key中下标为star到end的值集合
                client.AddRangeToList(listid, new List<string>() { "001", "002", "003", "004" });
                var lists = client.GetRangeFromList(listid, 0, 1);//从下标0到1的值
                foreach (var item in lists)
                {
                    Console.WriteLine(item);
                }
                #endregion

                #region  list 队列和集合操作 mq  
                var caocao = new UserInfo() { Id = 1, Name = "李太白" };
                client.AddItemToList(listid, JsonConvert.SerializeObject(caocao));
                var jiaxu = new UserInfo() { Id = 2, Name = "贾诩" };
                client.AddItemToList(listid, JsonConvert.SerializeObject(jiaxu));
                var gaunyu = new UserInfo() { Id = 3, Name = "关羽" };
                client.AddItemToList(listid, JsonConvert.SerializeObject(gaunyu));
                //移除尾部 并返回移除的数据 先删再给数据
                Console.WriteLine(client.RemoveEndFromList(listid));
                foreach (var item in client.GetAllItemsFromList(listid))
                {
                    Console.WriteLine(JsonConvert.DeserializeObject<UserInfo>(item).Name);
                }
               // 移除头部并返回移除的数据
                Console.WriteLine(client.RemoveStartFromList(listid));
                foreach (var item in client.GetAllItemsFromList(listid))
                {
                    Console.WriteLine(JsonConvert.DeserializeObject<UserInfo>(item).Name);
                }

               // 从一个list的尾部移除一个数据,添加到另外一个list的头部,并返回移动的值
                Console.WriteLine(client.PopAndPushItemBetweenLists(listid, "newlist"));
                Console.WriteLine("移动之后新队列的元素结果");
                Console.WriteLine(client.GetItemFromList("newlist", 0));
                //根据下标获取想要的集合元素,不做移除操作
                var userstr = client.GetItemFromList(listid, 0);
                Console.WriteLine(JsonConvert.DeserializeObject<UserInfo>(userstr).Name);
                //修改当前下标的结果
                client.SetItemInList(listid, 0, "new value");

                #endregion

            }
复制代码
Set
也是一个集合,只不过是一个去重的集合
比如我需要做投票-- 根据ip地址来投票,每一个ip只投一票。。。如果用list,需要我们自己来判断。如果使用set,则系统自动会去重。
也能取交集和去并集
a:{1,2,3,4,5}
b:{2,3,4,5,6}
a和b的交集= {2,3,4,5}
a和b的并集={1,2,3,4,5,6}
复制代码
public static void Show()
        {
            using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {   //删除当前数据库中的所有Key  默认删除的是db0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();
                #region Set 不重复集合
                string key = "clay_set";
                //投票 
                #region 添加键值 //就是自动去重,再带去重的功能
                var litaibai = new UserInfo() { Id = 1, Name = "李太白" };
                //client.AddItemToList(key, JsonConvert.SerializeObject(litaibai));
                //client.AddItemToList(key, JsonConvert.SerializeObject(litaibai));
                //client.AddItemToSet(key, JsonConvert.SerializeObject(litaibai));
                //client.AddItemToSet(key, JsonConvert.SerializeObject(litaibai));
                //client.AddItemToSet(key, JsonConvert.SerializeObject(litaibai));
                //client.AddItemToSet(key, JsonConvert.SerializeObject(litaibai));
                //Console.WriteLine("***完成了");
                #endregion

                #region 随机获取key集合中的一个值,获取当前setid中的所有值
                //批量的去操作set 集合
                //Console.WriteLine("set 开始了");
                //client.AddRangeToSet(key, new List<string>() { "001", "001", "002", "003", "003", "004" });
                //////当前setid中的值数量
                //Console.WriteLine(client.GetSetCount(key));

                ////随机获取key集合中的一个值 如果有需要取随机数也可以用
                //Console.WriteLine(client.GetRandomItemFromSet(key));
                ////获取当前setid中的所有值
                //var lists = client.GetAllItemsFromSet(key);
                //Console.WriteLine("展示所有的值");
                //foreach (var item in lists)
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 随机删除key集合中的一个值
                //client.AddRangeToSet(key, new List<string>() { "001", "001", "002" });
                //////随机删除key集合中的一个值 返回当前删掉的这个值
                //Console.WriteLine("随机删除的值" + client.PopItemFromSet(key));
                //var lists = client.GetAllItemsFromSet(key);
                //Console.WriteLine("展示删除之后所有的值");
                //foreach (var item in lists)
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 根据小key 删除  一个key 对象多个value
                //client.AddRangeToSet(key, new List<string>() { "001", "001", "002" });
                //client.RemoveItemFromSet(key, "001");
                //var lists = client.GetAllItemsFromSet(key);
                //Console.WriteLine("展示删除之后所有的值");
                //foreach (var item in lists)
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 从fromkey集合中移除值为value的值,并把value添加到tokey集合中
                //client.AddRangeToSet("fromkey", new List<string>() { "003", "001", "002", "004" });
                //client.AddRangeToSet("tokey", new List<string>() { "001", "002" });
                ////从fromkey 中把元素004 剪切到tokey 集合中去
                //client.MoveBetweenSets("fromkey", "tokey", "004");
                //Console.WriteLine("fromkey data ~~~~~~");
                //foreach (var item in client.GetAllItemsFromSet("tokey"))
                //{
                //    Console.WriteLine(item);
                //}

                //Console.WriteLine("tokey data ~~~~~~");
                //foreach (var item in client.GetAllItemsFromSet("tokey"))
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 并集  把两个集合合并起来,然后去重

                //client.AddRangeToSet("keyone", new List<string>() { "001", "002", "003", "004" });
                //client.AddRangeToSet("keytwo", new List<string>() { "001", "002", "005" });
                //var unionlist = client.GetUnionFromSets("keyone", "keytwo");
                //Console.WriteLine("返回并集结果");
                //foreach (var item in unionlist)
                //{
                //    Console.WriteLine(item);
                //}
                ////把 keyone 和keytwo 并集结果存放到newkey 集合中
                //client.StoreUnionFromSets("newkey", "keyone", "keytwo");
                //Console.WriteLine("返回并集结果的新集合数据");
                //foreach (var item in client.GetAllItemsFromSet("newkey"))
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #region 交集 获取两个集合中共同存在的元素
                //client.AddRangeToSet("keyone", new List<string>() { "001", "002", "003", "004" });
                //client.AddRangeToSet("keytwo", new List<string>() { "001", "002", "005" });
                //var Intersectlist = client.GetIntersectFromSets("keyone", "keytwo");
                //Console.WriteLine("交集的结果");
                //foreach (var item in Intersectlist)
                //{
                //    Console.WriteLine(item);
                //}
                ////把 keyone 和keytwo 交集结果存放到newkey 集合中
                //client.StoreIntersectFromSets("newkey", "keyone", "keytwo");
                //Console.WriteLine("返回交集结果的新集合数据");
                //foreach (var item in client.GetAllItemsFromSet("newkey"))
                //{
                //    Console.WriteLine(item);
                //}
                #endregion

                #endregion
            }
        }
复制代码

 

Zset
也是去重的集合,具有set的功能,而且在这些功能里面加了一个值,分数.
使用场景,做服务注册于发现,抽奖。。。限流。。排行榜。
提供了一个非常强大的功能,自动排序
数据结构底层:跳跃表 利用跳跃表,解决排序问题,把内容存在hash里面,把数值存在跳跃表里面,跳跃表里面的里面的数据是有顺序的。。。 跳跃表在存放数据的时候,就把顺序搞好了。。。 -- 它不是解决存放的问题,它是损失一部分写的性能,来提升查询的性能 跳跃表就相当于我们leven树。 一层上面有一层的大纲,后面我讲性能调优模块的时候,会单独讲数据结构和算法,给你提供.net跳跃表的源码 。
复制代码
public static void Show()
        {
            using (RedisClient client = new RedisClient("127.0.0.1", 6379))
            {   //删除当前数据库中的所有Key  默认删除的是db0
                client.FlushDb();
                //删除所有数据库中的key 
                client.FlushAll();
                #region Set 不重复集合
                string key = "clay_set";
                

                #region  sorted set
                //string zsett_key = "clay_zset";
                ////添加一个kye 如果有相同的值得花,则会替换(覆盖)进去,不会因为分数保留
                //client.AddItemToSortedSet(zsett_key, "cc", 33);
                //client.AddItemToSortedSet(zsett_key, "cc", 44);
                //client.AddItemToSortedSet(zsett_key, "cc", 22);
                //Console.WriteLine("ok");
                ////获取当前value的结果
                //Console.WriteLine(client.GetItemIndexInSortedSet(zsett_key, "cc"));
                ////批量操作多个key ,给多个key 赋值1
                //client.AddRangeToSortedSet(zsett_key, new List<string>() { "a", "b" }, 1);

                //foreach (var item in client.GetAllItemsFromSortedSet(zsett_key))
                //{
                //    Console.WriteLine(item);
                //}
                client.AddItemToSortedSet("蜀国", "刘备", 5);
                client.AddItemToSortedSet("蜀国", "关羽", 2);
                client.AddItemToSortedSet("蜀国", "张飞", 3);
                client.AddItemToSortedSet("魏国", "刘备", 5);
                client.AddItemToSortedSet("魏国", "关羽", 2);
                client.AddItemToSortedSet("蜀国", "张飞", 3);
                ////获取 key为蜀国的下标0,到2
                IDictionary<String, double> Dic = client.GetRangeWithScoresFromSortedSet("蜀国", 0, 2);
                foreach (var r in Dic)
                {
                    Console.WriteLine(r.Key + ":" + r.Value);
                }
                //var DicString = client.StoreIntersectFromSortedSets("2", "蜀国", "魏国");
                //var ss = client.GetAllItemsFromSortedSet("2");
                //foreach (var r in DicString)
                //{
                //    Console.WriteLine(r.Key + ":" + r.Value);   
                //}

                //int  int32
             
                #endregion
            }
        }
复制代码

redis 解决了两个问题:1.直接操作硬盘的问题

​ 2.连接阻塞的问题,之前是io阻塞,系统在等待请求的时候,不能干其他的事情,而且每次只能阻塞等待请求,redis通过多路复用,由系统帮你监听多个连接,只要有事情要处理 ,系统会调用你的回调函数,把监听的事情交给了系统,释放了我们自己的代码-- 开启的是高速通道,之前一次只能处理一个请求,现在可以处理多个请求。。。 (不管是单线程的redis还是多线程的redis,最后执行那个指令的线程有且只要一个,)

BitMaps
是一个节省内存的数据结构  0 1 有或者没有,.net 组件中没有封装没有api 调用 哈
Hyperloglog
基准统计数据结构类型  .net 组件中也没有封装 哈
有点使用少量的内存,存放大量的数据。缺点统计的结果有误差。
使用场景:网页浏览统计,访问量等等这些不是特别需要准确的数据,可以利用它。
Streams 
发布订阅--kafak的生产这和消费者的模型都是仿照他做的
发布
复制代码
namespace RedisPublish
{
    class Program
    {


        static void Main(string[] args)
        {
            try
            {
                //创建一个公众号--创建一个主题
                Console.WriteLine("发布服务");
                IRedisClientsManager redisClientManager = new PooledRedisClientManager("127.0.0.1:6379");
                string topicname = "Send_Log";
                RedisPubSubServer pubSubServer = new RedisPubSubServer(redisClientManager, topicname)
                {
                    OnMessage = (channel, msg) =>
                    {
                        Console.WriteLine($"从频道:{channel}上接受到消息:{msg},时间:{DateTime.Now.ToString("yyyyMMdd HH:mm:ss")}");
                        Console.WriteLine("___________________________________________________________________");
                    },
                    OnStart = () =>
                    {
                        Console.WriteLine("发布服务已启动");
                        Console.WriteLine("___________________________________________________________________");
                    },
                    OnStop = () => { Console.WriteLine("发布服务停止"); },
                    OnUnSubscribe = channel => { Console.WriteLine(channel); },
                    OnError = e => { Console.WriteLine(e.Message); },
                    OnFailover = s => { Console.WriteLine(s); },
                };
                //接收消息
                pubSubServer.Start();
                while (1==1)
                {
                    Console.WriteLine("请输入记录的日志");
                    string message = Console.ReadLine();
                    redisClientManager.GetClient().PublishMessage(topicname, message);
                }
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message);
            }
            

        }
    }
}
复制代码

订阅

复制代码
namespace RedisPublish
{
    class Program
    {


        static void Main(string[] args)
        {
            try
            {
                //创建一个公众号--创建一个主题
                Console.WriteLine("发布服务");
                IRedisClientsManager redisClientManager = new PooledRedisClientManager("127.0.0.1:6379");
                string topicname = "Send_Log";
                RedisPubSubServer pubSubServer = new RedisPubSubServer(redisClientManager, topicname)
                {
                    OnMessage = (channel, msg) =>
                    {
                        Console.WriteLine($"从频道:{channel}上接受到消息:{msg},时间:{DateTime.Now.ToString("yyyyMMdd HH:mm:ss")}");
                        Console.WriteLine("___________________________________________________________________");
                    },
                    OnStart = () =>
                    {
                        Console.WriteLine("发布服务已启动");
                        Console.WriteLine("___________________________________________________________________");
                    },
                    OnStop = () => { Console.WriteLine("发布服务停止"); },
                    OnUnSubscribe = channel => { Console.WriteLine(channel); },
                    OnError = e => { Console.WriteLine(e.Message); },
                    OnFailover = s => { Console.WriteLine(s); },
                };
                //接收消息
                pubSubServer.Start();
                while (1==1)
                {
                    Console.WriteLine("请输入记录的日志");
                    string message = Console.ReadLine();
                    redisClientManager.GetClient().PublishMessage(topicname, message);
                }
            }
            catch (Exception ex)
            {

                Console.WriteLine(ex.Message);
            }
            

        }
    }
}
复制代码
复制代码
public class Logger
    {
 

         
        /// <summary>
        /// 写入文本日志
        /// </summary>
        /// <param name="fileName"></param>
        /// <param name="type"></param>
        /// <param name="content"></param>
        public static void WriteTxtLogs(string fileName, string type, string content)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;
            if (!string.IsNullOrEmpty(path))
            {
                path = AppDomain.CurrentDomain.BaseDirectory + fileName;
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                path = path + "\\" + DateTime.Now.ToString("yyyyMMdd");
                if (!Directory.Exists(path))
                {
                    Directory.CreateDirectory(path);
                }
                path = path + "\\" + DateTime.Now.ToString("yyyyMMdd") + ".txt";
                if (!File.Exists(path))
                {
                    FileStream fs = File.Create(path);
                    fs.Close();
                }
                if (File.Exists(path))
                {
                    StreamWriter sw = new StreamWriter(path, true, System.Text.Encoding.Default);
                    sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff") + type + "-->" + content);
                    //  sw.WriteLine("----------------------------------------");
                    sw.Close();
                }
            }
        }
    }
复制代码
Geo
是一个做地理位置,不同key存储的就是一个经度和纬度。可以计算俩个key之间的距离
Bloom Filter (布隆过滤器)
过滤器:
1.存储数据----占用很少的内存存储跟多的数据
2.判断数据在不在存储的里面 ---存在一个查询效率的问题
优点:完美的解决上面这两个问题

 

 布隆过滤器可以判断某个数据一定不存在,但是无法判断一定存在

布隆过滤器优缺点

  优点:优点很明显,二进制组成的数组,占用内存极少,并且插入和查询速度都足够快。

  缺点:随着数据的增加,误判率会增加;还有无法判断数据一定存在;另外还有一个重要缺点,无法删除数据。

实操redis如何安装布隆过滤器

在docker中使用命令 docker run -p 6379:6379 --name redis--redisbloom redislabs/rebloom:latest  这个是把redis和过滤期集成在一起的了

使用它的客户端:docker exec -it redis -redisbloom bash

# redis-cli

代码:

//using (RedisClient client = new RedisClient("192.168.1.211", 6379))
                //{
                //    client.Custom("bf.add", "myfilter", "dddd");
                //    Console.WriteLine(client.Custom("bf.exists", "myfilter", "dddd4444").Text);
                //}

 

其他:

复制代码
1.内存满了,会触发数据淘汰策略,释放资源
2.限流--讲lua,扩展,看一下实现代码  
### 限流lua代码如下
local times = redis.call('incr',KEYS[1])
if times == 1 then
  redis.call('expire',KEYS[1], ARGV[1])
end
 
if times > tonumber(ARGV[2]) then
  return 0
end
return 1
复制代码

Docker 中如何设置redis密码

挂载的时候,把配置文件改一下,挂载进去就行了。或者直接进容器改配置文件---

等下,把docker挂载启动redis配置和脚本放在下面 :

docker run -d -p 6379:6379  -v /myredis/conf/redis.conf:/usr/local/etc/redis/redis.conf   --name redis01 redis:6.0 redis-server /usr/local/etc/redis/redis.conf 

 

posted @   根仔  阅读(77)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示