博客
关于我
.NET跨平台之旅:基于.NET Core改写EnyimMemcached,实现Linux上访问memcached缓存
阅读量:409 次
发布时间:2019-03-06

本文共 4308 字,大约阅读时间需要 14 分钟。

注:支持 .NET Core 的 memcached 客户端 EnyimMemcachedCore 的 NuGet 包下载地址:

经过一周的努力,我们的“.NET跨平台之旅”取得了一个重要的进展——基于.NET Core改写了开源的memcached .NET客户端EnyimMemcached,实现了Linux上访问memcached缓存,解决了跨平台.NET的缓存问题。

针对我们的应用场景,将实际应用迁移到部署在Linux服务器上的跨平台.NET(.NET Core)有两大障碍:一个障碍是Linux上访问SQL Server数据库,一个障碍是Linux上访问memcached缓存。第一个问题在苦等之后,终于被微软解决了,详见 ;而第二个问题,微软还没开始解决,目前的ASP.NET 5只支持进程内的内存缓存与redis,不支持memcached。但我们不想苦等了,选择了自己动手、丰衣足食,尝试自己解决这个问题。

我们用的memcached缓存客户端是EnyimMemcached,之前对它进行过,对源代码有些了解。用dnx基于.NET Core编译EnyimMemcached的源代码,出现了300多个编译错误,当时有点望而却步,但后来还是下定决心解决这些编译错误。

一类编译错误是对System.Configuration程序集的依赖,EnyimMemcached的配置是放在web.config中的,有不少代码依赖System.Configuration。而ASP.NET 5中根本没有web.config这个东东,corefx中自然也就没有System.Configuration的实现。为了解决这个问题,我们暂时放弃使用配置文件,通过硬编码进行配置,添加的主要代码如下:

IMemcachedClientConfiguration configuration = new MemcachedClientConfiguration(_loggger); configuration.SocketPool.MinPoolSize = 20;configuration.SocketPool.MaxPoolSize = 1000;configuration.SocketPool.ConnectionTimeout = new TimeSpan(0, 0, 3);configuration.SocketPool.ReceiveTimeout = new TimeSpan(0, 0, 3);configuration.SocketPool.DeadTimeout = new TimeSpan(0, 0, 3);

一类编译错误是corefx(.NET Core Framework)中程序集的变化,比如:

  • IPEndPoint跑到了System.Net.Primitives程序集中
  • System.Security.Cryptography.HashAlgorithm跑到了System.Security.Cryptography.Algorithms程序集中
  • System.Threading.Timer成为了一个独立的程序集

一类编译错误是corefx中类库的变化,比如没有了System.Net.Dns.GetHostEntry(),需要改用System.Net.NameResolution程序集中的System.Net.Dns.GetHostAddressesAsync()。

还有一类最头疼的编译错误是corefx中没有二进制序列化(BinaryFormatter)的实现,而对于EnyimMemcached来说这是关键部分,对象的缓存读写全靠二进制序列化与反序列化。针对这个问题,我们改用Json.NET进行bson序列化与反序列化。

序列化实现代码如下:

protected virtual ArraySegment
SerializeObject(object value){ using (var ms = new MemoryStream()) { using (BsonWriter writer = new BsonWriter(ms)) { JsonSerializer serializer = new JsonSerializer(); serializer.Serialize(writer, value); return new ArraySegment
(ms.ToArray(), 0, (int)ms.Length); } }}

反序列化实现代码如下:

T ITranscoder.Deserialize
(CacheItem item){ if (item.Data == null || item.Data.Count == 0) return default(T); using (var ms = new MemoryStream(item.Data.ToArray())) { using (BsonReader reader = new BsonReader(ms)) { if(typeof(T).GetTypeInfo().ImplementedInterfaces.Contains(typeof(IEnumerable))) { reader.ReadRootValueAsArray = true; } JsonSerializer serializer = new JsonSerializer(); return serializer.Deserialize
(reader); } }}

Json.NET的bson反序列有个麻烦的地方,对于集合类型需要专门设置ReadRootValueAsArray的值为true。当时在这个地方折腾了不少时间,没找到好的解决方法,只能用反射实现,就是上面代码中的 typeof(T).GetTypeInfo().ImplementedInterfaces.Contains(typeof(IEnumerable))

在解决了这些编译错误并在开发环境中测试通过之后,我们就将改造后的EnyimMemcached应用到“.NET的跨平台之旅”的示例站点(http://about.cnblogs.com/)上,调用代码如下:

public class TabNavService : ITabNavService{    private ITabNavRepository _tabNavRepository;    private IMemcachedClient _memcachedClient;    public TabNavService(        ITabNavRepository tabNavRepository,        IMemcachedClient memcachedClient)    {        _tabNavRepository = tabNavRepository;        _memcachedClient = memcachedClient;    }    public async Task
> GetAll() { var result = await _memcachedClient.GetAsync
>(cacheKey); if(!result.Success) { var tabNavs = await _tabNavRepository.GetAll(); await _memcachedClient.StoreAsync(StoreMode.Add, cacheKey, tabNavs, new TimeSpan(0, 0, 300)); return tabNavs; } return result.Value; }}

_memcachedClient是通过“依赖注入”注入的,但是在注入时,我们自己给自己挖了一个坑:

services.AddTransient
();

加了memcached缓存功能之后,示例站点在一台测试服务器(只有当前一个请求,没有其它请求)上运行正常,缓存读写正常。

但是一发布到about.cnblogs.com的正式服务器上(有多个请求),请求发出后就一直处于等待状态,服务器无任何响应。在原以为大功告成的时刻却卡在了这个奇怪的问题上,这个滋味你懂的。

折腾了半天,实在找不到原因,找了个替罪羊——可能是corefox中System.Net.Sockets在Linux上的实现对并发请求的处理有问题,准备暂时放弃。

就在这一刻,突然想到,MemcachedClient的构造函数中有初始化socket pool的操作,每创建一个MemcachedClient的实例时都要创建好多到memcached服务器的socket连接。难道是在注入时忘了使用单例,造成每个请求都要创建MemcachedClient的实例,太多的socket连接让kestrel服务器不堪重负。想到这一点,立马跑到电脑前打开代码一看,立马发现自己的坑坑自己不浅。改为单例后,问题立马解决。

services.AddSingleton
();

于是,运行在Linux服务器上的示例站点()用上了memached缓存;于是,写了这篇博文分享自己坑自己的过程;于是,我们的.NET跨平台之旅迈上了一个新台阶。

转载地址:http://mxekz.baihongyu.com/

你可能感兴趣的文章
QBlog V2.5 源码开放下载(ASP.NET 番外系列之开端)
查看>>
秋色园引发CPU百分百命案的事件分析与总结
查看>>
安装jdk并配置环境变量
查看>>
稀疏数组
查看>>
js的严格模式
查看>>
idea的安装和无限期试用
查看>>
Oracle VM VirtualBox安装PVE虚拟机
查看>>
【转】如何用css限制文字长度,使溢出的内容用省略号…显示
查看>>
Android MediaPlayer setDataSource failed
查看>>
[Vue 牛刀小试]:第十二章 - 使用 Vue Router 实现 Vue 中的前端路由控制
查看>>
ASP.NET Core 实战:Linux 小白的 .NET Core 部署之路
查看>>
【nodejs原理&源码杂记(8)】Timer模块与基于二叉堆的定时器
查看>>
大前端的自动化工厂(1)——Yeoman
查看>>
数据仓库建模方法论
查看>>
虚拟机搭建hadoop环境
查看>>
DataStax Bulk Loader教程(四)
查看>>
物联网、5G世界与大数据管理
查看>>
.NET应用框架架构设计实践 - 概述
查看>>
Rust 内置 trait :PartialEq 和 Eq
查看>>
Hibernate(十四)抓取策略
查看>>