新普金娱乐网址


“阿里人”分享大型网站架构系列:缓存在分布式系统中的应用

《你好,旧时光》回不去的常青

地理《小王子》你曾是个少年:永远年轻,永远热泪盈眶

  • 一月 15, 2019
  • 地理
  • 没有评论

读到这里,我们应该都很有感触,关于,友情、爱情、亲情,即便宇宙没有,尽管情绪消亡,我曾热情洋溢过。在此地想推荐好堂妹的《风又吹走了》给大家听,即使有些小伤感,但大家仍旧眷恋这来了又走的风。

5.1. 安装Redis

开辟微软开源技术公司维护的Redis
Github链接,找到Releases目录,下载最新版本的msi安装即可。

地理 1

下载后,一贯下一步安装即可。


4. Redis是何许玩意儿

Redis
是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和信息中间件。它帮助多连串型的数据结构,如字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序聚集(sorted
sets)与限定查询、bitmaps、hyperloglogs和地理空间(geospatial)索引半径查询。

官方的表达就是这般隐晦,对于初识Redis,我们可以简简单单把它知道为依据内存的进度特别快性能特别棒的Key-Value数据库。

有好几亟需表明,Redis官方仅补助Linux系统不援助Windows系统。
可是呢,微软大法好啊,微软开源技术团队(Microsoft Open Tech
group)开发和掩护了一个Win64
的本子,我们能够在https://github.com/MSOpenTech/redis内外载Win64版本来玩一玩。

想精通更多,请参见华语官方文档英文官方文档

狐狸渴望与小王子互相驯化,他说:我不吃面包,玉米对自身来说,一点用也没有。我对麦田无动于衷。而这,真使人扫兴。不过,你有金黑色的头发。那么,一旦您驯服了自家,这就会要命可观。稻谷,是金红色的,它就会使自己想起你。而且,我居然会喜欢这风吹麦浪的音响……

3.4.3. IEntityCache上手实战

既然如此是缓存实体,基于大家以此demo,我们就拿Task实体玩一下吗。
在这边大家先要复习下咋样是DTO,重申下DDD为何引入DTO。
Data Transfer Objects(DTO)用来在应用层和显现层之间传输数据。

DTO的必要性:

  1. 领域层的架空
  2. 数码隐藏
  3. 连串化和延期加载问题

那那多少个DTO跟要讲的实体缓存有哪些关系呢?
不绕弯子了,就是说实体缓存不应直接对Entity进行缓存,以幸免缓存时体系化了不该系列化的对象和实业。
这现实怎么操作呢?大家就直接上Demo吧。
大家定义一个TaskCacheItem,用来缓存Title、Description、State。并定义映射规则[AutoMapFrom(typeof(Task))]

namespace LearningMpaAbp.Tasks.Dtos
{
    [AutoMapFrom(typeof(Task))]
    public class TaskCacheItem
    {
        public string Title { get; set; }

        public string Description { get; set; }

        public TaskState State { get; set; }
    }
}

上边我们定义一个针对TaskCacheItem的缓存接口。

namespace LearningMpaAbp.Tasks
{
    public interface ITaskCache:IEntityCache<TaskCacheItem>
    {
    }
}

实现ITaskCache缓存接口:

namespace LearningMpaAbp.Tasks
{
    public class TaskCache : EntityCache<Task, TaskCacheItem>, ITaskCache, ISingletonDependency
    {
        public TaskCache(ICacheManager cacheManager, IRepository<Task, int> repository, string cacheName = null) 
            : base(cacheManager, repository, cacheName)
        {
        }
    }
}

近期,当我们需要遵照TaskId获取Title、Description、State,大家就足以因而在需要的类中流入注入ITaskCache,来从缓存中取得。
上面大家在ITaskAppService中添加一个接口TaskCacheItem GetTaskFromCacheById(int taskId);
然后在TaskAppService中落实它,声明变量并在构造函数注入ITaskCache,实现定义的接口:

private readonly ITaskCache _taskCache;

/// <summary>
///     In constructor, we can get needed classes/interfaces.
///     They are sent here by dependency injection system automatically.
/// </summary>
public TaskAppService(IRepository<Task> taskRepository, IRepository<User, long> userRepository,
    ISmtpEmailSenderConfiguration smtpEmialSenderConfigtion, INotificationPublisher notificationPublisher, ITaskCache taskCache)
{
    _taskRepository = taskRepository;
    _userRepository = userRepository;
    _smtpEmialSenderConfig = smtpEmialSenderConfigtion;
    _notificationPublisher = notificationPublisher;
    _taskCache = taskCache;
}

public TaskCacheItem GetTaskFromCacheById(int taskId)
{
    return _taskCache[taskId];
}

测试如下,直接在当下窗口调用方法,发现只有一条Sql查询生成,表达实体缓存成功。

地理 2

兴许读到这里,你恐怕会问,说好的『Redis缓存用起来』,你讲了半天,跟Redis没有半毛钱关系啊。

Redis这么狠心的技艺,当然要压轴登场啊,下边Redis开讲。

地理 3

3.3. 应用ICacheManager举办缓存

按照下面对Abp缓存机制的梳理,我们得以在急需利用缓存的地点注入ICacheManager来拓展缓存管理。
现行大家就在TasksController中注入ICacheManager
发明私有变量,并在构造函数中注入,代码如下:

private readonly ITaskAppService _taskAppService;
private readonly IUserAppService _userAppService;
private readonly ICacheManager _cacheManager;

public TasksController(ITaskAppService taskAppService, IUserAppService userAppService, ICacheManager _cacheManager) {
    _taskAppService = taskAppService;
    _userAppService = userAppService;
    _cacheManager = cacheManager;
}

下面修改RemoteCreateaction如下:

public PartialViewResult RemoteCreate()
{   
    var userList = _cacheManager.GetCache("ControllerCache").Get("AllUsers", 
                          () => _userAppService.GetUsers()) as ListResultDto<UserListDto>;
    ViewBag.AssignedPersonId = new SelectList(userList.Items, "Id", "Name");
    return PartialView("_CreateTaskPartial");
}

浅析代码发现我们在通过地点代码中收获的缓存是亟需展开类型转换的。原来_cacheManager.GetCache回到的是ICache类型,而ICache定义key-value相应的是string-object项目,所以本来从缓存获取完数据后要开展类型转换了(注:最新Abp版本为ICache提供了增添方法,不再需要出示进行类型转换)。这有没有泛型版本?聪明如你,作者对ICache拓展打包封装了个ITypedCache以贯彻项目安全。代码种举办了5种实现,可以一研究竟:

public PartialViewResult RemoteCreate()
{
    //1.1 注释该段代码,使用下面缓存的方式
    //var userList = _userAppService.GetUsers();

    //1.2 同步调用异步解决方案(最新Abp创建的模板项目已经去掉该同步方法,所以可以通过下面这种方式获取用户列表)
    //var userList = AsyncHelper.RunSync(() => _userAppService.GetUsersAsync());

    //1.3 缓存版本
    var userList = _cacheManager.GetCache("ControllerCache").Get("AllUsers", () => _userAppService.GetUsers());

    //1.4 转换为泛型版本
    //var userList = _cacheManager.GetCache("ControllerCache").AsTyped<string, ListResultDto<UserListDto>>().Get("AllUsers", () => _userAppService.GetUsers());

    //1.5 泛型缓存版本
    //var userList = _cacheManager.GetCache<string, ListResultDto<UserListDto>>("ControllerCache").Get("AllUsers", () => _userAppService.GetUsers());

    ViewBag.AssignedPersonId = new SelectList(userList.Items, "Id", "Name");
    return PartialView("_CreateTaskPartial");
}

经测试,用户列表正确缓存。

地理 4

与[OutputCache]相相比较,我们很当然就会问Abp提供的缓存怎么没有安排缓存过期岁月,你想到的框架肯定也想开了,Abp的默认缓存过期时间是60mins,我们得以经过在动用缓存项目标Module(模块)中自定义缓存时间。
因为大家是在Web项目中利用的Cache,所以一定到XxxWebModule.cs,在PreInitialize主意中展开缓存配置。

//配置所有Cache的默认过期时间为2小时
Configuration.Caching.ConfigureAll(cache =>
{
    cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2);
});

//配置指定的Cache过期时间为10分钟
Configuration.Caching.Configure("ControllerCache", cache =>
{
    cache.DefaultSlidingExpireTime = TimeSpan.FromMinutes(10);
});

当所有人都在忙正经事时,你是否上马舍弃真实的自己,和我们一道做一个正经人。并且在其旁人“不务正业”时,劝导他毫无有那个乱七八糟的想法,做一个正经人。在这一个时候,突然有人从怪圈子里跳出来鼓励你,扶助你,心底的种子怕是会在瞬间开出娇艳的花吧,小王子令人信任,豁然开朗,总有人会懂你。

3.4.1. 缓存形式的沉思

地点的二种缓存情势,我们一般用于存储自定义缓存,但有一个局限性,受到具体缓存过期时间的限制。
考虑一下,我们缓存的用户列表,它是一个实时会扭转的集结,而以此实时是风雨飘摇时的,可能1mins以内就有新用户注册,也有可能几天尚未用户注册(比如我们这多少个Demo),这一个时候就糟糕设置缓存过期(刷新)时间。
但鉴于我们是Demo性质只是为着演示用法,所以我们设定缓存过期时间为10mins也无可厚非。

这有没有一种缓存机制,不需要设置缓存过期光阴,当数码变化的时候就能活动重新缓存呢?
答案是早晚的,Abp为我们提供了IEntityCache,实体缓存机制。
当我们需要通过ID获取实体数据而又不想日常去数据库查询时,我们就可以利用IEntityCache
换句话说,IEntityCache补助按实体Id举办动态缓存。

这让自己记念了毛姆《面纱》中的句子:我领会您愚蠢、轻佻、头脑空虚,然则我爱你。我掌握您的图谋、你的美好,你势利、庸俗,但是我爱你。我精通您是个不好货色,然则我爱你。

7. 总结

这篇作品中重点梳理了Abp中咋样举行缓存管理,并简要介绍了Abp中的缓存机制,并与Asp.net
mvc自带的[Outputcache]缓存举办简短相比较,并开展了缓存管理实战演练。末了对Redis举行了简要介绍,并介绍了如何切换Redis缓存。

正因为你为你的玫瑰花费了时光,这才使您的玫瑰变得这般重大。

3.2. 使用[OutputCache]开展缓存

假如对OutputCache不精通,可以参照我的那篇著作Asp.net mvc
知多少(九)

我们可以省略在Action上添加[OutputCache]特性即可。

[OutputCache(Duration = 1200, VaryByParam = "none")]
[ChildActionOnly] 
public PartialViewResult Create() {
    var userList = _userAppService.GetUsers();
    ViewBag.AssignedPersonId = new SelectList(userList.Items, "Id", "Name");
    return PartialView("_CreateTask");
}

[OutputCache(Duration = 1200, VaryByParam = "none")]这句代码的意味是该action只缓存1200s。1200s后,ASP.NET
MVC会重新执行action同仁一视新缓存。因为是在[ChildActionOnly]中使用[OutputCache],所以该缓存属于Donut
Hole caching。
在该情势内部打个断点,测试唯有第一次调用会进入艺术内部,之后1200s内都不会再进来该办法,1200s后会再度进入,表明缓存成功!

地理 5

2. Abp的缓存机制

在一直利用缓存以前,大家仍然来大概梳理下Abp的缓存机制。
Abp之所以能成为一个得天独厚的DDD框架,我想跟笔者详细的文档有很大关系,
笔者曾经在ABP官方文档介绍了咋样运用Caching,英文水准好的就径直看官方的吗。

Abp对缓存举办抽象概念了ICache接口,位于Abp.Runtime.Caching取名空间。
并对ICache提供了默认的实现AbpMemoryCacheAbpMemoryCache是基于MemoryCache.aspx?f=255&MSPPError=-2147217396)的一种实现模式。MemoryCache是微软的一套缓存机制,定义在System.Runtime.Caching命名空间,顾名思义
,在内存中举办高速缓存。我们由此项目依赖图来看下Abp对Cache的实现:

地理 6

从图中可以看出重要概括三个部分:

  • ICache->CacheBase->AbpMemoryCache:对缓存的抽象以及落实;
  • ITypedCache:缓存的泛型实现;
  • ICacheManager->CacheManagerBase->AbpMemoryCacheManager:缓存管理类的架空和实现,代码中可以透过注入ICacheManager来获取缓存;
  • ICachingConfiguration->CachingConfiguration:用来部署利用哪一种缓存。

小王子拥有一棵独一无二的玫瑰花,他纯粹地,赤诚地爱着那朵玫瑰,虽然他自傲,虚荣。有一天他和她的玫瑰生了气,跑了出来,却在地球上发现了一个玫瑰园,原来他的玫瑰并不是无可比拟的,她非常难过。后来,他相见了一只狐狸,狐狸告诉她,小王子并不是惟一的,狐狸也不是,但当她们竞相驯化,相互需要时,就都变的独一无二了。玫瑰也是,正因为您为您的玫瑰花费了光阴,这才使你的玫瑰变得如此重要。

6.1. Abp集成Redis

率先打开Web层,下载Abp.RedisCache Nuget包安装。
修改XxxWebModule.cs,在DependsOn特性上添加对AbpRedisCacheModule的依赖,并在模块的PreInitialize形式中调用UseRedis扩展方法,代码如下:

[DependsOn(
        typeof(LearningMpaAbpDataModule),
        typeof(LearningMpaAbpApplicationModule),
        typeof(LearningMpaAbpWebApiModule),
        typeof(AbpWebSignalRModule),
        //typeof(AbpHangfireModule), - ENABLE TO USE HANGFIRE INSTEAD OF DEFAULT JOB MANAGER
        typeof(AbpWebMvcModule),
        typeof(AbpRedisCacheModule))]
    public class LearningMpaAbpWebModule : AbpModule
    {
        public override void PreInitialize()
        {
            //省略其他配置代码

            //配置使用Redis缓存
            Configuration.Caching.UseRedis();

            //配置所有Cache的默认过期时间为2小时
            Configuration.Caching.ConfigureAll(cache =>
            {
                cache.DefaultSlidingExpireTime = TimeSpan.FromHours(2);
            });

            //配置指定的Cache过期时间为10分钟
            Configuration.Caching.Configure("ControllerCache", cache =>
            {
                cache.DefaultSlidingExpireTime = TimeSpan.FromMinutes(10);
            });            
        }
  ....
}

说到底一步在Web.Config文件的【connectionStrings】节点为Abp.Redis.Cache累加连接字符串,如下:

  <connectionStrings>
    <add name="Default" connectionString="Server=.\sqlexpress; Database=LearningMpaAbp; Trusted_Connection=True;" providerName="System.Data.SqlClient" />
    <add name="Abp.Redis.Cache" connectionString="localhost"/>
  </connectionStrings>

起步Redis
Server后,F5运行web项目,断点调试,发现已经成功拔取Redis缓存。
若未启动Redis
Server,会报Error:It was not possible to connect to the redis server(s); to create a disconnected multiplexer, disable AbortOnConnectFail. SocketFailure on PING

地理 7

这样我们就用Redis取而代之了默认的MemoryCache缓存方案,而不需要改变此外代码,Abp就是如此简单、灵活、松藕合!

要是您爱上了一朵生长在一颗星星上的花,那么夜间,你看着天空就感到幸福愉快,所有的简单上都仿佛开着花。

ABP入门系列目录——学习Abp框架之实操演练
源码路径:Github-LearningMpaAbp

全面读《小王子》你会发现许多殷切而又难得的道理,关于爱与责任,仪式、空虚……请你真诚且怀有诚意的读这本属于您无比的《小王子》,永远年轻,永远热泪盈眶。

3.1. 原则性优化点

一定到我们的TasksController,其中有几种创造Task的Action,代码如下:

public PartialViewResult RemoteCreate() {
    var userList = _userAppService.GetUsers();
    ViewBag.AssignedPersonId = new SelectList(userList.Items, "Id", "Name");
    return PartialView("_CreateTaskPartial");
}

[ChildActionOnly] 
public PartialViewResult Create() {
    var userList = _userAppService.GetUsers();
    ViewBag.AssignedPersonId = new SelectList(userList.Items, "Id", "Name");
    return PartialView("_CreateTask");
}

可以看来多少个法子都急需调用_userAppService.GetUsers();来收获用户列表。
明日大家来行使缓存技术对其优化。首先大家相应想到了Asp.net
mvc自带的一套缓存机制,OutputCache。


3.4. 使用IEntityCache对实体举行缓存

狐狸与小王子分别时,狐狸哭了,小王子说:你如何利益也没得到。

6. ABP上试玩Redis缓存

接着自己的步履,对Redis也算有了着力的认识,我们上面就进入明日的压轴主旨,介绍Abp下怎么使用redis举办缓存。
率先我们要明了为啥要用Redis举办缓存。
默认的缓存管理是在内存中(in-memory)举办缓存。当您有随地一个并发web服务器需要周转同一个应用程序,默认的缓存管理就不知足你的需求。你或许需要一个分布式/中心缓存服务器来进展缓存管理,这时Redis就足以登台了。

飞行员原来的梦想是美学家,他欣赏画自己想象中的任何事物,当她信心满满地把画着吞着大象的巨蟒的画给爹妈看时,大人们却漠视地告诉她,这只是个帽子。同时劝她吐弃自己的绘画梦想和父四姨们一块“忙正事”,飞行员便真的初步不动声色地做一个老人家了。直到他遇见了向他讨要小羊画的小王子,他把画着帽子的画拿给她时,小王子却说“我毫无吞了大象的巨蟒,我一旦一只小羊。”

1. 引言

创办任务时我们需要指定分配给谁,Demo中我们采取一个下拉列表用来呈现当前系统的兼具用户,以供用户选用。大家每创制一个职责时都要去数据库取两次用户列表,然后绑定到用户下拉列表扬显。要是就只有对一个demo来说,这样实现也无可厚非,不过在专业项目中,显明是不创立的,浪费程序性能,有待优化。
说到优化,你肯定立即就悟出了利用缓存。是的,缓存是增进程序性能的短平快模式之一。
这一节我们就对准这一案例来看一看Abp中怎么样使用缓存来增强程序性能。

《小王子》是法兰西文学家安托万·德·圣·埃克苏佩里于1942年写成的头面小孩子法学短篇随笔。即便是小孩子经济学,但这并不阻拦它变成所有人的童话,初读时懵懵懂懂,再读时热泪盈眶。当你怀着大人的激情来读这本书时,它会显示异常无聊,但是还好,大家都曾是个少年。

3. Abp缓存实操演练

豁然开朗,总有人懂你。

5.2. 粗略试玩

找到安装目录,打开cmd并进入到安装目录,输入redis-server redis.windows.conf,即可启动Redis
服务。Redis服务默认启动在6379端口。

地理 8

再起步一个cmd窗口,执行redis-cli.exe即可开一个Redis客户端。
执行set一声令下举行缓存设置;
执行get命令举行缓存读取;
执行subscribe一声令下举行频道监听;
执行publish命令向指定频道发表新闻;
具体步骤详参下图:

地理 9

鉴于玉米的由来,我依旧得到了功利。

5. 出手试玩Redis

狐狸说:由于稻谷的缘故,我要么拿到了便宜。

3.4.2. IEntityCache缓存法则

在演示具体操作在此以前,我们先来讲学下IEntityCache的缓存原理:

  • 首先它首先次从数据库中拿到实体,然后继续调用将会从缓存获取。
  • 当实体更新或删除时它自动将缓存的实业置为无效状态,因而它将会再下两回呼吁中从数据库中另行赢得。
  • 它应用缓存的类的完好类名作为缓存名称,可以透过为构造函数传参来修改缓存名称。
  • 它是线程安全的。
  • 它应用IObjectMapper将实体映射到缓存项。
    IObjectMapper由AutoMapper模块实现。所以,假若你使用它,你需要AutoMapper模块。您可以覆盖MapToCacheItem方法以手动将实体映射到缓存项。

当所有人执着于追求高速、高效的中标,做正面高尚的行事时,却忘记了,成功之所以体贴,是因为它花费时间。人们连续为工作、为生存奔波,忙正经事,可什么人又能说,欣赏一朵小花,不是一件正经事呢。我爱她,仅仅是因为自身爱他。


《小王子》是以一个叙述者的口气最先的,叙述者是一个落寞的试飞员,因为她在家长的世界里找不到可以并行倾诉的人,大人们都太实在了。直到有一天,他因飞机故障被迫降落撒哈拉沙漠,在这边,他遇见了来自另一个星体的小王子。小王子讲述了和谐的故事,他离开了协调的星星,在抵达地球在此之前访问了多少个星球,他遇见了呼喊着统治整个的天皇,体贴虚荣的“绅士”,酒鬼,商人,为星球点灯的人,未曾探索地理的地医学家,空虚的玫瑰园,和交互驯化的狐狸……最重点的是讲述了属于自己独一无二的玫瑰的故事。

                                                          ——小王子

相关文章

No Comments, Be The First!
近期评论
    分类目录
    功能
    网站地图xml地图