ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统

简介: 原文:ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统升级到 Asp.Net Core 2.0 (2017/08/29 更新) 为什么使用 Jwt 最近,移动开发的劲头越来越足,学校搞的各种比赛都需要用手机 APP 来撑场面,所以,作为写后端的,很有必要改进一下以往的基于 ...
原文: ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统

升级到 Asp.Net Core 2.0 (2017/08/29 更新)

为什么使用 Jwt

最近,移动开发的劲头越来越足,学校搞的各种比赛都需要用手机 APP 来撑场面,所以,作为写后端的,很有必要改进一下以往的基于 Session 的身份认证方式了,理由如下:

  1. 移动端经常要保持长时间(1 到 2 星期)在线,但是 Session 却不好在服务端保存这么久,虽然可以持久化到数据库,但是还是挺费资源
  2. 移动端往往不是使用的网页技术,所以藏在 Cookie 里面的 SessionId 不是很方便的传递给服务端
  3. 服务端暴露给客户端的接口往往是 RESTful 风格的,这是一种无状态的 API 风格,所以身份认证的方式最好也是无状态的才好

所以我选择了使用 Jwt (Json Web Token) 这个技术。Jwt 是一种无状态的分布式的身份验证方式,与 Session 相反,Jwt 将用户信息存放在 Token 的 payload 字段保存在客户端,通过 RSA 加密的方式,保证数据不会被篡改,验证数据有效性。
下面是一个使用 Jwt 的系统的身份验证流程:

image_1bfoostkp1rc3q5gn7o1nqs10c99.png-59.6kB

可以看出,用户的信息保存在 Token 中,而 Token 分布在用户的设备中,所以服务端不再需要在内存中保存用户信息了
身份认证的 Token 传递时以一种相当简单的格式保存在 header 中,方便客户端对其进行操作

Jwt 简介

Jwt 形式的 token 一般分为 3 个部分,分别是 Header,Payload,Signature,这三个部分使用 . 分隔。其中前两部分使用 Base64 编码,未经加密处理,第三个部分使用 RSA 加密。
所以一个 Jwt 看起来大概是这个样子:

header.payload.signature

下面是一个真实的 Jwt:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6InplZWtvIiwicm9sZSI6IiIsIm5hbWVpZCI6MSwianRpIjoiNjNjN2Q3OWY2N2VhMDhjYjRiYzNjMmNkOTJiY2JkNTgiLCJuYmYiOjE0OTQ0MDMwMjQsImV4cCI6MTQ5NTAwNzgyMywiaWF0IjoxNDk0NDAzMDI0LCJpc3MiOiJUZXN0SXNzdWVyIiwiYXVkIjoiVGVzdEF1ZGllbmNlIn0.V7Mfi3FGOTLYV0O5DmOWju7LkDJwZNO6HZN19CHb3ekYxcoVbP51YjYAr0fUHc3RPIp3gxITzziHY-07xZ2swCaV0K-hiF5IbwpDuvyxsnlgaRxS94wKDGKSJkArC82KukCtm7IuFBxnNr6kxe7tGcebVhqtaqgnxEUg5lKtDtVI85kd17YtzBp9Vxnc3Ie0r-6KPgUa2HacCf2Pc3hkvY7tZdWZ6ininZlZ-EbcyZI2KTx-vOqdK63MS2JYSw7W2qwf89tsRsORwbB2P4dOBBFK8YSXJpeyGeJWFEMjAMkiH3AeMmW2w_H7r_6Pn-jh5gozzBei4JoHTU6RVDUg1A

Header

Header 部分一般用来记录加密算法跟 Token 类型
举个例子:

{
  "alg": "HS256",
  "typ": "JWT"
}

Payload

Payload 存放的是一些不敏感的用户数据,因为这一部分仅仅只是使用 Base64 加密,所以不应该用来保存用户的密码之类的信息。

一个例子:

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Signature

这一部分是 Jwt 最重要的部分,使用 header 中记录的算法进行了加密,加密方式如下:

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

所以这个部分可以用来保证用户信息不被篡改,起到验证用户身份的作用

在开发过程中,可以访问 https://jwt.io 来调试 Token
当然,为了更快的访问速度,还可以使用 这个网站

在 ASP.NET Core 中使用 Jwt

因为 Jwt 本身的特点,所以用来签发 Token 的服务器可以跟应用服务器不是同一台,这样就可以搞微服务之类的东西(反正我不懂。。。)
因此,在这篇博客中,将会创建两个 Web 应用:

  • JwtIssuer // 用来签发 Token
  • JwtAudience // 应用服务器,提供 API 的

image_1bfoq5a6k16231f5k291fba1f0fm.png-2.6kB

首先来搭建我们的 Token 签发服务器吧!

签发第一个 Token

由于要使用到 RSA 加密,所以先创建一个辅助类来帮助简化调用:

RSAUtils.cs

using System.IO;
using System.Security.Cryptography;
using Newtonsoft.Json;

namespace JwtUtils
{
    public static class RSAUtils
    {
        /// 
        /// 从本地文件中读取用来签发 Token 的 RSA Key
        /// 
        /// 
存放密钥的文件夹路径 /// /// /// public static bool TryGetKeyParameters(string filePath, bool withPrivate, out RSAParameters keyParameters) { string filename = withPrivate ? "key.json" : "key.public.json"; keyParameters = default(RSAParameters); if (Directory.Exists(filePath) == false) return false; keyParameters = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine(filePath, filename))); return true; } /// /// 生成并保存 RSA 公钥与私钥 /// /// 存放密钥的文件夹路径 /// public static RSAParameters GenerateAndSaveKey(string filePath) { RSAParameters publicKeys, privateKeys; using (var rsa = new RSACryptoServiceProvider(2048)) { try { privateKeys = rsa.ExportParameters(true); publicKeys = rsa.ExportParameters(false); } finally { rsa.PersistKeyInCsp = false; } } File.WriteAllText(Path.Combine(filePath, "key.json"), JsonConvert.SerializeObject(privateKeys)); File.WriteAllText(Path.Combine(filePath, "key.public.json"), JsonConvert.SerializeObject(publicKeys)); return privateKeys; } } }

这个工具类能够帮助我们生成 RSA 密钥,并把生成的私钥跟公钥保存在两个文件中,还能从文件中读取密钥。

然后定义一个数据类,用来帮助我们在应用的各个地方获取加密相关的信息:

JWTTokenOptions.cs

using Microsoft.IdentityModel.Tokens;

namespace JwtUtils
{
    public class JWTTokenOptions
    {
        public string Audience { get; set; }
        public RsaSecurityKey Key { get; set; }
        public SigningCredentials Credentials { get; set; }
        public string Issuer { get; set; }
    }
}

接下来在 Startup.cs 中配置 Jwt 的加密选项:

public void ConfigureServices(IServiceCollection services)
        {
            // 省略了其他的东西
            
            // 从文件读取密钥
            string keyDir = PlatformServices.Default.Application.ApplicationBasePath;
            if (RSAUtils.TryGetKeyParameters(keyDir, true, out RSAParameters keyParams) == false)
            {
                keyParams = RSAUtils.GenerateAndSaveKey(keyDir);
            }
            _tokenOptions.Key = new RsaSecurityKey(keyParams);
            _tokenOptions.Issuer = "TestIssuer"; // 签发者名称
            _tokenOptions.Credentials = new SigningCredentials(_tokenOptions.Key, SecurityAlgorithms.RsaSha256Signature);
            // 添加到 IoC 容器
            services.AddSingleton(_tokenOptions);
            
            services.AddMvc();
        }

接下来创建一个控制器,用来提供签发 Token 的 API

TokenController.cs

namespace JwtIssuer.Controllers
{
    [Route("api/[controller]")]
    public class TokenController : Controller
    {
        private readonly JWTTokenOptions _tokenOptions;
        private readonly AuthDbContext _dbContext;

        public TokenController(JWTTokenOptions tokenOptions, AuthDbContext dbContext)
        {
            _tokenOptions = tokenOptions;
            _dbContext = dbContext;
        }

        /// 
        /// 生成一个新的 Token
        /// 
        /// 
用户信息实体 /// token 过期时间 /// Token 接收者 /// private string CreateToken(User user, DateTime expire, string audience) { var handler = new JwtSecurityTokenHandler(); string jti = audience + user.Username + expire.GetMilliseconds(); jti = jti.GetMd5(); // Jwt 的一个参数,用来标识 Token var claims = new[] { new Claim(ClaimTypes.Role, user.Role ?? string.Empty), // 添加角色信息 new Claim(ClaimTypes.NameIdentifier, user.Id.ToString(), // 用户 Id ClaimValueTypes.Integer32), new Claim("jti",jti,ClaimValueTypes.String) // jti,用来标识 token }; ClaimsIdentity identity = new ClaimsIdentity(new GenericIdentity(user.Username, "TokenAuth"), claims); var token = handler.CreateEncodedJwt(new SecurityTokenDescriptor { Issuer = "TestIssuer", // 指定 Token 签发者,也就是这个签发服务器的名称 Audience = audience, // 指定 Token 接收者 SigningCredentials = _tokenOptions.Credentials, Subject = identity, Expires = expire }); return token; } /// /// 用户登录 /// /// 用户登录信息 /// 要访问的网站 /// [HttpPost("{audience}")] public IActionResult Post([FromBody]User user, string audience) { DateTime expire = DateTime.Now.AddDays(7); // 在这里来验证用户的用户名、密码 var result = _dbContext.Users.First(u => u.Username == user.Username && u.Password == user.Password); if (result == null) { return Json(new { Error = "用户名或密码错误" }); } return Json(new { Token = CreateToken(result, expire, audience) }); } } }

现在,访问这个 API(http://localhost:port/api/token/TestAudience) 就可以获取用户的 Token 了

image_1bfovtq6k11cg2baslp1p0k1nkk34.png-85.4kB

在应用服务器验证 Token

在 Startup.cs 中注册 Jwt 相关的服务:

public void ConfigureServices(IServiceCollection services)
        {
            // 省略了其他的内容
            
             // 从文件读取密钥
            string keyDir = PlatformServices.Default.Application.ApplicationBasePath;
            if (RSAUtils.TryGetKeyParameters(keyDir, false, out RSAParameters keyparams) == false)
            {
                _tokenOptions.Key = default(RsaSecurityKey);
            }
            else
            {
                _tokenOptions.Key = new RsaSecurityKey(keyparams);
            }
            _tokenOptions.Issuer = "TestIssuer"; // 设置签发者
            _tokenOptions.Audience = "TestAudience"; // 设置签收者,也就是这个应用服务器的名称
            _tokenOptions.Credentials = new SigningCredentials(_tokenOptions.Key, SecurityAlgorithms.RsaSha256Signature);

            services.AddAuthorization(auth =>
            {
                auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
                    .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
                    .RequireAuthenticatedUser()
                    .Build());
            });
            
            // Add framework services.
            services.AddMvc();
        }

然后在 Startup.cs 添加 Jwt 认证中间件:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
        {
            // 省略了其他的内容

            app.UseJwtBearerAuthentication(new JwtBearerOptions
            {
                TokenValidationParameters = new TokenValidationParameters
                {
                    IssuerSigningKey = _tokenOptions.Key,
                    ValidAudience = _tokenOptions.Audience, // 设置接收者必须是 TestAudience
                    ValidIssuer = _tokenOptions.Issuer, // 设置签发者必须是 TestIssuer
                    ValidateLifetime = true
                }
            });

        }

接着随便创建一个 API 控制器

namespace JwtAudience.Controllers
{
    [Route("api/[controller]")]
    public class ValuesController : Controller
    {
        // GET api/values
        [HttpGet]
        [Authorize]
        public IEnumerable Get()
        {
            return new string[] { "value1", "value2" };
        }
        
    }
}

首先编译一下应用服务器,但是不要急着运行。因为应用服务器验证 Token 是需要公钥的,所以现在去之前的签发服务器的 build 目录
image_1bfov9v1jngmv0p128d1mh81kn41g.png-46.4kB

可以看到生成了两个json文件,将其中的 key.public.json 拷贝到应用服务器的对应的目录下面,然后运行应用服务器。

如果我们直接访问应用服务器的 API,就会被挡在外面:

image_1bfovfiiqmcsofb1d0e14r2kd51t.png-47.6kB

所以现在去把之前拿到的 token 复制出来,然后给这个请求加个请求头——Authorization
值是 Bearer 你的Token

image_1bfovjhie6fu1erfca510t51f3j2a.png-46.4kB
这样,基本的身份验证就完成了~

有兴趣的话还可以把这个 Token 放在前面提到的用来调试 Jwt 网站上,我的 Token 的解析结果是:

image_1bfovmv6l12gi11c7rvu1duvo8f2n.png-39.8kB

这里面的 iss 指的就是签发者,aud 指的是接收者,对于我们的应用服务器来说,这两个参数错了任意一个都将无法通过验证(这里就不演示了,等会儿会有测试代码~)

真的足够安全?

至此,我们已经把 Jwt 的身份认证基本实现了,但是仔细想想,却发现存在一个很严重的问题————用户的 Token 在过期时间之内根本无法手动设置失效,随之而来的还有重放攻击等等问题!

Jwt官方也没有提供很好的应对方法,现在就只有一条路可以走,就是把失效的 Token 加入黑名单。只要能够让 Token 失效,之后应对这些安全问题就只是策略上的选择。

在 Jwt 的官方说明中,jti 这个参数就是用来标识 Token 的。所以,让一个 Token 失效只需要把这个 Token 中的 jti 加入应用服务器的数据库的黑名单就好了。

得益于微软对 Identity 良好的设计,我们可以很容易的拓展默认的 Jwt 认证规则

首先创建一个 ValidJtiRequirement 类

public class ValidJtiRequirement : IAuthorizationRequirement
{
}

嗯,他的结构就是这么简单。。。

然后创建一个用来验证这个 Requirement 的 ValidJtiHandler

public class ValidJtiHandler : AuthorizationHandler
{
    private readonly AudienceDbContext _dbContext;

    public ValidJtiHandler(AudienceDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidJtiRequirement requirement)
    {
        // 检查 Jti 是否存在
        var jti = context.User.FindFirst("jti")?.Value;
        if (jti == null)
        {
            context.Fail(); // 显式的声明验证失败
            return Task.CompletedTask;
        }

        // 检查 jti 是否在黑名单
        var tokenExists = _dbContext.BlackRecords.Any(r => r.Jti == jti);
        if (tokenExists)
        {
            context.Fail();
        }
        else
        {
            context.Succeed(requirement); // 显式的声明验证成功
        }
        return Task.CompletedTask;

    }
}

最后,稍微的修改一下注册服务时的代码

services.AddAuthorization(auth =>
{
    auth.AddPolicy("Bearer", new AuthorizationPolicyBuilder()
        .AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)
        .RequireAuthenticatedUser()
        .AddRequirements(new ValidJtiRequirement()) // 添加上面的验证要求
        .Build());
});
// 注册验证要求的处理器,可通过这种方式对同一种要求添加多种验证
services.AddSingleton();

最后再来提供一个使 Token 失效的 API

namespace JwtAudience.Controllers
{
    [Route("api/[controller]")]
    public class TokenController : Controller
    {
        private readonly AudienceDbContext _dbContext;

        public TokenController(AudienceDbContext dbContext)
        {
            _dbContext = dbContext;
        }

        [HttpGet]
        public IActionResult Get() => Json(_dbContext.BlackRecords);

        /// 
        /// 使用户的 Token 失效
        /// 
        /// 
        [Authorize("Bearer")]
        [HttpDelete]
        public IActionResult Delete()
        {
            // 从 payload 中提取 jti 字段
            var jti = User.FindFirst("jti")?.Value;
            var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
            if (jti == null)
            {
                HttpContext.Response.StatusCode = 400;
                return Json(new { Result = false });
            }
            // 把这个 jti 加入数据库
            _dbContext.BlackRecords.Add(new BlackRecord { Jti = jti, UserId = userId });
            _dbContext.SaveChanges();
            return Json(new {Result = true});
        }
    }
}

这里需要注意的是,因为拓展了默认的验证策略,所以需要在 Authorize 这个特性钦定使用 Bearer 策略:

[Authorize("Bearer")]

但是这样就容易在编码的时候出现拼写错误,所以来创建一个继承自这个特性的BearerAuthorize类。

namespace JwtAudience
{
    /// 
    /// Jwt 验证
    /// 
    public class BearerAuthorizeAttribute : AuthorizeAttribute
    {
        public BearerAuthorizeAttribute() : base("Bearer") { }
    }
}

现在我们就可以使用[BearerAuthorize]来替代[Authorize]

至此,使 token 失效的能力就具备了。

然后附带一份测试代码,用来检验认证过程是否符合我们的预期:

升级到 Asp.Net Core 2.0 (2017/08/29)

花了一天时间来把项目升级到 2.0,并不是因为 API 变化很大,而是之前的 bug 有些多,修起来有些慢。

首先要升级 Program.cs 里面的 Main 函数:

public class Program
{
    public static void Main(string[] args)
    {
        BuildWebHost(args).Run();
    }

    public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup()
            .Build();
}

看起来更简短了一些。

接下来升级认证配置,按照官方的说明,所有的 app.UseXxxAuthentication 方法都变成了 service.AddAuthentication(XxxSchema).AddXxx(),所以改动不是很大:

JwtIssuer/Startup.cs/ConfigureServices

services.AddAuthentication().AddJwtBearer(jwtOptions =>
{
    jwtOptions.TokenValidationParameters = new TokenValidationParameters
    {
        IssuerSigningKey = _tokenOptions.Key,
        ValidAudience = _tokenOptions.Audience,
        ValidIssuer = _tokenOptions.Issuer,
        ValidateLifetime = true
    };
});

JwtAudience/Startup.cs/ConfigureServices

services.AddAuthentication().AddJwtBearer(jwtOptions =>
{
    jwtOptions.TokenValidationParameters = new TokenValidationParameters
    {
        IssuerSigningKey = _tokenOptions.Key,
        ValidAudience = _tokenOptions.Audience,
        ValidIssuer = _tokenOptions.Issuer,
        ValidateLifetime = true
    };
});

至此,需要升级的地方就修改好了,但是到目前为止还是无法运行,因为有些在 1.0 里面没有严格检验的地方开始报错了。

第一个地方是 ValidJtiHandler,之前在注册的时候,生命周期选的是单例并没有报错,但是因为这个类依赖了一个生命周期是 Scoped 的对象—— AudienceDbContext,这会引发一个异常,解决方法是把 ValidJtiHandler 也改成 Scoped:

services.AddScoped();

第二个地方是 RSAParameters 在 2.x 里面,它的私钥属性不能被 Json.Net 序列化,解决方法也很简单,加一个对应的类似 DTO 的类:

class RsaParameterStorage
{
    public byte[] D { get; set; }
    public byte[] DP { get; set; }
    public byte[] DQ { get; set; }
    public byte[] Exponent { get; set; }
    public byte[] InverseQ { get; set; }
    public byte[] Modulus { get; set; }
    public byte[] P { get; set; }
    public byte[] Q { get; set; }
}

然后在导出私钥前将 RSAParameters 映射成一个 RsaParameterStorage对象,然后使用 Json.Net 来序列化,映射使用的是我自己写的一个 Mapper(所以升级项目只花了几十分钟,调教 Mapper 花了一天),代码更改如下:

// 转换成 json 字符串
static string ToJsonString(this RSAParameters parameters)
{
    var content = parameters.Map().To();
    return JsonConvert.SerializeObject(content);
}

// 从文件中读取
keyParameters = JsonConvert.DeserializeObject(File.ReadAllText(filePath)).Map().To();
目录
相关文章
|
8月前
|
Kubernetes 大数据 调度
Airflow vs Argo Workflows:分布式任务调度系统的“华山论剑”
本文对比了Apache Airflow与Argo Workflows两大分布式任务调度系统。两者均支持复杂的DAG任务编排、社区支持及任务调度功能,且具备优秀的用户界面。Airflow以Python为核心语言,适合数据科学家使用,拥有丰富的Operator库和云服务集成能力;而Argo Workflows基于Kubernetes设计,支持YAML和Python双语定义工作流,具备轻量化、高性能并发调度的优势,并通过Kubernetes的RBAC机制实现多用户隔离。在大数据和AI场景中,Airflow擅长结合云厂商服务,Argo则更适配Kubernetes生态下的深度集成。
1006 34
|
6月前
|
前端开发 JavaScript 关系型数据库
使用 OpenAuth.Net 快速搭建 .NET 企业级权限工作流系统
使用 OpenAuth.Net 快速搭建 .NET 企业级权限工作流系统
206 0
|
3月前
|
开发框架 .NET C#
ASP.NET Core Blazor 路由配置和导航
大家好,我是码农刚子。本文系统介绍Blazor单页应用的路由机制,涵盖基础配置、路由参数、编程式导航及高级功能。通过@page指令定义路由,支持参数约束、可选参数与通配符捕获,结合NavigationManager实现页面跳转与参数传递,并演示用户管理、产品展示等典型场景,全面掌握Blazor路由从入门到实战的完整方案。
325 6
|
4月前
|
存储 算法 安全
“卧槽,系统又崩了!”——别慌,这也许是你看过最通俗易懂的分布式入门
本文深入解析分布式系统核心机制:数据分片与冗余副本实现扩展与高可用,租约、多数派及Gossip协议保障一致性与容错。探讨节点故障、网络延迟等挑战,揭示CFT/BFT容错原理,剖析规模与性能关系,为构建可靠分布式系统提供理论支撑。
269 2
|
4月前
|
机器学习/深度学习 算法 安全
新型电力系统下多分布式电源接入配电网承载力评估方法研究(Matlab代码实现)
新型电力系统下多分布式电源接入配电网承载力评估方法研究(Matlab代码实现)
173 3
|
6月前
|
数据采集 缓存 NoSQL
分布式新闻数据采集系统的同步效率优化实战
本文介绍了一个针对高频新闻站点的分布式爬虫系统优化方案。通过引入异步任务机制、本地缓存池、Redis pipeline 批量写入及身份池策略,系统采集效率提升近两倍,数据同步延迟显著降低,实现了分钟级热点追踪能力,为实时舆情监控与分析提供了高效、稳定的数据支持。
246 1
分布式新闻数据采集系统的同步效率优化实战
|
8月前
|
存储 算法 安全
JWT深度解析:现代Web身份验证的通行证为什么现在都是JWT为什么要restful-优雅草卓伊凡
JWT深度解析:现代Web身份验证的通行证为什么现在都是JWT为什么要restful-优雅草卓伊凡
435 41
JWT深度解析:现代Web身份验证的通行证为什么现在都是JWT为什么要restful-优雅草卓伊凡
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:<https://github.com/khellang/Scrutor>
342 5
|
9月前
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
368 0
|
12月前
|
存储 运维 安全
盘古分布式存储系统的稳定性实践
本文介绍了阿里云飞天盘古分布式存储系统的稳定性实践。盘古作为阿里云的核心组件,支撑了阿里巴巴集团的众多业务,确保数据高可靠性、系统高可用性和安全生产运维是其关键目标。文章详细探讨了数据不丢不错、系统高可用性的实现方法,以及通过故障演练、自动化发布和健康检查等手段保障生产安全。总结指出,稳定性是一项系统工程,需要持续迭代演进,盘古经过十年以上的线上锤炼,积累了丰富的实践经验。
947 7

热门文章

最新文章