三沣开发知识 购物 网址 游戏 小说 歌词 地图 快照 开发 股票 美女 新闻 笑话 | 汉字 软件 日历 阅读 下载 图书馆 编程 China
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题
autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程 CSS/HTML/Xhtml
html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
站长资讯 .NET新手 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA VisualStudio ASP.NET-MVC .NET控件开发 EntityFramework WinRT-Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动 Html-Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP OracleERP DynamicsCRM K2 BPM 信息安全 企业信息 Android开发 iOS开发 WindowsPhone WindowsMobile 其他手机 敏捷开发 项目管理 软件工程 SQLServer Oracle MySQL NoSQL 其它数据库 Windows7 WindowsServer Linux
  IT知识库 -> ASP.NET -> CYQ.Data V5 分布式自动化缓存设计介绍 -> 正文阅读
 

[ASP.NET]CYQ.Data V5 分布式自动化缓存设计介绍

CYQ.Data V5 分布式自动化缓存设计介绍 前方:
其实完成这个功能之前,我就在思考:是先把想法写了来,和大伙讨论讨论后再实现,还是实现后再写文论述自己的思维。
忽然脑后传来一个声音说:你发文后会进入发呆阶段。
所以还是静下心,让我轻轻地把代码撸完再说。
最近这几天,自己在大脑里演练过各种技术难点,解决方案,推敲了各种该解决的问题,觉的差不多了,才决定撸码。
忽然发觉,原来代码是可以写在大脑里的。
要是你看到一个员工坐着2天没写一行代码,说明人家是高手,正在大脑编程。
好,不扯,回正文!
传统ORM的二级缓存为何失效?
有些ORM会提供:如Hibernate。
有些不提供:如EF,不提供是因为知道提供了也没啥鸟用,因为:
1:你不能强迫一个项目全部用单实体编程,多表时,用户更偏向于执行SQL语句。
2:没有分布式缓存做为基础,解决不了多应用程序部署的缓存策略问题。
因此:
1:若控制不了整个项目用户的SQL语句,单机的搞不了。
2:没有分布式缓存做基础,分布式的都搞不了。
这也是为啥EF一直不提供,是因为看到Hibernate虽然提供但并没多大卵用的原因吧!
疑惑数据库已有缓存,为何框架还要造孽?
主要原因:
1:数据库从请求到建立缓存,需要时间(框架缓存可以减缓数据库缓存失效时压力)
2:数据库是有链接数限制的,不可能允许大量并发的直连,需要外界分压。
3:数据库的缓存是单机性。
4:数据库发数据往服务器的时间比本机缓存的长。
自动缓存设计前的一些思考:
1:一开始我思考的缓存策略,是细化到行或列,于是了解数据库自身缓存后发现数据库目前也只是做了以表为单位。
2:MSSQL是有提供SqlDependency的缓存依赖项的,它可以从数据库层面通知你的数据何时失效。
3:但是SqlDependency和SqlCommand依赖太深,无法在所有数据库层面通用。
4:SqlDependency的缓存依赖只能在本地缓存。
5:其它数据库不支持依赖通知。
6:所以方案只能通过全局执行与分析,来处理缓存及失效策略。
7:单机时:全局拦截分析,如何分析出表?
8:应用分布式时:缓存及时失效?
9:用户直接修改数据库时:缓存如何失效?
还有好多好多问题,一直在思考......
缓存什么?
1:缓存单个对象时,是直接存档对象的,Cache返回时会根据本地或是远程选择是否Clone返回。。
2:缓存列表时:只存档字段类型仅包含:(数字、布尔、字符、时间、GUID)的字段,并转成Json字符串存档。
技术细节:
  A:一个对象存档在本机时,存档的是引用(可能出现误写操作);存档在分布式时,存档的不是引用,这会在使用时出现不确定性。
  B:大对象的存档,在缓存来去间需要序列化和反序列化,性能上降低很多。
因此:将列表转成Json存档,拿到时再还原,可以同时解决A和B的问题。
简单的说,如果对象有长字段,或者有二进制数据,是不会被缓存的,所以MSSQL的Timestamp字段就不要用了;
如果要用:AppConfig.DB.HiddenFields="字段名",把它隐藏了也行。
缓存时间?
考虑到通常访问量低时都是在中午和晚上的时间,因此,将缓存的对象的时间随机分布(早上的分布在中午失效,下午的分布在晚上失效)
考虑到分页时的查询,通常都关注前面几页,因此前面几页的数据,时间如上的时间段分布。
分页后面的数据,只默认2分钟的缓存时间。
其它规则有待讨论......
缓存多大?
1:在单机状态,检测到内存的可用比例低于15%时,则不再接受缓存。
2:在分布式缓存状态,暂时有多少扔多少。
缓存如何失效:
1:拦截请求:(包括(MAction)增删改查+(MProc)执行自定义语句+(MDataTable)批量方法)
2:分析语句的关联表(单表的可以拿表名,视图的拿关联结构涉及的表名,存储过程(目前没法),自定义SQL(语句分析出表名),批量(直接拿表名)
3:技术难点:如何从未知的SQL或视图中准确的分析出所有关联的表。
4:缓存失效:执行以下方法应该失效:增删改,执行ExeNonQuery,批量语句。
5:技术难点:
  1:对于视图(关联了多个表,如何根据一个表名,关联到相应涉及的视图语句失效?)
  2:对于分布式的应用,A服务更新,如何B服务器也失效。
如何处理修改频繁的表:
1:一开始想增加配置,让用户设置不参与缓存的表,认真思考后,发现根据缓存失效的时间和次数,可自动分析判断一个表是否修改频繁。
2:表操作相关增删查时,该表被置为失效(相关缓存会被移除),此时设置好时间间隔(6秒),在此时间段对该表相关的不缓存,同时提交的缓存删命令也可以无视。
3:对被分析出为修改频繁的表该如何处理?延长相应的不缓存时间,或是??还需要思考!!!
缓存失效的粒度能不能小?
1:目前的失效,和数据库一样,是以表为单位的。
2:对于插入操作,不会影响某一条数据的读取(所以单条数据的查询,是不应该受到插入操作的影响的)
3:还有其它情形是必然不会影响的?
框架有自动缓存,业务需不需要缓存?
1:数据库有自动缓存,框架的也可以自动缓存。
2:框架有自动缓存,同理业务也可以有缓存。
框架能处理的粒度是有限的,不能细到具体的行或列的缓存级别,因此在业务复杂和并发到一定量后,业务缓存是必要的。
数据库有缓存,业务也可做缓存,为何还思考往框架增加自动缓存?
1:数据库的默认缓存是固定的,需要配置,各种数据库环境不一致。
2:数据库链接池默认是固定的。
3:业务加缓存的事,往往是后期的动作。
现另一个现状是:
1:.NET 群体,存在很多初中级的开发人员,这部分人员的技术成长相对较慢,对缓存或性能调优并不熟。
2:国内有很多的中小网站,默认都抗不起并发,攻击成本很小,几百上千个并发就可以挂你站了。
因此,既然有现实的问题,就可以有对应的解决方案。
V5框架此功能的出现,就是为了从基础层面统一解决这些问题。
只有当.NET行业不在有慢网站的存在,整体提升档次了,有良好的口碑,才会引进更多的BOSS选用 .NET,大伙所期待的.NET春天也就近了。
V5的目前解决的问题:
总体而言,要实现这个功能,核心要解决以下问题:

下面我来将技术一点一点出卖:
5:AOP拦截问题:
首先,要实现这功能,就得全局拦截,扫荡过源码或用过V5的同学,听说过框架本身就有AOP的吧;
其次,得改造这个AOP:框架默认有一个空AOP,当外部有AOP装载的时候,会替换掉这个空AOP。
要实现这个自动缓存:本想在空AOP里实现,放着浪费,但若用户自定义的Aop被装载,又会被替换掉,走不通...
方案想了三四个,思考了三四夜,最后还是在撸码时才确定了现在的模式(这个告诉我们,想的差不多了就该撸码了,要100%想通再撸不太靠谱):
于是,我这样做了:
原有的Aop,改名成InterAop,不过是挂名的,因为它没有继承IAOP接口,而且从原本的单例变更成多例模式。
这里可以贴两行代码,意思是:在Bengin和End方法调用了外部AOP的接口,并根据外部AOP的状态决定后续的执行流程:
完整的源码你们自己SVN了:https://github.com/cyq1162/cyqdata.git

 public AopResult Begin(AopEnum action)
        {
            AopResult ar = AopResult.Continue;
            if (outerAop != null)
            {
                ar = outerAop.Begin(action, Para);
                if (ar == AopResult.Return)
                {
                    return ar;
                }
            }
            if (AppConfig.Cache.IsAutoCache && !IsTxtDataBase) // 只要不是直接返回
            {
                isHasCache = AutoCache.GetCache(action, Para); //找看有没有Cache
            }
            if (isHasCache)  //找到Cache
            {
                if (outerAop == null || ar == AopResult.Default)//不执行End
                {
                    return AopResult.Return;
                }
                return AopResult.Break;//外部Aop说:还需要执行End
            }
            else // 没有Cache,默认返回
            {
                return ar;
            }
        }

        public void End(AopEnum action)
        {
            if (outerAop != null)
            {
                outerAop.End(action, Para);
            }
            if (!isHasCache && !IsTxtDataBase)
            {
                AutoCache.SetCache(action, Para); //找看有没有Cache
            }
        }

代码最后很少,但没想出来之前,2天都搞不定。
1:基础单表、视图操作
A:单表,这个是最简单的,传递进来的就是表名;
B:视图,这个麻烦一点,传递的是视图名;
于是,如何从视图获取相关参与的表名?你现在应该不知道,我来告诉你吧:

DBDataReader sdr=....
DataTable dt = sdr.GetSchemaTable();

这条语句,可以通杀所有的数据库,不用去N种数据库里搜各种元数据藏在哪了!!!
2:多表SQL语句操作:
对于SQL语句,可以用上面的方法,执行一个DataReader再拿,但我弄了一个简单的方法来找关联表:

 internal static List<string> GetTableNamesFromSql(string sql)
        {
            List<string> nameList = new List<string>();

            //获取原始表名
            string[] items = sql.Split(' ');
            if (items.Length == 1) { return nameList; }//单表名
            if (items.Length > 3) // 总是包含空格的select * from xxx
            {
                bool isKeywork = false;
                foreach (string item in items)
                {
                    if (!string.IsNullOrEmpty(item))
                    {
                        string lowerItem = item.ToLower();
                        switch (lowerItem)
                        {
                            case "from":
                            case "update":
                            case "into":
                            case "join":
                            case "table":
                                isKeywork = true;
                                break;
                            default:
                                if (isKeywork)
                                {
                                    if (item[0] == '(' || item.IndexOf('.') > -1) { isKeywork = false; }
                                    else
                                    {
                                        isKeywork = false;
                                        nameList.Add(NotKeyword(item));
                                    }
                                }
                                break;
                        }
                    }
                }
            }
            return nameList;
        }

有可能会找多,找到后,再过滤一下名称是不是数据库里的表就可以了。
3:直接操作数据库
一开始设置的思维,是动态创建一个表,字段大概是这样的:
表名    更新时间
然后如果手工操作数据库,可以手工更改时间,也可以用触发器引发这里的更新。
然后后台线程定时扫这个表,就知道有没有表被更新了。
不过--------V5目前并木有实现它,只是开放了一个接口,可以让你在代码里调用移除缓存。
这个方法就是:

 public abstract partial class CacheManage
    {
        /// <summary>
        /// 获取系统内部缓存Key
        /// </summary>
        public static string GetKey(CacheKeyType ckt, string tableName)
        {
            return GetKey(ckt, tableName, AppConfig.DB.DefaultDataBase, AppConfig.DB.DefaultDalType);
        }
        /// <summary>
        /// 获取系统内部缓存Key
        /// </summary>
        public static string GetKey(CacheKeyType ckt, string tableName, string dbName, DalType dalType)
        {
            switch (ckt)
            {
                case CacheKeyType.Schema:
                    return TableSchema.GetSchemaKey(tableName, dbName, dalType);
                case CacheKeyType.AutoCache:
                    return AutoCache.GetBaseKey(dalType, dbName, tableName);
            }
            return string.Empty;
        }
    }

4:跨服务器操作
这个本来是简单的,后来又想麻烦了,因为要兼顾性能问题,缓存移除可能会频繁的问题。
后来,通过增加了缓存类型,来识别本地缓存或分布式缓存,来区别写代码:

private static void SetBaseKey(string baseKey, string key)
        {
            //baseKey是表的,不包括视图和自定义语句
            if (_MemCache.CacheType == CacheType.LocalCache)
            {
                if (cacheKeys.ContainsKey(baseKey))
                {
                    cacheKeys[baseKey] = cacheKeys[baseKey].Append("," + key);
                }
                else
                {
                    cacheKeys.Add(baseKey, new StringBuilder(key));
                }
            }
            else
            {
                StringBuilder sb = _MemCache.Get<StringBuilder>(baseKey);
                if (sb == null)
                {
                    _MemCache.Set(baseKey, new StringBuilder(key));
                }
                else
                {
                    sb.Append("," + key);
                    _MemCache.Set(baseKey, sb);
                }
            }
        }

6:缓存失效问题  
 这个问题,流程本来很简单的:

但思考到Cache多,而且分布式时,返回会卡,所以删除Cache操作就变成线程处理了。
后来为了避免线程多开,又把类改成了单例(一开始是多实例的)
现在,又把这线程的线程开启,放到LocalCache里和另一个线程作伴了,然后这个单例类又变更成了静态类。
V5框架怎么使用这功能:
升级版本到最新版即可!
总结:
1:没有这个功能之前:框架解决了三大问题:编程架构的统一(自动化)、数据库压力(读写分离)、服务器压力(分布式缓存)。
2:此功能的存在:是针对从基础层面提升行业项目的整体水平。
3:最近大脑有点发春,一个个创新Idea不断的从我大脑冒出来,折腾的我好累:
要思考架构、落实框架代码、要写文分享,写框架Demo、群里解答。
4:开源不赚钱,又投入这么多精力,只能把它当理想了,希望它有天成为.NET项目的标配数据层。
5:我博客是有打赞插件的,哈。
  ASP.NET 最新文章
IIS服务器的请求流程
通过Web Service实现IP地址查询功能
VS 远程调试阿里云上的web站点,Remote Deb
sqlserver的四种分页方式
WebService服务(转)
C#去除字符串中的反斜杠
黑马程序员
ASP.NET之电子商务系统开发
电商开放平台设计
【ASP.NET MVC】jqGrid 增删改查详解
上一篇文章      下一篇文章      查看所有文章
加:2016-07-13 20:03:42  更:2017-05-14 08:08:06 
 
技术频道: 站长资讯 .NET新手区 ASP.NET C# WinForm Silverlight WCF CLR WPF XNA Visual Studio ASP.NET MVC .NET控件开发 Entity Framework WinRT/Metro Java C++ PHP Delphi Python Ruby C语言 Erlang Go Swift Scala R语言 Verilog 其它语言 架构设计 面向对象 设计模式 领域驱动设计 Html/Css JavaScript jQuery HTML5 SharePoint GIS技术 SAP Oracle ERP Dynamics CRM K2 BPM 信息安全 企业信息化其他 Android开发 iOS开发 Windows Phone Windows Mobile 其他手机开发 敏捷开发 项目与团队管理 软件工程其他 SQL Server Oracle MySQL NoSQL 其它数据库 Windows 7 Windows Server Linux
脚本语言: vbs/VBScript DOS/BAT hta htc python perl 游戏相关 VBA 远程脚本 ColdFusion ruby专题 autoit seraphzone PowerShell linux shell Lua Golang Erlang 其它教程
网站开发: CSS/HTML/Xhtml html5 CSS XML/XSLT Dreamweaver教程 经验交流 开发者乐园 Android开发资料
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2018年7日历
2018-7-22 22:28:14
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT知识库