微服务之道:8个原则,打造高效的微服务体系

这篇具有很好参考价值的文章主要介绍了微服务之道:8个原则,打造高效的微服务体系。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

hi,我是熵减,见字如面。

现在,在大型的软件工程系统中,微服务化的系统设计,成为了大部分时候的必然之选。

而如何将微服务做有效的设计,则是需要每一个团队和工程师都需要考虑的一个问题。在保持系统的一致性、可理解性、可维护性和可扩展性上,需要有一些基本的指导原则。

下面分享微服务设计和实践中的8个基础原则,具体如下:

基本原则概览

在微服务中,设计API时可以遵循以下原则:

  • 单一职责原则(Single Responsibility Principle):每个微服务应该只关注一个特定的业务领域或功能,因此其API应该具有明确的职责,只提供与该领域或功能相关的接口。

  • 显式接口原则(Explicit Interface Principle):API应该明确和清晰地定义其接口,包括输入参数、输出结果和可能的错误码。这样可以提高接口的可理解性和可维护性,减少误用和不必要的沟通。

  • 界限上下文(Bounded Context):根据微服务的边界和业务需求,划分出不同的界限上下文。API的设计应该与界限上下文相匹配,以确保接口的一致性和内聚性。

  • 服务契约(Service Contract):API应该建立明确的服务契约,包括接口的语义、协议和版本管理。这有助于不同团队之间的协作,确保服务之间的兼容性和互操作性。

  • 信息隐藏(Information Hiding):API应该隐藏内部实现细节,只暴露必要的接口。这样可以减少对内部实现的依赖性,提高服务的独立性和可替代性。

  • 无状态性(Statelessness):尽量设计无状态的API,即不保存客户端的状态信息,每个请求都应该是独立的。这样可以提高服务的可伸缩性和容错性。

  • 适应性与演进性(Adaptability and Evolution):API应该具有适应性和演进性,能够容易地适应不同的需求和变化。通过版本控制和向后兼容性,可以使API在不破坏现有客户端的情况下进行演进和升级。

  • 安全性和身份验证(Security and Authentication):API应该提供适当的安全机制和身份验证,以保护服务和数据的安全性。这可能包括使用加密传输、身份验证令牌和访问控制等措施。

接下来,我们将通过日常的一些具体demo,来逐个展开这8个原则。

原则具体实例

单一职责原则

以下是一个违反单一职责原则的反例,使用Java代码进行演示:

public class UserAPI {
    
    public void createUser(String username, String password) {
        // 创建用户的逻辑
    }
    
    public void getUserInfo(String username) {
        // 获取用户信息的逻辑
    }
    
    public void updateUser(String username, String newPassword) {
        // 更新用户密码的逻辑
    }
    
    public void deleteUser(String username) {
        // 删除用户的逻辑
    }
    
    public void sendEmail(String username, String subject, String content) {
        // 发送邮件的逻辑
    }
    
}

在上述代码中,UserAPI 类违反了单一职责原则。它既包含了用户管理的功能(创建、获取、更新、删除用户),又包含了邮件发送的功能。这使得这个类承担了多个不同的职责,导致了耦合度增加、代码复杂度提高和可维护性下降的问题。

根据单一职责原则,应该将不同的职责拆分为独立的类或模块。

对于上述例子,可以将用户管理和邮件发送拆分为两个单独的类,分别负责各自的功能。这样可以提高代码的可读性、可维护性和扩展性。

public class UserManagementAPI {
    
    public void createUser(String username, String password) {
        // 创建用户的逻辑
    }
    
    public void getUserInfo(String username) {
        // 获取用户信息的逻辑
    }
    
    public void updateUser(String username, String newPassword) {
        // 更新用户密码的逻辑
    }
    
    public void deleteUser(String username) {
        // 删除用户的逻辑
    }
    
}

public class EmailService {
    
    public void sendEmail(String username, String subject, String content) {
        // 发送邮件的逻辑
    }
    
}

通过将功能进行拆分,每个类只关注一个特定的职责,代码变得更加清晰、可维护,并符合单一职责原则。

显式接口原则

以下是一个违反显式接口原则的反例,使用Java代码进行演示:

public class Calculator {
    
    public int calculate(int a, int b, String operation) {
        if (operation.equals("add")) {
            return a + b;
        } else if (operation.equals("subtract")) {
            return a - b;
        } else if (operation.equals("multiply")) {
            return a * b;
        } else if (operation.equals("divide")) {
            return a / b;
        }
        return 0;
    }
    
}

在上述代码中,Calculator 类违反了显式接口原则。它使用了一个字符串参数 operation 来决定进行何种计算操作。这种设计方式不明确和不清晰,没有明确定义接口和输入输出的结构,使用方在调用时无法准确理解和使用该接口。

根据显式接口原则,应该明确和清晰地定义接口,包括输入参数、输出结果和可能的错误码。以下是一个改进的示例:

public interface Calculator {
    
    int add(int a, int b);
    
    int subtract(int a, int b);
    
    int multiply(int a, int b);
    
    int divide(int a, int b);
    
}

通过定义明确的接口,使用方可以清晰地知道接口的输入和输出,而不需要传递一个字符串参数来确定操作类型。这样可以提高接口的可理解性和可维护性,遵循了显式接口原则。

public class SimpleCalculator implements Calculator {
    
    @Override
    public int add(int a, int b) {
        return a + b;
    }
    
    @Override
    public int subtract(int a, int b) {
        return a - b;
    }
    
    @Override
    public int multiply(int a, int b) {
        return a * b;
    }
    
    @Override
    public int divide(int a, int b) {
        return a / b;
    }
    
}

通过实现明确的接口,使用方可以根据接口定义来调用相应的方法,而无需传递一个字符串参数来指定操作。这样可以提高代码的可读性、可维护性和扩展性,并符合显式接口原则。

界限上下文

界限上下文原则(Bounded Context)的主要目标是将大型系统拆分为不同的上下文,每个上下文专注于一个特定的业务领域,并且在该上下文内保持一致性。以下是一个违反界限上下文原则的反例:

假设有一个电子商务系统,其中包含订单管理和库存管理两个领域。下面是一个违反界限上下文原则的实现示例:

public class OrderService {
    
    public void createOrder(Order order) {
        // 创建订单的逻辑
    }
    
    public void updateOrderStatus(Order order, String status) {
        // 更新订单状态的逻辑
    }
    
    public void reserveStock(Order order) {
        // 预留库存的逻辑
    }
    
    public void releaseStock(Order order) {
        // 释放库存的逻辑
    }
    
    public void updateStock(Order order) {
        // 更新库存的逻辑
    }
    
}

在上述代码中,OrderService 类同时包含了订单管理和库存管理的逻辑,违反了界限上下文原则。应该将这两个业务领域拆分为独立的上下文,分别负责各自的功能。

public class OrderService {
    
    public void createOrder(Order order) {
        // 创建订单的逻辑
    }
    
    public void updateOrderStatus(Order order, String status) {
        // 更新订单状态的逻辑
    }
    
}

public class InventoryService {
    
    public void reserveStock(Order order) {
        // 预留库存的逻辑
    }
    
    public void releaseStock(Order order) {
        // 释放库存的逻辑
    }
    
    public void updateStock(Order order) {
        // 更新库存的逻辑
    }
    
}

通过将订单管理和库存管理拆分为独立的服务,每个服务只关注自己领域的逻辑,代码变得更加清晰、可维护,并符合界限上下文原则。这样可以减少不同领域之间的耦合度,提高代码的模块化和可扩展性。

服务契约

服务契约(Service Contracts)旨在定义服务之间的明确契约,包括输入参数、输出结果和可能的错误码。

假设我们有一个用户管理服务,其中有一个方法用于更新用户信息。下面是一个违反服务契约原则的示例:

public class UserService {
    
    public void updateUser(String userId, String newEmail) {
        // 更新用户信息的逻辑
    }
    
}

在上述代码中,updateUser 方法只接受用户ID和新的电子邮件地址作为参数,但是它没有返回任何结果或处理任何错误情况。这违反了服务契约原则,因为它没有明确定义输入参数、输出结果和错误处理。

改进的做法是明确定义服务的契约,包括输入参数、输出结果和错误处理。以下是一个改进的示例:

public class UserService {
    
    public UpdateUserResponse updateUser(UpdateUserRequest request) {
        // 更新用户信息的逻辑
        // ...
        UpdateUserResponse response = new UpdateUserResponse();
        // 设置更新结果
        return response;
    }
    
}

public class UpdateUserRequest {
    private String userId;
    private String newEmail;
    // 其他相关属性和方法
    
    // Getters and setters
}

public class UpdateUserResponse {
    private boolean success;
    private String errorMessage;
    // 其他相关属性和方法
    
    // Getters and setters
}

通过引入UpdateUserRequest和UpdateUserResponse对象来明确定义输入参数和输出结果的结构,我们可以更好地遵循服务契约原则。使用方可以清楚地了解服务的输入参数类型、输出结果类型以及如何处理错误情况。这样可以提高代码的可读性、可维护性和扩展性,并确保服务之间的契约明确。

信息隐藏

信息隐藏原则(Information Hiding Principle)是面向对象设计中的一个原则,它强调将类的内部细节隐藏起来,只暴露必要的接口给外部使用。

以下是一个违反信息隐藏原则的反例:

public class BankAccount {
    
    public String accountNumber;
    public String accountHolder;
    public double balance;
    
    public void deposit(double amount) {
        balance += amount;
    }
    
    public void withdraw(double amount) {
        balance -= amount;
    }
    
    public void displayAccountInfo() {
        System.out.println("Account Number: " + accountNumber);
        System.out.println("Account Holder: " + accountHolder);
        System.out.println("Balance: " + balance);
    }
}

在上述代码中,BankAccount 类违反了信息隐藏原则。它将账户号码、账户持有人和余额都声明为公共的属性,可以被外部直接访问和修改。同时,displayAccountInfo 方法也直接打印账户信息到控制台。

改进的做法是将类的内部状态和实现细节封装起来,只提供必要的接口供外部访问和操作。以下是一个改进的示例:

public class BankAccount {
    
    private String accountNumber;
    private String accountHolder;
    private double balance;
    
    public BankAccount(String accountNumber, String accountHolder) {
        this.accountNumber = accountNumber;
        this.accountHolder = accountHolder;
        this.balance = 0;
    }
    
    public void deposit(double amount) {
        balance += amount;
    }
    
    public void withdraw(double amount) {
        balance -= amount;
    }
    
    public void displayAccountInfo() {
        System.out.println("Account Number: " + accountNumber);
        System.out.println("Account Holder: " + accountHolder);
        System.out.println("Balance: " + balance);
    }
}

在改进后的代码中,将账户的属性声明为私有,并提供了公共的方法来进行存款、取款和显示账户信息的操作。外部代码无法直接访问和修改账户的内部状态,只能通过提供的接口来与账户对象进行交互,保护了类的内部实现细节并提高了封装性。

无状态性

无状态性原则(Statelessness Principle)强调在设计中避免保存客户端的状态信息,每个请求应该是独立且自包含的。

以下是一个违反无状态性原则的反例:

public class ShoppingCart {
    
    private List<Item> items;
    private double totalPrice;
    
    public void addItem(Item item) {
        items.add(item);
        totalPrice += item.getPrice();
    }
    
    public void removeItem(Item item) {
        items.remove(item);
        totalPrice -= item.getPrice();
    }
    
    public double getTotalPrice() {
        return totalPrice;
    }
    
    // 其他方法
}

在上述代码中,ShoppingCart 类保存了客户端的状态信息,包括购物车中的商品列表和总价格。每次添加或移除商品时,都会更新购物车中的商品列表和总价格。这违反了无状态性原则,因为购物车的状态信息依赖于之前的操作,并且随着时间的推移会发生变化。

改进的做法是使购物车变得无状态,每个请求都是独立的。以下是一个改进的示例:

public class ShoppingCart {
    
    public double calculateTotalPrice(List<Item> items) {
        double totalPrice = 0;
        for (Item item : items) {
            totalPrice += item.getPrice();
        }
        return totalPrice;
    }
    
    // 其他方法
}

在改进后的代码中,我们将购物车改为一个无状态的类,不保存任何状态信息。相反,我们提供了一个 calculateTotalPrice 方法,接收商品列表作为参数,并根据传入的列表计算总价格。每次调用该方法时,都是独立的,不依赖于之前的操作,保持了无状态性。

这样设计可以更好地遵循无状态性原则,使每个请求都是独立的,无需保存客户端的状态信息,提高了可伸缩性和可靠性。

适应性与演进性

适应性与演进性原则(Adaptability and Evolvability Principle)强调系统的设计应具备适应变化和演进的能力,能够灵活应对新需求和技术的引入。

以下是一个违反适应性与演进性原则的反例:

public class PaymentService {
    
    public void processPayment(String paymentMethod, double amount) {
        if (paymentMethod.equals("creditCard")) {
            // 处理信用卡支付逻辑
            System.out.println("Processing credit card payment...");
        } else if (paymentMethod.equals("paypal")) {
            // 处理PayPal支付逻辑
            System.out.println("Processing PayPal payment...");
        } else if (paymentMethod.equals("applePay")) {
            // 处理Apple Pay支付逻辑
            System.out.println("Processing Apple Pay payment...");
        } else {
            throw new IllegalArgumentException("Unsupported payment method");
        }
    }
    
    // 其他方法
}

在上述代码中,PaymentService 类中的 processPayment 方法根据传入的支付方式进行相应的支付处理。这种实现方式违反了适应性与演进性原则,因为当引入新的支付方式时,需要修改 processPayment 方法的代码来添加新的逻辑分支。

改进的做法是通过接口和策略模式来实现支付方式的适应性和演进性。以下是一个改进的示例:

public interface PaymentMethod {
    void processPayment(double amount);
}

public class CreditCardPayment implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        // 处理信用卡支付逻辑
        System.out.println("Processing credit card payment...");
    }
}

public class PayPalPayment implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        // 处理PayPal支付逻辑
        System.out.println("Processing PayPal payment...");
    }
}

public class ApplePayPayment implements PaymentMethod {
    @Override
    public void processPayment(double amount) {
        // 处理Apple Pay支付逻辑
        System.out.println("Processing Apple Pay payment...");
    }
}

public class PaymentService {
    
    public void processPayment(PaymentMethod paymentMethod, double amount) {
        paymentMethod.processPayment(amount);
    }
    
    // 其他方法
}

在改进后的代码中,我们定义了一个 PaymentMethod 接口,并为每种支付方式实现了具体的实现类。

PaymentService 类的 processPayment 方法接收一个 PaymentMethod 对象作为参数,并调用相应的支付方式的 processPayment 方法进行支付处理。

通过接口和策略模式的使用,我们使得支付方式的添加和修改变得更加灵活和可扩展,符合适应性与演进性原则。

安全性和身份验证

安全性和身份验证原则(Security and Authentication Principle)强调在系统设计中应该考虑安全性需求,并采取适当的身份验证措施来保护系统和用户的安全。

以下是一个违反安全性和身份验证原则的反例:

public class UserController {
    
    public UserDTO getUser(String userId) {
        // 根据用户ID查询用户信息
        return userRepository.findUserById(userId);
    }
    
    public void updateUser(String userId, UserDTO updatedUser) {
        // 更新用户信息
        userRepository.updateUser(userId, updatedUser);
    }
    
    // 其他方法
}

在上述代码中,UserController 类提供了获取用户和更新用户信息的方法。然而,该实现没有进行任何身份验证或安全性检查,任何人只要知道用户ID就可以获取和更新用户信息。

改进的做法是引入身份验证和安全性措施来保护用户信息。以下是一个改进的示例:

public class UserController {
    
    private AuthenticationService authenticationService;
    private UserRepository userRepository;
    
    public UserDTO getUser(String userId, String authToken) {
        if (!authenticationService.isAuthenticated(authToken)) {
            throw new SecurityException("Unauthorized access");
        }
        // 根据用户ID查询用户信息
        return userRepository.findUserById(userId);
    }
    
    public void updateUser(String userId, UserDTO updatedUser, String authToken) {
        if (!authenticationService.isAuthenticated(authToken)) {
            throw new SecurityException("Unauthorized access");
        }
        // 更新用户信息
        userRepository.updateUser(userId, updatedUser);
    }
    
    // 其他方法
}

在改进后的代码中,我们引入了 AuthenticationService 来进行身份验证,并在获取用户和更新用户信息的方法中进行验证。

如果身份验证失败,将抛出一个安全异常,阻止未经授权的访问。

这样,用户信息的访问和修改将受到身份验证和安全性保护,符合安全性和身份验证原则。

最后

以上的8个基本原则,可以作为我们日常设计微服务API的指导,来帮助团队确保服务的一致性、可理解性、可维护性和可扩展性。

然而,具体的微服务的API设计,还应根据具体的项目的特定需求、团队的技术栈和业务场景做出适当的调整和决策。文章来源地址https://www.toymoban.com/news/detail-467206.html

到了这里,关于微服务之道:8个原则,打造高效的微服务体系的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Cloud Gateway:打造可扩展的微服务网关

    🎉欢迎来到架构设计专栏~Spring Cloud Gateway:打造可扩展的微服务网关 ☆* o(≧▽≦)o *☆嗨~我是IT·陈寒🍹 ✨博客主页:IT·陈寒的博客 🎈该系列文章专栏:架构设计 📜其他专栏:Java学习路线 Java面试技巧 Java实战项目 AIGC人工智能 数据结构学习 🍹文章作者技术和水平有限

    2024年02月08日
    浏览(33)
  • Go 语言体系下的微服务框架选型:Dubbo-go

    随着微服务技术的快速发展,其在各个领域都形成了一系列事实标准,在 Kubernetes 和容器技术加持下,云原生微服务已经成为了主流解决方案。而 Go 语言作为云原生领域最受欢迎的开发语言,正被越来越多的企业作为微服务开发的首选语言,其中比较流行的包括 Go-micro、Go

    2024年01月21日
    浏览(33)
  • Go 语言体系下的微服务框架选型: Dubbo-go

      一、Go 微服务体系发展与选型 随着微服务技术的快速发展,其在各个领域都形成了一系列事实标准,在 Kubernetes 和容器技术加持下,云原生微服务已经成为了主流解决方案。而 Go 语言作为云原生领域最受欢迎的开发语言,正被越来越多的企业作为微服务开发的首选语言,

    2023年04月10日
    浏览(31)
  • P2E游戏《西游降魔》站在元宇宙风口 打造高效、完整且可持续的GameFi2.0体系

    引言:当人类大步迈入元宇宙时代,链上P2E游戏《西游降魔》正与元宇宙生态相伴相生,带领人们开启Play to Earn的变革之旅。 区块链结合游戏组成新的 GameFi 赛道,在 2021 年迎来爆炸式增长。各大公链如:ETH、BSC、OKChain 等呈现出几何量级的数据,乘着热度迅速积累了众多资

    2023年04月08日
    浏览(31)
  • 某汽车金融企业:搭建SDLC安全体系,打造智慧金融服务样本

    某汽车金融企业是国内头部汽车金融公司,已经为超过数百万名客户提供专业的汽车金融服务。该公司通过近几年的数字化创新,在提升客户体验、提高管理效率、降低经营成本等方面已具备很强的服务能力,让客户获得更方便、更快捷、更灵活的金融服务。 发力线上汽车金

    2024年02月05日
    浏览(33)
  • Spring MVC实现RESTful API,打造高效便捷的Web服务

    REST(Representational State Transfer)是一种架构风格一种设计风格而非标准。它并不是新技术是用于Web服务端的一种设计风格。通过设计好的URI和HTTP方法可以实现对资源的操作。RESTful API是符合REST风格的API,具有良好的可读性、可扩展性、可维护性、可测试性和可移植性。 Sprin

    2024年02月05日
    浏览(33)
  • 浪潮信息G7服务器打造高效智慧算力,全新支持第五代英特尔®至强®可扩展处理器

    近日,浪潮信息多款G7服务器创新升级,全面支持英特尔最新发布的第五代至强®可扩展处理器并完成适配,通过系统架构、硬件、固件和散热等方面的创新设计,以及AI加速功能引入,G7服务器的通用计算性能提升23%,在客户工作负载中每瓦特性能提升超36%,尤其是在AI推理场

    2024年01月20日
    浏览(42)
  • 光芒绽放:妙用“GLAD原则”打造标准的数据可视化图表

    之前读过一本书《人类简史:从动物到上帝》。是 1976年出生的赫拉利写的,在2016年我读了中文版 。该书在2011年出版的希伯来文版,另外还被翻译为45种语言。里面有一句经典的话是这么说的。 这个也是坚定我走数据这条路的原因。大家可以去看看。 以下一些工具是比较常

    2024年02月21日
    浏览(23)
  • 探索泛型与数据结构:解锁高效编程之道

    在当今信息爆炸的时代,数据结构和算法成为了程序员必备的核心技能。而泛型作为Java语言中的一项强大特性,为数据结构和算法的实现提供了更高效、更安全的方式。本文将深入探讨泛型的概念、使用场景以及结合数据结构的应用,为您打开高效编程之道。 1.1 为什么使用

    2024年02月13日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包