.NET平台下Redis使用(五)【StackExchange.Redis和Protobuf-net】

本文介绍了一种使用Redis缓存结合Protobuf.NET序列化的高效数据存储方案。通过具体示例演示了不同类型数据的存储与读取过程,并比较了有属性与无属性实体类在序列化过程中的差异。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

没有应该获得的成功,只有不肯放弃的梦想


Models层实体类:

[ProtoContract]
    public class People
    {
        [ProtoMember(1)]
        public int ID { get; set; }

        [ProtoMember(2)]
        public string FirstName { get; set; }

        [ProtoMember(3)]
        public string LastName { get; set; }

        [ProtoMember(4)]
        public DateTime BirthDate { get; set; }

        [ProtoMember(5)]
        public bool Active { get; set; }

        [ProtoMember(6)]
        public AddressModel Address { get; set; }
    }

    [ProtoContract]
    public class AddressModel
    {
        [ProtoMember(1)]
        public int AptNumber { get; set; }

        [ProtoMember(2)]
        public string StreetAdress { get; set; }

        [ProtoMember(3)]
        public string ZipCode { get; set; }

        [ProtoMember(4)]
        public string City { get; set; }

        [ProtoMember(5)]
        public string State { get; set; }

        [ProtoMember(6)]
        public string Country { get; set; }
    }


    [ProtoContract]
    public class PeopleNoAttr
    {
        [ProtoMember(1)]
        public int ID { get; set; }

        [ProtoMember(2)]
        public string FirstName { get; set; }

        [ProtoMember(3)]
        public string LastName { get; set; }

        [ProtoMember(4)]
        public DateTime BirthDate { get; set; }

        [ProtoMember(5)]
        public bool Active { get; set; }

        [ProtoMember(6)]
        public AddressNoAttr Address { get; set; }
    }

    [ProtoContract]
    public class AddressNoAttr
    {
        [ProtoMember(1)]
        public int AptNumber { get; set; }

        [ProtoMember(2)]
        public string StreetAdress { get; set; }

        [ProtoMember(3)]
        public string ZipCode { get; set; }

        [ProtoMember(4)]
        public string City { get; set; }

        [ProtoMember(5)]
        public string State { get; set; }

        [ProtoMember(6)]
        public string Country { get; set; }
    }

Program.cs主程序:

 internal class Program
    {
        private static IDatabase db = RedisConnection.Instance.GetDatabase();

        private static void Main(string[] args)
        {
            SetAndGet();
            TestInteger();
            TestDouble();
            TestBool();
            TestSerializedDate();
            TestProtobufNet();
            TestSerializedArray();
            TestProtobufAndRedis();
            TestProtobufAndRedis_List();
            TestProtobufAndRedis_IEnumerable();
            TestDeleteKey();
            TestSync();
            TestAsync();
            Console.ReadKey();
        }


        public static void SetAndGet()
        {
            const string value = "abcdefg";
            db.StringSet("mykey", value);
            var val = db.StringGet("mykey");
            Console.WriteLine(val);
        }


        public static void TestInteger()
        {
            const int num = 5;
            db.StringSet("StackExchangeRedis_TestInteger", num);
            var val = db.StringGet("StackExchangeRedis_TestInteger");
            Console.WriteLine(val);
        }


        public static void TestDouble()
        {
            const double num = 5.34567;
            db.StringSet("StackExchangeRedis_TestDouble", num);
            var val = db.StringGet("StackExchangeRedis_TestDouble");
            Console.WriteLine(val);
        }


        public static void TestBool()
        {
            const bool b = true;
            db.StringSet("StackExchangeRedis_TestBoolT", b);
            var val = db.StringGet("StackExchangeRedis_TestBoolT");
            Console.WriteLine(val);
        }


        public static void TestSerializedDate()
        {
            DateTime now = DateTime.Now;
            SetCache<DateTime>("StackExchangeRedis_TestSerializedDate", now);
            var val = GetCache<DateTime>("StackExchangeRedis_TestSerializedDate");
            Console.WriteLine(now);
            Console.WriteLine(val);
        }


        public static void TestProtobufNet()
        {
            var ppl = new People()
            {
                ID = 1,
                FirstName = "John",
                LastName = "Doe",
                Address = new AddressModel()
                {
                    AptNumber = 56,
                    StreetAdress = "123 Main Street",
                    City = "Toronto",
                    State = "Ontario",
                    Country = "Canada"
                }
            };
            using (var file = File.Create("person.bin"))
            {
                Serializer.Serialize<People>(file, ppl);
            }

            People newPerson;
            using (var file = File.OpenRead("person.bin"))
            {
                newPerson = Serializer.Deserialize<People>(file);
            }
            Console.WriteLine(newPerson.Address.StreetAdress);
            Console.WriteLine(newPerson.Address.Country+"=="+ppl.Address.Country);
        }


        public static void TestSerializedArray()
        {
            int[] arr = new int[4] {5, 7, 11, 17};
            SetCache<int[]>("StackExchangeRedis_TestSerializedArray", arr);
            Console.WriteLine("Array length = " + arr.Length);
            arr = GetCache<int[]>("StackExchangeRedis_TestSerializedArray");
            Console.WriteLine("Deserialized array length = " + arr.Length);
            Console.WriteLine(arr[2]);
        }


        public static void TestProtobufAndRedis()
        {
            var ppl = new PeopleNoAttr()
            {
                ID = 2,
                FirstName = "Jane",
                LastName = "Smith",
                Address = new AddressNoAttr()
                {
                    AptNumber = 56,
                    StreetAdress = "123 Main Street",
                    City = "Toronto",
                    State = "Ontario",
                    Country = "Canada"
                }
            };
            SetCacheNoAttr<PeopleNoAttr>("StackExchangeRedis_TestProtobufAndRedis_NoAttr", ppl);
            var val2 = GetCache<PeopleNoAttr>("StackExchangeRedis_TestProtobufAndRedis_NoAttr");
            Console.WriteLine(val2.Address.AptNumber);
        }


        public static void TestProtobufAndRedis_List()
        {
            var cachekey = "StackExchangeRedis_TestProtobufAndRedisList";
            List<People> ppl = GenerateList();
            SetCache<List<People>>(cachekey, ppl);
            var val2 = GetCache<List<People>>(cachekey);
            Console.WriteLine(val2[1].Address.StreetAdress);
        }


        public static void TestProtobufAndRedis_IEnumerable()
        {
            var cachekey = "StackExchangeRedis_TestProtobufAndRedisIEnumerable";
            List<People> ppl = GenerateList();
            IEnumerable<People> Ippl = (IEnumerable<People>) ppl;
            SetCache<IEnumerable<People>>(cachekey, ppl);
            var val2 = GetCache<IEnumerable<People>>(cachekey);
            var el = val2.ElementAt(1);
            Console.WriteLine(el.Address.StreetAdress);
        }


        public static void TestDeleteKey()
        {
            DeleteFromCache("StackExchangeRedis_TestProtobufAndRedis");
        }

        // TO DO:
        // =====
        // no attributes
        // twemproxy
        // compare to old redis: C:\workspace\CareerCruising_Core\CC.Data_Tests\RemoteCacheProvider_Test.cs


        //******************************

        public static void TestSync()
        {
            var aSync = db.StringGet("StackExchangeRedis_TestDouble");
            var bSync = db.StringGet("StackExchangeRedis_TestInteger");
        }

        public static void TestAsync()
        {
            var aPending = db.StringGetAsync("StackExchangeRedis_TestDouble");
            var bPending = db.StringGetAsync("StackExchangeRedis_TestInteger");
            var a = db.Wait(aPending);
            var b = db.Wait(bPending);
        }

        //******************************

        /*
        public static void TestExpirationDate()
        {
            var cachekey = "StackExchangeRedis_TestExpirationDate";
            db.StringSet(cachekey, "testing expiration date");
            db.KeyExpire(cachekey, TimeSpan.FromMinutes(30));
            var ttl = db.KeyTimeToLive(cachekey);
            Console.Write(ttl);
        }

        
        public static void TestDeleteKeysByPartOfName()
        {
            DeleteKeysByPartOfName("StackExchangeRedis_");
        }*/

        /*
        public static void TestDeleteAllKeys()
        {
            ClearCache();
        }*/

        #region non-test methods

        
        private static byte[] DataToBytes<T>(T data)
        {
            MemoryStream stream = new MemoryStream();
            //ProtoBuf序列化开始
            Serializer.Serialize(stream, data);
            byte[] bytes = stream.ToArray();
            stream.Close();
            return bytes;
        }

        private static List<People> GenerateList()
        {
            List<People> ppl = new List<People>();
            var person1 = new People()
            {
                ID = 1,
                FirstName = "Jane",
                LastName = "Smith",
                Address =
                    new AddressModel()
                    {
                        AptNumber = 51,
                        StreetAdress = "123 Main Street",
                        City = "Toronto",
                        State = "Ontario",
                        Country = "Canada"
                    }
            };
            var person2 = new People()
            {
                ID = 2,
                FirstName = "John",
                LastName = "Doe",
                Address =
                    new AddressModel()
                    {
                        AptNumber = 52,
                        StreetAdress = "678 Main Street",
                        City = "Toronto1",
                        State = "Ontario1",
                        Country = "Canada1"
                    }
            };
            ppl.Add(person1);
            ppl.Add(person2);
            return ppl;
        }

        // Serialization/deserialization and caching:
        public static bool SetCache<T>(string key, T value)
        {
            if (!string.IsNullOrWhiteSpace(key))
            {
                return db.StringSet(key, DataToBytes<T>(value));
            }
            return false;
        }

        public static bool SetCacheNoAttr<T>(string key, T value)
        {
            if (!string.IsNullOrWhiteSpace(key))
            {

                Console.WriteLine(DataToBytes<T>(value));
                return db.StringSet(key, DataToBytes<T>(value));
            }
            return false;
        }


        public static T GetCache<T>(string key)
        {
            byte[] val = db.StringGet(key);
            MemoryStream stream = new MemoryStream(val, false);
            return Serializer.Deserialize<T>(stream);
        }

        public static bool DeleteFromCache(string key)
        {
            return db.KeyDelete(key);
        }

        public bool DeleteKeysByPartOfName(string pattern)
        {
            bool result = true;
            var keysPattern = string.Format("*{0}*", pattern);
            /*foreach (var key in server.Keys(pattern: keysPattern))
            {
                if (!db.KeyDelete(key))
                    result = false;
            }*/
            return result;
        }

        /*public static void ClearCache()
        {
            server.FlushDatabase();
        }*/

        #endregion
    }

RedisConnection.cs代码:

  public sealed class RedisConnection
    {
        //自动配置与手动配置

        //在很多常见的情况下,StackExchange.Redis 将会自动的配置多个设置选项,包括服务器类型和版本,连接超时和主/从关系配置。可是有时候在Redis服务器这个命令是被禁止的。在这种情况下,提供更多的信息是非常有用的:
        private static ConfigurationOptions configOptions = new ConfigurationOptions
        {
            EndPoints =
            {
                { "127.0.0.1", 6379 }
            },
            CommandMap = CommandMap.Create(new HashSet<string>
            { 
                // 排除几个命令
                //"INFO", "CONFIG", "CLUSTER", "PING", "ECHO", "CLIENT"
            }, available: false),
            AllowAdmin = true,
            Proxy = Proxy.Twemproxy,
            Password = "123456",
        };

        private static readonly ConnectionMultiplexer redis = ConnectionMultiplexer.Connect(configOptions);

        static RedisConnection()
        {

        }

        /// <summary>
        /// 获得Redis的连接实例
        /// </summary>
        public static ConnectionMultiplexer Instance
        {
            get
            {
                return redis;
            }
        }
    }

运行结果:

这里写图片描述


这里写图片描述

NetGain是Stack Overflow(StackExchange)开源的一个高性能的websocket服务端类库。       它只有一个dll:StackExchange.NetGain.dll。     Stack Overflow使用 websocket 向用户推送实时的更新内容,比如顶部栏中的通知、投票数、新导航数、新的答案评论等等。      socket 服务器本身在 web 层上运行,使用原生的 socket。这是一个基于我们的开源库实现的非常小型的应用程序:StackExchange.NetGain。在高峰时刻,我们大约有 50 万个并发的 websocket 连接,这可是一大堆浏览器。一个有趣的事实:其中一些浏览器已经打开超过 18 个月了,得找人去看看那些开发者是不是还活着。下面这张图是本周 websocket 并发量的模式:       为什么用 websocket?在我们这个规模下,它比轮询要有效率得多。通过这种方式,我们可以简单地使用更少资源来推送更多数据,而且对用户而言实时性也更高。安装:Install-Package StackExchange.NetGain代码示例:using System;using System.Net;using StackExchange.NetGain;using StackExchange.NetGain.WebSockets;namespace Example{  public class Program   {    public static void Main (string[] args)     {         IPEndPoint endpoint = new IPEndPoint(IPAddress.Loopback, 6002);        using(var server = new TcpServer())         {             server.ProtocolFactory = WebSocketsSelectorProcessor.Default;             server.ConnectionTimeoutSeconds = 60;             server.Received  = msg =>             {                var conn = (WebSocketConnection)msg.Connection;                string reply = (string)msg.Value   " / "   conn.Host;                 Console.WriteLine("[server] {0}", msg.Value);                 msg.Connection.Send(msg.Context, reply);             };             server.Start("abc", endpoint);             Console.WriteLine("Server running");             Console.ReadKey();         }         Console.WriteLine("Server dead; press any key");         Console.ReadKey();       }     }   } } 标签:WebSocket
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值