nosql

推荐列表 站点导航

当前位置:首页 > 数据库 > nosql >

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

来源:网络整理  作者:网友投稿  发布时间:2020-12-27 12:50
前言:自从CYQ Data框架出了数据库读写分离、分布式缓存MemCache、自动缓存等大功能之后,就进入了频繁的细节打磨优...

自从CYQ.Data框架出了数据库读写分离、分布式缓存MemCache、自动缓存等大功能之后,就进入了频繁的细节打磨优化阶段。

从以下的更新列表就可以看出来了,3个月更新了100条次功能:

305:处理视图名重复时的问题,同时简化MDataTable的代码,取消MDataTable的ReadFromDbDataReader(统一用CreateFrom(sdr)方法读取。(2016-07-16) 306:优化通过Reader获取列结构(该方法不靠谱,需要重新修正元数据的DataType、Size、Scale、DalType等参数)(2016-07-16) 307:为MDataTable和MAction的Set方法增加重载Set(key,value,state),在循环赋值时,产生批量更新时,可以对state赋值2(2016-07-21) 308:增加贴心功能:自定义参数化语句@符号,在各数据库自动被替换成相应的?或:符号兼容多数据库。(2016-07-22) 309:增强MDataTable绑定到Winform和WFP的功能(2016-07-23) 310:修正MProc的ExeMDataTableList的自动缓存问题2016-07-23) 311:DBTool的GetMapTable增加对表名-中划线符号和空格的兼容处理(2016-07-30) 312:CYQ.Data.ProjectTool 升级版本到V2.0(支持英文环境)(2016-07-30) 313:XHtmlAction大力调整升级(细节改动多)(2016-07-31) 314:MDataRow:SetToAll和MDataTable的Bind功能支持XHtmlAction对象(2016-07-31) 315:Dtd文件变成资源文件合在V5里,用到时动态自动解压提升使用体验(为减少文件大小,删注释扣到我差点眼瞎)(2016-07-31) 316:处理MDataTable的GetChange方法引发的Bug和CreateFrom产生的数据初始状态置为1(2016-08-02) 317:XHtmlAction处理对radio标签的处理。(2016-08-02) 318:XHtmlAction增加html的clearflag标签【值为0(清除InnerXml)或1(节点移除)】(用于节点未处理时,处理掉标签)(2016-08-02) 319:XHtmlAction处理html的img,select,input checkbox等节点的处理。(2016-08-02) 320:XHtmlActon重写Load方法(优化加载,自动识别,并处理该<转义的符号)(2016-08-03) 321:AppConfig减少一个Xml相关的配置项(UseFileLoadXml)(2016-08-03) 322:MDataTable修正Select方法(修正为引用)(2016-08-04) 323:DBTool的GetTables方法增加Lock(2016-08-04) 324:修正失败时仍缓存的问题(2016-08-08) 325:增加AppConfig.RunPath属性,获取框架运行的所在文件夹(2016-08-09) 326:处理配置工具ProjectTool升级(2016-08-09) 327:修正MDataCell对二进制数据二次赋值(2016-08-10) 328:调整MDataRow:CreateFrom(外部数据)的行状态初始始为1;LoadFrom(外部数据)的状态和自身值有关(2016-08-10) 329:修正自动缓存(2016-08-10) 330:Oracle修正第1页分页问题【当排序条件为字符串时】(2016-08-11) 331:AppConfig新增加NoCacheTables属性,允许指定某些表不允许缓存(自动缓存开启时)(2016-08-11) 332:XHtmlAction 增加对Xml文档中&符号的处理(2016-08-15) 333:XHtmlAction 对SetForeachEventHandler事件做优化调整(2016-08-15) 334:MProc的SetCustom方法增加对MSSQL用户自定义表类型的支持(2016-08-15) 335:StaticTool:提升了ChangeType方法的转换性能(2016-08-18) 336:MDataTable的ToList<T>方法增加一个判断条件,预防继承OrmBase的远程实体使用Emit(2016-08-18) 337:JsonHelper:优化提升了大数量下的ToString()的性能(2016-08-19) 338:AutoCache:当数据>10万条时不自动缓存(2016-08-19) 339:MDataRow:修正索引取值(在字段名为2个符号同时字段数>10时候产生的问题)(2016-08-23) 340:内部SQL语句优化(2016-08-23) 341:MAction:Select方法(优化查询记录总数的代码,利用自动缓存功能,避免分页时重新计算)(2016-08-24) 342:AppConfig.Cache.IgnoreCacheColumns,可以指定表的某些列的更新操作时不更新缓存(2016-08-24) 343:JsonHelper增加对数组的检测支持(2016-08-25) 344:JsonHelper支持对二进制和Base64的转换(2016-08-26) 345:DBTool.CreateTable或DBTool.DropTable后的缓存处理(2016-08-27)。 346:MAction、MProc取消SetAopOn和SetAopOff方法,统一为:SetAopState方法(简化方法,同时能处理更多的状态,包括关闭自动缓存)(2016-08-27) 347:MDataTable的Select方法增强(对浮点数的比较)(2016-08-27) 348:AutoCache的缓存时间,改成DefaultCacheTime配置的时间,(用户可以自己配置自动缓存时间)(2016-08-27) 349:MProc的ExeMDataTableList方法增加对Oracle的批量语句的支持(2016-08-27) 350:优化Oracle拿表结构的语句(2016-08-27) 351:MDataTable的Merge方法修正(2016-08-27) 352:ThreadBreak的AddGlobalThread增加重载方法(2016-08-27) 353:CacheManage提供PreLoadDBSchemaToCache方法(2016-08-27) 354:JsonSplit处理IsJson判断问题(2016-08-28) 355:MDataTable AcceptChanges(Update方法,处理当配置了AppConfig.DB.DeleteField时引发的问题)(2016-08-30) 356:DBTool.GetColumns方法处理' where'场景时产生的错误(2016-09-02) 357:文本数据库(NoSqlCommand)增对select a as b 别名的支持(2016-09-02) 358:MAction处理多次Fill时未清理旧值的问题(2016-09-02) 359:ORM(OrmBase和SimpleOrmBase)增加SetAopState方法(2016-09-02) 360:AutoCache:处理MAction的Fill方法的时的缓存引用(改成克隆,避免多次Fill指向同一缓存)(2016-09-02) 361:MDataTable增加Description属性。(2016-09-03) 362:DBTool的GetColumns增加对表映射的支持(2016-09-05) 363:修正文本数据库的ResetTable方法(原表没有清空)(2016-09-06) 364:改造并去掉内部的MD5(win2008下加密算法默认引发异常)(2016-09-08) 365:去掉映射表的条件限制(支持更多的外部映射)(2016-09-11) 366:修正读写分离时,insert into ...select语句处理到分库的问题(2016-09-12) 367:SqlCreate处理Oracle日期条件的转换问题。(2016-09-13) 368:SqlCreate增加对GUID类型的检测(2016-09-20) 369:OrmBase、SimpleOrmBase延迟加载初始化(2016-09-20) 370:MAction在Insert时,对Oracle,Mysql等放置(获取最大值)事务(2016-09-20) 371:MAction在Insert时的InsertOp默认选项变更为:ID,原来为(Fill)(2016-09-20) 372:JsonHelper.ToJson增加对List<MDataTable>和List<DataTable>的支持(2016-09-20) 373:DBBase处理Oracle下返回的DataBase名称问题。(2016-09-21) 374:Oracle的加载方式进行小细节优化(2016-09-22) 375:StaticTool处理ChangeType中对于Guid的转换(2016-09-22) 376:SqlCompatible增加对(+ ||)、Left和Right函数的处理(2016-09-24) 377:Oracle的ODP.NET参数添BindByName置为true(2016-09-24) 378:MDataRowCollection AddNew方法,处理Winform(DataGrid绑定时)在空白行和数据行来回点击时不断添加空白数据的问题。(2016-09-29) 379:MAction SetPara增加重载方法(2016-09-29) 380:MAction Update的where条件Error时,RecordsAffected值从原来的0变更为-2;(2016-09-30) 381:MDataTable 修正批量更新的返回值问题(2016-09-30) 382:MAction 内部增加IsIgnoreDeleteField 内部属性(2016-09-30) 383:XHtmlBase 修正对Xml的加载(2016-10-08) 384:SqlValue 调整两个名称(GUID和ISNULL)的命名(2016-10-08) 385:MDataTable 修正Select条件为<=的数字判断问题(2016-10-08) 386:AutoCache(JsonHelper增加Escape属性、MDataTable增加ToJson重载)不处理 的转义替换(2016-10-09) 387:MDataTable ToJson 对于null的数据,默认输出 xx:null 值(2016-10-09) 388:Oracle(DBTool.GetTables) 增加对视图的过滤(2016-10-10) 389:JsonHelper 修正实体嵌套的问题、同时增加对数组的支持(2016-10-14) 390:MDataTable AcceptChange 修正无主键时的的批量更新(2016-10-14) 391:MDataTable 增加 GetIndex 方法(统计满足条件的行所在的索引)(2016-10-16) 392:NoSqlAction 文本数据库修正无法删除最后1条数据的问题(2016-10-16) 393:MDictionary增加索引取值或赋值。(2016-10-17) 394:XHtmlAction、RSS的OnForeach的参数由Dictionary变为MDictionary(2016-10-17) 395:JsonHelper 修正对数组的输出和还原(2016-10-17) 396:JsonHelper 修正Json嵌套问题。(2016-10-18) 397:MDataTable 优化批量更新问题。(2016-10-18) 398:MDataRow和MDataColumn 的ToTable() 调整适应(新增智能提示)(2016-10-19) 399:MySql 处理存储过程Out值。(2016-10-19) 400:MySql 批量方法解决了Bit类型和空表时自增ID被置为1的问题(2016-10-20) 401:JsonHelper、NoSqlAction小优化调整(2016-10-20) 402:MDataTable的AcceptChanges新增加Truncate属性(2016-10-20) 403:JsonHelper的GetJosnValue(json写错顺理)变更名称为GetValue(2016-10-21) 404:NoSqlAction 文本数据库加强删除最后一条数据时的并发处理问题(2016-10-23) 405:DBTool.GetColumns修正对于没有where的group by语句拿表结构的问题(2016-10-24) 406:AppConfig增加SetConn方法(同时增加链接缓存)(2016-10-24) 407:SqlCreateForPager 处理分页的order by aa,bb 没带asc的问题(2016-10-25) 408:NoSqlAction(修正第404修改产生删除后无法批量插入的问题)(2016-10-26) 409:MDataTable的AcceptChanges处理重复批量(同时外部没有产生事务对象的条件下)的问题(2016-10-26) 410:SqlCompatible 对多语句兼容的关键词(不区分大小写)(2016-10-26) 411:MDataTable的Description增加表字段说明输出(2016-10-27) 412:StaticTool优化处理GetDbName的细节(2016-10-28) 413:增加Redis分布式缓存支持(配置AppConfig.Cache.RedisServers)(2016-10-30) 414:为Redis和MemCache增加备份节点支持(配置AppConfig.Cache.RedisServersBak、AppConfig.Cache.MemCacheServersBak)(2016-10-30)

其实更多的时间,是放在ASP.NET Aries 业务开发框架上,上里下外全部重构了一遍。

前几天,决定把Redis集成进来,一鼓作气,解决了。

下面分享一下经历:

最初的想法:

一开始我是拒绝的,不愿动态调用第三方的客户端(关联依赖的dll太多)。

最近打算支持Redis,有点妥协了,动态加载就动态加载了吧:

考虑着引入:StackExchange.Redis或ServiceStack.Redis?

看着这些DLL,太重量级,方法反射起来也费劲!

中间思维停顿了一会。。。

发现轻量级:Bettle.Redis

在寻找Redis的API资料时,无意发现了这个开源的轻量级Bettle.Redis。

看到源码编绎后才46K,感觉就是它了。

不过才几刻间,发现了以下几个问题了:

1:自身虽然46K,但代码引用了另外两个3个dll(依赖太多):

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

2:使用的方法不符合使用习惯,一个命令类型就对应一个类。

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

3:不支持集群的水平扩展(没实现支持一致性Hash)。

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

4:代码是用.NET 4.0 以下版本写的,(CYQ.Data 框架是支持2.0起的,改代码改到我手痛)

所以,以上原因估计是它没被普及的原因,也是最终没有被我选择集成的原因。

但是它开放了源码、对我还是有点启发和参考意义。

Redis API 扫盲:

在决定支持Redis的过程中,花了不少时间扫了Redis的文档:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

更多命令详情可以看:

从这么一堆的命令中,找到基本命令:Get、Set、Exists、Expire、Info,可怜没有Add。

其它的命令,多数都是可以用基本命令实现的,就被无视了。

经过短时间内大量的集中思考,决定自己实现了:

重新定位的思路:

框架之前已经集成了MemCache,而Redis和MemCache又大同小异。

一些共性的东西,可以复用:

1:hash算法。

2:一致性Hash(水平扩展)。

3:SocketPool。

4:ServerPool。

5:序列化(压缩)

剩下的,就是完成Socket和Redis的交互及使用方式。

以下是Redis的协议规范,不过是我实现Redis相关功能后才发现的:

协议规范 redis允许客户端以TCP方式连接,默认6379端口。传输数据都以 结尾。 请求格式 *<number of arguments> $<number of bytes of argument 1> <argument data> 例:*1 $4 INFO 响应格式 1:简单字符串,非二进制安全字符串,一般是状态回复。 +开头,例:+OK 2: 错误信息。          -开头, 例:-ERR unknown command 'mush' 3: 整型数字。 :开头, 例::1 4:大块回复值,最大512M。 $开头+数据长度。 例:$4 mush 5:多条回复。 *开头, 例:*2 $3 foo $3 bar 折腾的经过:

Bettle.Redis里有源码,看看实现就可以了,所以没找协议规范:

通过几个小时的引进和代码调整,测试。

以为大功告成之际,测试到当Set的数据太大时,NetworkStream报异常:此流不支持Seek操作。

怀疑是Redis的Set有大小限制?:用Bettle.Redis自身试了下,发现正常,梦B了。

经代码调试,发现Bettle的Socket实现(Socket.Send)和Socket池的实现(NetworkStream.Write)不一样。

Bettle.Redis是把所有的协议构造好一次性Socket.Send(byte[])。

怀疑NetworkStream的默认缓存池太小引发的?:用memCache,Set了大量的数据,发现NetworkStream并没有抛异常,又梦B了。

怀疑是Redis协议的问题了?:改造代码,把协议分拆,先发送:$长度 ,再发送数据,发现竟然正常了,无语问苍天了!

经过一夜一天的折腾,Cache目录下补了4个类,同时进行了算法优化,清掉一些没用的代码。

支持Redis后,发现cyq.data.dll的大小竟然没变化,结果超出了预期,很好!

最后改造成的源码结构是:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

完整的源码已经提交在:https://github.com/cyq1162/cyqdata

Redis使用方式:        AppConfig.Cache.RedisServers = '127.0.0.1:6379,127.0.0.1:1121';//配置启用, AppConfig.Cache.RedisServersBak = '127.0.0.1:6379';//备用配置。 CacheManage cache = CacheManage.RedisInstance;//操作对象 cache.Add('obj', cache.CacheTable);//添加DataTable MDataTable obj = cache.Get<MDataTable>('obj'); Console.WriteLine(obj.Rows.Count); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add('路过秋天', ''); cache.Add('dic', dic);//添加字段 Dictionary<string, string> dicObj = cache.Get<Dictionary<string, string>>('dic'); Console.WriteLine(dicObj['路过秋天']); cache.Remove('dic');//移除Dic bool hasKey = cache.Contains('dic');//检测是否存在 Console.WriteLine(hasKey); Console.Read();

结果:

对于存储类型的改进:

由于Redis的Get只支持字符串,为了达到支持任意类型,我必须改进算法:

1:存档:目标是对象时=》进行序列化(对于>128K的会进行压缩)

2:数据的第1个字节:存档数据类型。

3:获取数据时:根据第1个字节,进行准确的数据类型还原。

(aaa是通过命令行Set的,而a0是通过代码设置的,所以多了的类型标识)

因此:框架靠Set与Get能支持任意类型的存取档!

对于分布式算法的改进: 1:对于水平增加节点的扩展:

内部已经实现了一致性Hash算法,因此省了不少工作:

简单的描述为:把ip1产生N个hash ,ip2产生N个hash,... 然后排序(最后就看key的hash值离谁最新就粘谁了)

借用一张图表示为:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

2:对于节点故障的转移:

在测试的过程中,我填写了一台异常的主机,发现被分配到异常的主机的key的读写都没反应了:

(我潜意识默认以为会自动转移到相邻的主机中)

默认的算法:

1:没有自动切换相邻的主机【用思考代码疑问:主动切换可能导致雪崩效应,(累积的压力可能把所有的服务器都搞挂)】。

2:有重试连接机制(2分钟试1次)。

改进了算法:增加了一个备份机的配置(AppConfig.Cache.RedisServersBak) 1:根据Hash,每一台主机都会指向一台备份机。 2:主机异常时,由备份机代理服务器15分钟(即每15分检测主机是否正常一次,如果正常,则恢复主机服务)。

3:当主机恢复时,从备份机里恢复数据,并清空备份机的数据(未实现

由于可能同时挂掉N台,所以备份机可能存档多台主机的信息。

于是算法的思路有3个:

1:数据不要了(主机重新缓存即可) 2:主机被请求时(检测是否挂过,如果是,读自身(若没有)=》读备份机(同时发表移除指令)(若有数据)=》返回(同时写入主机) 3:主机被请求时(检测是否挂过,如果是开启线程(读备份机所有Key,检测Hash是否符合自身,如果是,则从备份读取并写入,同时清除备份机的数据) 总结:

至此,CYQ.Data已经支持上Redis了,而且在分布式算法上,借了memCache的风,以及改进的算法,显的更为实用!

当然,细节仍需打磨,代码还可以改的更简洁优美。

在分布式已经泛滥的今天,能正确的判断并用好分布式框架是一种能力的体现。

刚刚群里有人发了这条消息:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

其实前面的问题都可以无视,因为最后解决方案他只是把Redis部署从Windows转移到Linux就好了。

QPS最大时听说7万多(两台Web分来就是3万多,大部分是刷票造成的请求)

Redis在Windows上的表现并不如Linux的好,这个可以理解。

但是如果在架构设计方案上稍为调整,其实也毫无压力了。

最后我发现问题的根源不在于技术,在于人:.NET缺少有足够知识和思维的架构师。

不要遇到点问题就力不从心,在.NET的阵营上坚持吧,少年!

相关热词:

本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供用于网络技术学习参考,学习中请遵循相关法律法规!

本文地址: https://v30.fanwenzhu.com/sql/nosql/9684.shtml

最新文章
 3NF(无依赖):主键字段 3NF(无依赖):主键字段

时间:2021-01-22

进修Redis你必需相识的数据 进修Redis你必需相识的数据

时间:2021-01-22

领略OVER子句 领略OVER子句

时间:2021-01-22

MongoDB的查询操纵 MongoDB的查询操纵

时间:2021-01-22

动态加载就动态加载了吧 动态加载就动态加载了吧

时间:2021-01-22

数据库理相关常识 数据库理相关常识

时间:2021-01-14

存储进程实现可扩展机动 存储进程实现可扩展机动

时间:2021-01-14

通过计算出的hashkey 通过计算出的hashkey

时间:2021-01-14

Copyright © www.juheyunku.com      关于 | 合作 | 声明 | 联系 | 更新 | 地图 | Tags

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

2020-12-27 编辑:网友投稿

自从CYQ.Data框架出了数据库读写分离、分布式缓存MemCache、自动缓存等大功能之后,就进入了频繁的细节打磨优化阶段。

从以下的更新列表就可以看出来了,3个月更新了100条次功能:

305:处理视图名重复时的问题,同时简化MDataTable的代码,取消MDataTable的ReadFromDbDataReader(统一用CreateFrom(sdr)方法读取。(2016-07-16) 306:优化通过Reader获取列结构(该方法不靠谱,需要重新修正元数据的DataType、Size、Scale、DalType等参数)(2016-07-16) 307:为MDataTable和MAction的Set方法增加重载Set(key,value,state),在循环赋值时,产生批量更新时,可以对state赋值2(2016-07-21) 308:增加贴心功能:自定义参数化语句@符号,在各数据库自动被替换成相应的?或:符号兼容多数据库。(2016-07-22) 309:增强MDataTable绑定到Winform和WFP的功能(2016-07-23) 310:修正MProc的ExeMDataTableList的自动缓存问题2016-07-23) 311:DBTool的GetMapTable增加对表名-中划线符号和空格的兼容处理(2016-07-30) 312:CYQ.Data.ProjectTool 升级版本到V2.0(支持英文环境)(2016-07-30) 313:XHtmlAction大力调整升级(细节改动多)(2016-07-31) 314:MDataRow:SetToAll和MDataTable的Bind功能支持XHtmlAction对象(2016-07-31) 315:Dtd文件变成资源文件合在V5里,用到时动态自动解压提升使用体验(为减少文件大小,删注释扣到我差点眼瞎)(2016-07-31) 316:处理MDataTable的GetChange方法引发的Bug和CreateFrom产生的数据初始状态置为1(2016-08-02) 317:XHtmlAction处理对radio标签的处理。(2016-08-02) 318:XHtmlAction增加html的clearflag标签【值为0(清除InnerXml)或1(节点移除)】(用于节点未处理时,处理掉标签)(2016-08-02) 319:XHtmlAction处理html的img,select,input checkbox等节点的处理。(2016-08-02) 320:XHtmlActon重写Load方法(优化加载,自动识别,并处理该<转义的符号)(2016-08-03) 321:AppConfig减少一个Xml相关的配置项(UseFileLoadXml)(2016-08-03) 322:MDataTable修正Select方法(修正为引用)(2016-08-04) 323:DBTool的GetTables方法增加Lock(2016-08-04) 324:修正失败时仍缓存的问题(2016-08-08) 325:增加AppConfig.RunPath属性,获取框架运行的所在文件夹(2016-08-09) 326:处理配置工具ProjectTool升级(2016-08-09) 327:修正MDataCell对二进制数据二次赋值(2016-08-10) 328:调整MDataRow:CreateFrom(外部数据)的行状态初始始为1;LoadFrom(外部数据)的状态和自身值有关(2016-08-10) 329:修正自动缓存(2016-08-10) 330:Oracle修正第1页分页问题【当排序条件为字符串时】(2016-08-11) 331:AppConfig新增加NoCacheTables属性,允许指定某些表不允许缓存(自动缓存开启时)(2016-08-11) 332:XHtmlAction 增加对Xml文档中&符号的处理(2016-08-15) 333:XHtmlAction 对SetForeachEventHandler事件做优化调整(2016-08-15) 334:MProc的SetCustom方法增加对MSSQL用户自定义表类型的支持(2016-08-15) 335:StaticTool:提升了ChangeType方法的转换性能(2016-08-18) 336:MDataTable的ToList<T>方法增加一个判断条件,预防继承OrmBase的远程实体使用Emit(2016-08-18) 337:JsonHelper:优化提升了大数量下的ToString()的性能(2016-08-19) 338:AutoCache:当数据>10万条时不自动缓存(2016-08-19) 339:MDataRow:修正索引取值(在字段名为2个符号同时字段数>10时候产生的问题)(2016-08-23) 340:内部SQL语句优化(2016-08-23) 341:MAction:Select方法(优化查询记录总数的代码,利用自动缓存功能,避免分页时重新计算)(2016-08-24) 342:AppConfig.Cache.IgnoreCacheColumns,可以指定表的某些列的更新操作时不更新缓存(2016-08-24) 343:JsonHelper增加对数组的检测支持(2016-08-25) 344:JsonHelper支持对二进制和Base64的转换(2016-08-26) 345:DBTool.CreateTable或DBTool.DropTable后的缓存处理(2016-08-27)。 346:MAction、MProc取消SetAopOn和SetAopOff方法,统一为:SetAopState方法(简化方法,同时能处理更多的状态,包括关闭自动缓存)(2016-08-27) 347:MDataTable的Select方法增强(对浮点数的比较)(2016-08-27) 348:AutoCache的缓存时间,改成DefaultCacheTime配置的时间,(用户可以自己配置自动缓存时间)(2016-08-27) 349:MProc的ExeMDataTableList方法增加对Oracle的批量语句的支持(2016-08-27) 350:优化Oracle拿表结构的语句(2016-08-27) 351:MDataTable的Merge方法修正(2016-08-27) 352:ThreadBreak的AddGlobalThread增加重载方法(2016-08-27) 353:CacheManage提供PreLoadDBSchemaToCache方法(2016-08-27) 354:JsonSplit处理IsJson判断问题(2016-08-28) 355:MDataTable AcceptChanges(Update方法,处理当配置了AppConfig.DB.DeleteField时引发的问题)(2016-08-30) 356:DBTool.GetColumns方法处理' where'场景时产生的错误(2016-09-02) 357:文本数据库(NoSqlCommand)增对select a as b 别名的支持(2016-09-02) 358:MAction处理多次Fill时未清理旧值的问题(2016-09-02) 359:ORM(OrmBase和SimpleOrmBase)增加SetAopState方法(2016-09-02) 360:AutoCache:处理MAction的Fill方法的时的缓存引用(改成克隆,避免多次Fill指向同一缓存)(2016-09-02) 361:MDataTable增加Description属性。(2016-09-03) 362:DBTool的GetColumns增加对表映射的支持(2016-09-05) 363:修正文本数据库的ResetTable方法(原表没有清空)(2016-09-06) 364:改造并去掉内部的MD5(win2008下加密算法默认引发异常)(2016-09-08) 365:去掉映射表的条件限制(支持更多的外部映射)(2016-09-11) 366:修正读写分离时,insert into ...select语句处理到分库的问题(2016-09-12) 367:SqlCreate处理Oracle日期条件的转换问题。(2016-09-13) 368:SqlCreate增加对GUID类型的检测(2016-09-20) 369:OrmBase、SimpleOrmBase延迟加载初始化(2016-09-20) 370:MAction在Insert时,对Oracle,Mysql等放置(获取最大值)事务(2016-09-20) 371:MAction在Insert时的InsertOp默认选项变更为:ID,原来为(Fill)(2016-09-20) 372:JsonHelper.ToJson增加对List<MDataTable>和List<DataTable>的支持(2016-09-20) 373:DBBase处理Oracle下返回的DataBase名称问题。(2016-09-21) 374:Oracle的加载方式进行小细节优化(2016-09-22) 375:StaticTool处理ChangeType中对于Guid的转换(2016-09-22) 376:SqlCompatible增加对(+ ||)、Left和Right函数的处理(2016-09-24) 377:Oracle的ODP.NET参数添BindByName置为true(2016-09-24) 378:MDataRowCollection AddNew方法,处理Winform(DataGrid绑定时)在空白行和数据行来回点击时不断添加空白数据的问题。(2016-09-29) 379:MAction SetPara增加重载方法(2016-09-29) 380:MAction Update的where条件Error时,RecordsAffected值从原来的0变更为-2;(2016-09-30) 381:MDataTable 修正批量更新的返回值问题(2016-09-30) 382:MAction 内部增加IsIgnoreDeleteField 内部属性(2016-09-30) 383:XHtmlBase 修正对Xml的加载(2016-10-08) 384:SqlValue 调整两个名称(GUID和ISNULL)的命名(2016-10-08) 385:MDataTable 修正Select条件为<=的数字判断问题(2016-10-08) 386:AutoCache(JsonHelper增加Escape属性、MDataTable增加ToJson重载)不处理 的转义替换(2016-10-09) 387:MDataTable ToJson 对于null的数据,默认输出 xx:null 值(2016-10-09) 388:Oracle(DBTool.GetTables) 增加对视图的过滤(2016-10-10) 389:JsonHelper 修正实体嵌套的问题、同时增加对数组的支持(2016-10-14) 390:MDataTable AcceptChange 修正无主键时的的批量更新(2016-10-14) 391:MDataTable 增加 GetIndex 方法(统计满足条件的行所在的索引)(2016-10-16) 392:NoSqlAction 文本数据库修正无法删除最后1条数据的问题(2016-10-16) 393:MDictionary增加索引取值或赋值。(2016-10-17) 394:XHtmlAction、RSS的OnForeach的参数由Dictionary变为MDictionary(2016-10-17) 395:JsonHelper 修正对数组的输出和还原(2016-10-17) 396:JsonHelper 修正Json嵌套问题。(2016-10-18) 397:MDataTable 优化批量更新问题。(2016-10-18) 398:MDataRow和MDataColumn 的ToTable() 调整适应(新增智能提示)(2016-10-19) 399:MySql 处理存储过程Out值。(2016-10-19) 400:MySql 批量方法解决了Bit类型和空表时自增ID被置为1的问题(2016-10-20) 401:JsonHelper、NoSqlAction小优化调整(2016-10-20) 402:MDataTable的AcceptChanges新增加Truncate属性(2016-10-20) 403:JsonHelper的GetJosnValue(json写错顺理)变更名称为GetValue(2016-10-21) 404:NoSqlAction 文本数据库加强删除最后一条数据时的并发处理问题(2016-10-23) 405:DBTool.GetColumns修正对于没有where的group by语句拿表结构的问题(2016-10-24) 406:AppConfig增加SetConn方法(同时增加链接缓存)(2016-10-24) 407:SqlCreateForPager 处理分页的order by aa,bb 没带asc的问题(2016-10-25) 408:NoSqlAction(修正第404修改产生删除后无法批量插入的问题)(2016-10-26) 409:MDataTable的AcceptChanges处理重复批量(同时外部没有产生事务对象的条件下)的问题(2016-10-26) 410:SqlCompatible 对多语句兼容的关键词(不区分大小写)(2016-10-26) 411:MDataTable的Description增加表字段说明输出(2016-10-27) 412:StaticTool优化处理GetDbName的细节(2016-10-28) 413:增加Redis分布式缓存支持(配置AppConfig.Cache.RedisServers)(2016-10-30) 414:为Redis和MemCache增加备份节点支持(配置AppConfig.Cache.RedisServersBak、AppConfig.Cache.MemCacheServersBak)(2016-10-30)

其实更多的时间,是放在ASP.NET Aries 业务开发框架上,上里下外全部重构了一遍。

前几天,决定把Redis集成进来,一鼓作气,解决了。

下面分享一下经历:

最初的想法:

一开始我是拒绝的,不愿动态调用第三方的客户端(关联依赖的dll太多)。

最近打算支持Redis,有点妥协了,动态加载就动态加载了吧:

考虑着引入:StackExchange.Redis或ServiceStack.Redis?

看着这些DLL,太重量级,方法反射起来也费劲!

中间思维停顿了一会。。。

发现轻量级:Bettle.Redis

在寻找Redis的API资料时,无意发现了这个开源的轻量级Bettle.Redis。

看到源码编绎后才46K,感觉就是它了。

不过才几刻间,发现了以下几个问题了:

1:自身虽然46K,但代码引用了另外两个3个dll(依赖太多):

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

2:使用的方法不符合使用习惯,一个命令类型就对应一个类。

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

3:不支持集群的水平扩展(没实现支持一致性Hash)。

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

4:代码是用.NET 4.0 以下版本写的,(CYQ.Data 框架是支持2.0起的,改代码改到我手痛)

所以,以上原因估计是它没被普及的原因,也是最终没有被我选择集成的原因。

但是它开放了源码、对我还是有点启发和参考意义。

Redis API 扫盲:

在决定支持Redis的过程中,花了不少时间扫了Redis的文档:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

更多命令详情可以看:

从这么一堆的命令中,找到基本命令:Get、Set、Exists、Expire、Info,可怜没有Add。

其它的命令,多数都是可以用基本命令实现的,就被无视了。

经过短时间内大量的集中思考,决定自己实现了:

重新定位的思路:

框架之前已经集成了MemCache,而Redis和MemCache又大同小异。

一些共性的东西,可以复用:

1:hash算法。

2:一致性Hash(水平扩展)。

3:SocketPool。

4:ServerPool。

5:序列化(压缩)

剩下的,就是完成Socket和Redis的交互及使用方式。

以下是Redis的协议规范,不过是我实现Redis相关功能后才发现的:

协议规范 redis允许客户端以TCP方式连接,默认6379端口。传输数据都以 结尾。 请求格式 *<number of arguments> $<number of bytes of argument 1> <argument data> 例:*1 $4 INFO 响应格式 1:简单字符串,非二进制安全字符串,一般是状态回复。 +开头,例:+OK 2: 错误信息。          -开头, 例:-ERR unknown command 'mush' 3: 整型数字。 :开头, 例::1 4:大块回复值,最大512M。 $开头+数据长度。 例:$4 mush 5:多条回复。 *开头, 例:*2 $3 foo $3 bar 折腾的经过:

Bettle.Redis里有源码,看看实现就可以了,所以没找协议规范:

通过几个小时的引进和代码调整,测试。

以为大功告成之际,测试到当Set的数据太大时,NetworkStream报异常:此流不支持Seek操作。

怀疑是Redis的Set有大小限制?:用Bettle.Redis自身试了下,发现正常,梦B了。

经代码调试,发现Bettle的Socket实现(Socket.Send)和Socket池的实现(NetworkStream.Write)不一样。

Bettle.Redis是把所有的协议构造好一次性Socket.Send(byte[])。

怀疑NetworkStream的默认缓存池太小引发的?:用memCache,Set了大量的数据,发现NetworkStream并没有抛异常,又梦B了。

怀疑是Redis协议的问题了?:改造代码,把协议分拆,先发送:$长度 ,再发送数据,发现竟然正常了,无语问苍天了!

经过一夜一天的折腾,Cache目录下补了4个类,同时进行了算法优化,清掉一些没用的代码。

支持Redis后,发现cyq.data.dll的大小竟然没变化,结果超出了预期,很好!

最后改造成的源码结构是:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

完整的源码已经提交在:https://github.com/cyq1162/cyqdata

Redis使用方式:        AppConfig.Cache.RedisServers = '127.0.0.1:6379,127.0.0.1:1121';//配置启用, AppConfig.Cache.RedisServersBak = '127.0.0.1:6379';//备用配置。 CacheManage cache = CacheManage.RedisInstance;//操作对象 cache.Add('obj', cache.CacheTable);//添加DataTable MDataTable obj = cache.Get<MDataTable>('obj'); Console.WriteLine(obj.Rows.Count); Dictionary<string, string> dic = new Dictionary<string, string>(); dic.Add('路过秋天', ''); cache.Add('dic', dic);//添加字段 Dictionary<string, string> dicObj = cache.Get<Dictionary<string, string>>('dic'); Console.WriteLine(dicObj['路过秋天']); cache.Remove('dic');//移除Dic bool hasKey = cache.Contains('dic');//检测是否存在 Console.WriteLine(hasKey); Console.Read();

结果:

对于存储类型的改进:

由于Redis的Get只支持字符串,为了达到支持任意类型,我必须改进算法:

1:存档:目标是对象时=》进行序列化(对于>128K的会进行压缩)

2:数据的第1个字节:存档数据类型。

3:获取数据时:根据第1个字节,进行准确的数据类型还原。

(aaa是通过命令行Set的,而a0是通过代码设置的,所以多了的类型标识)

因此:框架靠Set与Get能支持任意类型的存取档!

对于分布式算法的改进: 1:对于水平增加节点的扩展:

内部已经实现了一致性Hash算法,因此省了不少工作:

简单的描述为:把ip1产生N个hash ,ip2产生N个hash,... 然后排序(最后就看key的hash值离谁最新就粘谁了)

借用一张图表示为:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

2:对于节点故障的转移:

在测试的过程中,我填写了一台异常的主机,发现被分配到异常的主机的key的读写都没反应了:

(我潜意识默认以为会自动转移到相邻的主机中)

默认的算法:

1:没有自动切换相邻的主机【用思考代码疑问:主动切换可能导致雪崩效应,(累积的压力可能把所有的服务器都搞挂)】。

2:有重试连接机制(2分钟试1次)。

改进了算法:增加了一个备份机的配置(AppConfig.Cache.RedisServersBak) 1:根据Hash,每一台主机都会指向一台备份机。 2:主机异常时,由备份机代理服务器15分钟(即每15分检测主机是否正常一次,如果正常,则恢复主机服务)。

3:当主机恢复时,从备份机里恢复数据,并清空备份机的数据(未实现

由于可能同时挂掉N台,所以备份机可能存档多台主机的信息。

于是算法的思路有3个:

1:数据不要了(主机重新缓存即可) 2:主机被请求时(检测是否挂过,如果是,读自身(若没有)=》读备份机(同时发表移除指令)(若有数据)=》返回(同时写入主机) 3:主机被请求时(检测是否挂过,如果是开启线程(读备份机所有Key,检测Hash是否符合自身,如果是,则从备份读取并写入,同时清除备份机的数据) 总结:

至此,CYQ.Data已经支持上Redis了,而且在分布式算法上,借了memCache的风,以及改进的算法,显的更为实用!

当然,细节仍需打磨,代码还可以改的更简洁优美。

在分布式已经泛滥的今天,能正确的判断并用好分布式框架是一种能力的体现。

刚刚群里有人发了这条消息:

CYQ.Data V5 分布式缓存Redis应用开发及实现算法理介绍

其实前面的问题都可以无视,因为最后解决方案他只是把Redis部署从Windows转移到Linux就好了。

QPS最大时听说7万多(两台Web分来就是3万多,大部分是刷票造成的请求)

Redis在Windows上的表现并不如Linux的好,这个可以理解。

但是如果在架构设计方案上稍为调整,其实也毫无压力了。

最后我发现问题的根源不在于技术,在于人:.NET缺少有足够知识和思维的架构师。

不要遇到点问题就力不从心,在.NET的阵营上坚持吧,少年!

本站内容来源于网络,如有侵权请与我们联系,我们会及时删除,我们深感抱歉!
注:本站所有信息仅供学习参考!
本文地址为 https://v30.fanwenzhu.com/sql/nosql/9684.shtml

相关文章

风云图片

推荐阅读

返回nosql频道首页