返回
Featured image of post 12.ET框架接入Redis

12.ET框架接入Redis

ET框架应用

本来我都已经Redis我都快融合完了,然后在群里讨论了下Redis对游戏项目的帮助,结果得到的反馈是完全没必要。

按猫大的说法就是,用户在运行时,数据已经保存在内存中了,再加一层Redis就是多此一举,还浪费性能。

所以新的解决方案就是,给用户添加一个数据持久化组件,组件定时将用户的数据存储到数据库中,关键数据变动直接存储到数据库,以此来替代Redis。【主要还是从减轻数据库读写负担的角度出发】

什么,你说容灾,普通数据直接给用户补偿,关键数据直接保存都丢失了,换Redis能好到哪里去。

Redis融合流程

虽然做了无用功,但是简单的记录还是要记录下的。

在服务端 NuGet 中搜索 StackExchange.Redis,直接点击按钮安装

在服务端Model层添加脚本RedisComponent

using StackExchange.Redis;

namespace ETModel
{
    public class RedisComponent : Component
    {
        public ConnectionMultiplexer m_Redis;
        public IDatabase m_RedisDB;
        public IServer m_RedisServer;
    }
}

在服务端Hotfix层添加脚本RedisComponentSystem

using ETModel;
using StackExchange.Redis;
using System;
using System.Threading;

namespace ETHotfix
{
    [ObjectSystem]
    public class RedisComponentAwakeSystem : AwakeSystem<RedisComponent>
    {
        public override void Awake(RedisComponent self)
        {
            self.Awake();
        }
    }

    [ObjectSystem]
    public class RedisComponentUpdateSystem : UpdateSystem<RedisComponent>
    {
        long time = TimeHelper.ClientNow();
        long nowtime;
        public override void Update(RedisComponent self)
        {
            long nowtime = TimeHelper.ClientNow();
            //超过十秒保存一次数据到数据库
            if (nowtime - time > 10000)
            {
                self.SaveRedis().Coroutine();
                time = nowtime;
            }
        }
    }

    public static class RedisComponentSystem
    {
        public static void Awake(this RedisComponent self)
        {
            self.m_Redis = ConnectionMultiplexer.Connect("localhost");
            self.m_RedisDB = self.m_Redis.GetDatabase(0);
            self.m_RedisServer = self.m_Redis.GetServer("localhost:6379,password=password");
        }

        /// <summary>
        /// 存类,key只能是数据库主键值
        /// </summary>
        /// <param name="key"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool SetClass<T>(this RedisComponent self, T component) where T : ComponentWithId
        {
            return self.SetString(component.GetType().Name, component.Id.ToString(), MongoHelper.ToBson(component));
        }

        /// <summary>
        /// 取类,key只能是数据库主键值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="self"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static async ETTask<T> GetClass<T>(this RedisComponent self, long Id) where T : ComponentWithId
        {
            RedisValue redisValue = self.GetString(typeof(T).Name, Id.ToString());
            if (redisValue.HasValue)
            {
                return MongoHelper.FromBson<T>(redisValue);
            }
            else
            {
                T t = await QueryComponent<T>(Id);
                if (t != null)
                {
                    self.SetClass(t);
                }
                return t;
            }
        }
        public static async ETTask<T> QueryComponent<T>(long Id) where T : ComponentWithId
        {
            DBProxyComponent dBProxyComponent = Game.Scene.GetComponent<DBProxyComponent>();
            return await dBProxyComponent.Query<T>(Id);
        }
        /// <summary>
        /// 存字符串
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static bool SetString(this RedisComponent self, RedisKey key, RedisValue field, RedisValue value)
        {
            try
            {
                self.m_RedisDB.HashSet(key, field, value);
                return true;
            }
            catch (Exception ex)
            {
                Log.Error("Redis数据写入错误" + ex.ToString());
                return false;
            }
        }

        /// <summary>
        /// 取字符串
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static RedisValue GetString(this RedisComponent self, RedisKey key, RedisValue field)
        {
            return self.m_RedisDB.HashGet(key, field);
        }

        /// <summary>
        /// 存储数据到数据库里
        /// </summary>
        /// <param name="self"></param>
        /// <returns></returns>
        public static async ETVoid SaveRedis(this RedisComponent self)
        {
            //获取库中所有的Key
            var keys = self.m_RedisServer.Keys();
            foreach (var key in keys)
            {
                //获取当前key下所有的field
                RedisValue[] fields = self.m_RedisDB.HashValues(key);

                ComponentWithId componentWithId = MongoHelper.FromBson<ComponentWithId>(key);
                await SaveComponent(componentWithId);
            }
        }
        public static async ETTask SaveComponent<T>(T component) where T : ComponentWithId
        {
            DBProxyComponent dBProxyComponent = Game.Scene.GetComponent<DBProxyComponent>();
            await dBProxyComponent.Save(component);
        }


        /// <summary>
        /// 示范
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="self"></param>
        /// <param name="userId"></param>
        /// <param name="component"></param>
        public static void SetHash<T>(this RedisComponent self, long Id, T component) where T : ComponentWithId
        {
            //组件类型名
            string key = component.GetType().Name;
            //组件Id
            string field = Id.ToString();
            //组件
            byte[] value = MongoHelper.ToBson(component);

            //写入组件
            self.m_RedisDB.HashSet(key, field, value);
            //读取某个类型的所有组件
            RedisValue[] components = self.m_RedisDB.HashKeys(key);
            //读取单个组件
            T newComponent = self.m_RedisDB.HashGet(key, field) as T;

            //删除用户数据
            self.m_RedisDB.HashDelete(typeof(T).Name, Id);

            //获取库中所有的组件
            var keys = self.m_RedisServer.Keys();
        }
    }
}

Licensed under CC BY-NC-SA 4.0
0