在 .NET Core 中从 Redis 迁移到本地内存中缓存:分步指南

作者:微信公众号:【架构师老卢】
8-9 17:7
32

概述:作为一名全栈开发人员,我最近在 .NET Core 项目中完成了从 Redis 过渡到内存缓存的过程。这种转变的驱动力是需要简化我们的架构并提高特定方案的性能。在本文中,我将指导你完成此迁移的步骤,提供编码做法,并演示在微服务体系结构中使用 .NET Core 后端和 TypeScript 前端的实际方案。为什么要迁移到内存中缓存?虽然 Redis 是一种强大的缓存解决方案,但内存中缓存在某些情况下可以提供优势,例如:单纯: 通过消除对单独缓存服务器的需求,降低了基础架构的复杂性。性能: 更快的访问时间,因为数据直接存储在应用程序的内存中。成本: 通过消除维护和扩展 Redis 实例的需要来降

作为一名全栈开发人员,我最近在 .NET Core 项目中完成了从 Redis 过渡到内存缓存的过程。这种转变的驱动力是需要简化我们的架构并提高特定方案的性能。在本文中,我将指导你完成此迁移的步骤,提供编码做法,并演示在微服务体系结构中使用 .NET Core 后端和 TypeScript 前端的实际方案。

为什么要迁移到内存中缓存?

虽然 Redis 是一种强大的缓存解决方案,但内存中缓存在某些情况下可以提供优势,例如:

  • 单纯: 通过消除对单独缓存服务器的需求,降低了基础架构的复杂性。
  • 性能: 更快的访问时间,因为数据直接存储在应用程序的内存中。
  • 成本: 通过消除维护和扩展 Redis 实例的需要来降低运营成本。

分步迁移

1. 调整架构

我们的架构基本保持不变,只是我们用内存缓存替换了 Redis:

  • 用户服务: 处理与用户相关的操作。
  • 功能服务: 管理新的缓存功能及其逻辑。
  • API网关: 将请求路由到相应的服务。
  • 前端应用: 与后端服务交互。
  • 内存中缓存: 充当缓存层。

2. 在 .NET Core 中设置内存中缓存

添加必要的软件包

请确保 .NET Core 项目中具有所需的包。

dotnet add package Microsoft.Extensions.Caching.Memory

配置 In-Memory 缓存

在文件中配置内存中缓存。Startup.cs

// Startup.cs  
public void ConfigureServices(IServiceCollection services)  
{  
    services.AddMemoryCache();  
  
    services.AddScoped<IFeatureService, FeatureService>();  
    services.AddDbContext<AppDbContext>(options =>  
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));  
    services.AddControllers();  
}

在服务中实现缓存

更新服务以使用内存中缓存。

// FeatureService.cs
public class FeatureService : IFeatureService
{
    private readonly AppDbContext _context;
    private readonly IMemoryCache _cache;

    public FeatureService(AppDbContext context, IMemoryCache cache)
    {
        _context = context;
        _cache = cache;
    }

    public async Task<FeatureResponse> ProcessFeatureAsync(FeatureRequest request)
    {
        var cacheKey = $"Feature-{request.Input}";
        if (_cache.TryGetValue(cacheKey, out FeatureResponse cachedData))
        {
            return cachedData;
        }

        // Simulate processing
        var result = new FeatureResponse
        {
            Success = true,
            Message = "Feature processed successfully"
        };

        _cache.Set(cacheKey, result, new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
        });

        return result;
    }
}

设置控制器

// FeatureController.cs
[ApiController]
[Route("api/[controller]")]
public class FeatureController : ControllerBase
{
    private readonly IFeatureService _featureService;

    public FeatureController(IFeatureService featureService)
    {
        _featureService = featureService;
    }

    [HttpPost]
    public async Task<IActionResult> ProcessFeature([FromBody] FeatureRequest request)
    {
        var response = await _featureService.ProcessFeatureAsync(request);
        return Ok(response);
    }
}

3. 开发前端

我们继续使用带有 TypeScript 的 React 作为前端应用程序。

设置 API 服务

// apiService.ts
import axios from 'axios';

export const processFeature = async (data: FeatureRequest) => {
  try {
    const response = await axios.post<FeatureResponse>('/api/feature', data);
    return response.data;
  } catch (error) {
    throw new Error('Failed to process feature');
  }
};

创建 React 组件

// FeatureComponent.tsx
import React, { useState } from 'react';
import { processFeature } from './apiService';

const FeatureComponent: React.FC = () => {
  const [input, setInput] = useState('');
  const [message, setMessage] = useState('');

  const handleSubmit = async (event: React.FormEvent) => {
    event.preventDefault();
    try {
      const response = await processFeature({ input });
      setMessage(response.message);
    } catch (error) {
      setMessage('Error processing feature');
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
        />
        <button type="submit">Submit</button>
      </form>
      {message && <p>{message}</p>}
    </div>
  );
};

export default FeatureComponent;

创建 React 组件

// FeatureComponent.tsx
import React, { useState } from 'react';
import { processFeature } from './apiService';

const FeatureComponent: React.FC = () => {
  const [input, setInput] = useState('');
  const [message, setMessage] = useState('');

  const handleSubmit = async (event: React.FormEvent) => {
    event.preventDefault();
    try {
      const response = await processFeature({ input });
      setMessage(response.message);
    } catch (error) {
      setMessage('Error processing feature');
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
        />
        <button type="submit">Submit</button>
      </form>
      {message && <p>{message}</p>}
    </div>
  );
};

export default FeatureComponent;

4. 测试和部署

在实现内存中缓存后,我们进行了彻底的测试:

  • 单元测试: 确保各个组件按预期工作。
  • 集成测试: 验证服务之间的交互。
  • 性能测试: 衡量内存中缓存对响应时间的影响。
  • 用户验收测试 (UAT): 让真实用户参与验证解决方案。

最后,我们分阶段部署了新的缓存机制,从有限的 beta 版本开始。

编码实践和真实世界场景

以下是一些基于我们的迁移经验的编码实践和示例:

在 .NET Core 中使用依赖项注入Using Dependency Injection in .NET Core

依赖关系注入 (DI) 有助于管理依赖关系并促进干净的架构。

public void ConfigureServices(IServiceCollection services)  
{  
    services.AddMemoryCache();  
  
    services.AddScoped<IFeatureService, FeatureService>();  
    services.AddDbContext<AppDbContext>(options =>  
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));  
    services.AddControllers();  
}

在 TypeScript 中处理 API 请求

使用 Axios 处理 API 请求提供了一种干净简单的方法来处理 HTTP 请求。

import axios from 'axios';  
  
interface FeatureRequest {  
  input: string;  
}  
  
interface FeatureResponse {  
  success: boolean;  
  message: string;  
}  
  
export const processFeature = async (data: FeatureRequest): Promise<FeatureResponse> => {  
  try {  
    const response = await axios.post<FeatureResponse>('/api/feature', data);  
    return response.data;  
  } catch (error) {  
    throw new Error('Failed to process feature');  
  }  
};

React 中的状态管理

使用钩子管理功能组件中的状态。

const FeatureComponent: React.FC = () => {
  const [input, setInput] = useState('');
  const [message, setMessage] = useState('');

  const handleSubmit = async (event: React.FormEvent) => {
    event.preventDefault();
    try {
      const response = await processFeature({ input });
      setMessage(response.message);
    } catch (error) {
      setMessage('Error processing feature');
    }
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={input}
          onChange={(e) => setInput(e.target.value)}
        />
        <button type="submit">Submit</button>
      </form>
      {message && <p>{message}</p>}
    </div>
  );
};

在我们的 .NET Core 项目中从 Redis 迁移到内存中缓存简化了我们的架构,并提高了特定用例的性能。这一旅程强化了结构良好的开发方法和现代编码实践的重要性。通过将 .NET Core 用于后端,将 TypeScript 用于前端,我们创建了一个可靠且可缩放的解决方案,可有效满足用户的需求。

阅读排行