前言:我认为你们在了解了整个微服务架构之后,需要能够明白,微服务架构重点在于架构二字,这个内容搞清楚了,其实任何的架构,任何的手段都是一个工具,如何去利用这些工具解决一些问题才是最重要的。
架构的本质:用最简单的手段解决复杂的问题。
系统整理是复杂的没错,然而80%(数字只是一个比喻,表示大多数)的用户和80%的场景都是简单的,架构的目的就是首先保证80%的简单性问题能够得到真正简单的处理,然后再构建复杂的专家级的应用去处理真正复杂的事情。
系统复杂度增加的原因:
很多架构/系统一开始是简单的,这一点都没错,因为他们开始只处理简单问题,只处理几个点,这是正确的。随着系统的不断升级迭代,他们开始把复杂的事情往简单里入侵,于是系统边界开始变得模糊不清,最后崩塌。
我们到底要如何降低系统的复杂度呢?本质思想如上所述,需要加入外力的干预,最好是强力的干预。而这个外力我认为就是架构设计思想和架构解耦工具
我认为分层几乎是系统设计中最重要的思想,可以参考计算机网络协议和计算机缓存设计等。
三层架构
四层架构 职责单一化
良好的领域拆分需要依赖系统设计人员对系统应用场景的深刻理解。且具备很好的抽象能力。
同拆分一样,找到同类的功能进行聚合,也是需要对场景的理解,且需要不断优化和尝试。
A +B = C
系统拆分与聚合清晰后,需要独立模块有高度自治的能力。对外定义控制输入和输出协议,对内实现独立且明确的能力。
系统链路一定要简化,尤其系统核心链路。简单意味着好理解、易维护、稳定性强、容易扩展。
用户-商品-订单- 库存- 支付 冗余到一起
DDD领域驱动
import java.util.ArrayList;
import java.util.List;
public class Event {
private String type;
public Event(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
public interface EventHandler {
public void handleEvent(Event event);
}
public class EventDispatcher {
private List<EventHandler> handlers;
public EventDispatcher() {
handlers = new ArrayList<EventHandler>();
}
public void addHandler(EventHandler handler) {
handlers.add(handler);
}
public void dispatchEvent(Event event) {
for (EventHandler handler : handlers) {
if (handler != null) {
handler.handleEvent(event);
}
}
}
}
在这个事件驱动的代码中,我们有一个Event类来表示事件,并具有一个类型属性。我们还有一个EventHandler接口,用于处理事件。最后,我们有一个EventDispatcher类,用于添加处理程序并分派事件。
可以创建不同类型的事件,并创建实现EventHandler接口的处理程序来处理这些事件。然后,可以将处理程序添加到EventDispatcher中以便可以启动事件处理。
例如,我们可以创建一个名为“ButtonClickEvent”的事件,并创建一个名为“ButtonClickEventHandler”的处理程序来处理该事件。然后,可以将该处理程序添加到EventDispatcher中,以便在单击按钮时启动事件处理。
public class ButtonClickEvent extends Event {
public ButtonClickEvent() {
super("ButtonClickEvent");
}
}
public class ButtonClickEventHandler implements EventHandler {
public void handleEvent(Event event) {
if (event.getType().equals("ButtonClickEvent")) {
// 执行单击按钮时要执行的操作
System.out.println("Button clicked");
}
}
}
public static void main(String[] args) {
// 创建一个事件分派器
EventDispatcher eventDispatcher = new EventDispatcher();
// 创建一个按钮单击事件
ButtonClickEvent buttonClickEvent = new ButtonClickEvent();
// 创建一个处理程序来处理按钮单击事件
EventHandler buttonClickEventHandler = new ButtonClickEventHandler();
// 将处理程序添加到事件分派器
eventDispatcher.addHandler(buttonClickEventHandler);
// 分派按钮单击事件
eventDispatcher.dispatchEvent(buttonClickEvent);
}
在这个示例中,我们创建了一个名为“ButtonClickEvent”的事件,并创建一个名为“ButtonClickEventHandler”的处理程序来处理它。然后,我们创建了一个事件分派器,并添加了该处理程序。最后,我们分派按钮单击事件,该事件将触发执行单击按钮时要执行的操作。
可以根据需要添加更多的事件和处理程序,并根据事件类型执行不同的操作。
在电商场景中,责任链模式可以用于处理订单退款申请。下面是一个简单的电商场景的责任链Java代码实现:
public abstract class RefundHandler {
private RefundHandler nextHandler;
public void setNextHandler(RefundHandler handler) {
this.nextHandler = handler;
}
public void handleRefundRequest(Order order, RefundRequest request) {
if (canHandle(request)) {
handle(order, request);
} else if (nextHandler != null) {
nextHandler.handleRefundRequest(order, request);
} else {
System.out.println("没有处理该退款请求的处理程序");
}
}
protected abstract boolean canHandle(RefundRequest request);
protected abstract void handle(Order order, RefundRequest request);
}
public class CustomerServiceHandler extends RefundHandler {
@Override
protected boolean canHandle(RefundRequest request) {
return request.getType() == RefundType.CUSTOMER_SERVICE;
}
@Override
protected void handle(Order order, RefundRequest request) {
// 联系客服处理退款申请
System.out.println("联系客服处理退款申请");
}
}
public class FinanceHandler extends RefundHandler {
@Override
protected boolean canHandle(RefundRequest request) {
return request.getType() == RefundType.FINANCE;
}
@Override
protected void handle(Order order, RefundRequest request) {
// 财务部门处理退款申请
System.out.println("财务部门处理退款申请");
}
}
public class LogisticsHandler extends RefundHandler {
@Override
protected boolean canHandle(RefundRequest request) {
return request.getType() == RefundType.LOGISTICS;
}
@Override
protected void handle(Order order, RefundRequest request) {
// 物流部门处理退款申请
System.out.println("物流部门处理退款申请");
}
}
在这个责任链的实现中,我们定义了一个抽象的RefundHandler类,它有一个指向下一个处理程序的引用,还有一个处理退款申请的抽象方法handle。如果当前处理程序无法处理退款申请,则将退款请求转发给下一个处理程序。
我们还定义了三个具体的处理程序CustomerServiceHandler、FinanceHandler和LogisticsHandler,它们分别处理不同类型的退款请求。如果一个处理程序可以处理退款请求,则处理该请求并结束责任链。否则,将该请求传递给下一个处理程序。
我们可以将这些处理程序按照责任链的顺序连接起来:
RefundHandler logisticsHandler = new LogisticsHandler();
RefundHandler financeHandler = new FinanceHandler();
RefundHandler customerServiceHandler = new CustomerServiceHandler();
logisticsHandler.setNextHandler(financeHandler);
financeHandler.setNextHandler(customerServiceHandler);
然后,当收到一个退款请求时,我们将它传递给责任链的第一个处理程序:
Order order = getOrder();
RefundRequest request = getRefundRequest();
logisticsHandler.handleRefundRequest(order, request);
如果第一个处理程序无法处理该请求,则将其传递给下一个处理程序。如果所有处理程序都无法处理该请求,则在最后提供默认响应。
System.out.println("没有处理该退款请求的处理程序");
规则引擎可以帮助你将逻辑和数据解耦,数据放入领域模型中,逻辑放入规则中
电商领域的规则引擎可以用来处理价格计算、促销活动、优惠券使用等复杂的业务逻辑。以下是一个电商领域的规则引擎的简单示例代码:
假设我们需要计算某个商品的价格,考虑到会有多种不同的优惠策略,如会员折扣、新用户优惠、满减等,这时我们可以使用规则引擎来实现灵活的计价方案。
首先我们定义一个Rule类,用来表示一个规则:
public abstract class Rule<T> {
private String ruleName;
private int priority;
public abstract boolean evaluate(T obj);
public abstract BigDecimal calculate(T obj);
public void setPriority(int priority) {
this.priority = priority;
}
public int getPriority() {
return priority;
}
public String getRuleName() {
return ruleName;
}
public void setRuleName(String ruleName) {
this.ruleName = ruleName;
}
}
在这里,我们定义了两个抽象方法 evaluate
和 calculate
,分别用来评估当前规则是否适用于给定的对象(如某个订单)以及如何计算折扣后的价格等。
接下来,我们定义一个RuleEngine类,用来实现规则的执行逻辑:
public class RuleEngine<T> {
private List<Rule<T>> rules;
public RuleEngine() {
rules = new ArrayList<>();
}
public void addRule(Rule<T> rule) {
rules.add(rule);
}
public BigDecimal execute(T obj) {
rules.sort(Comparator.comparingInt(Rule::getPriority));
BigDecimal price = BigDecimal.ZERO;
for (Rule<T> rule : rules) {
if (rule.evaluate(obj)) {
price = rule.calculate(obj);
}
}
return price;
}
}
在这里,我们定义了一个 addRule
方法和一个 execute
方法。其中 addRule
用来添加规则,而 execute
方法则用来执行规则引擎的逻辑。在 execute
方法中,我们首先对规则按照优先级进行排序,然后依次运行每一个规则。如果当前规则适用于给定的对象,则执行该规则的计算方法,累加价格并返回。
最后,我们可以使用具体的规则来实现价格计算:
public class MemberDiscountRule extends Rule<Order> {
// ...
@Override
public boolean evaluate(Order obj) {
return obj.getUser().isMember();
}
@Override
public BigDecimal calculate(Order obj) {
return obj.getTotalPrice().multiply(new BigDecimal("0.9")); // 9折优惠
}
}
public class NewUserDiscountRule extends Rule<Order> {
// ...
@Override
public boolean evaluate(Order obj) {
return obj.getUser().isNewUser();
}
@Override
public BigDecimal calculate(Order obj) {
return obj.getTotalPrice().subtract(new BigDecimal("5")); // 新用户减5元
}
}
public class Over100DiscountRule extends Rule<Order> {
// ...
@Override
public boolean evaluate(Order obj) {
return obj.getTotalPrice().compareTo(new BigDecimal("100")) >= 0;
}
@Override
public BigDecimal calculate(Order obj) {
return obj.getTotalPrice().subtract(new BigDecimal("10")); // 满100减10元
}
}
在这里,我们实现了会员折扣、新用户优惠和满减等三个规则。通过 evaluate
方法判断当前规则是否适用于给定的订单,通过 calculate
计算满足当前规则后的价格。我们可以通过如下方式来应用这些规则:
RuleEngine<Order> engine = new RuleEngine<>();
engine.addRule(new MemberDiscountRule());
engine.addRule(new NewUserDiscountRule());
engine.addRule(new Over100DiscountRule());
Order order = new Order();
// 初始化订单信息,如商品列表、会员信息等
BigDecimal finalPrice = engine.execute(order);
当然,市面上也有一些开源的规则引擎,这个更好用一些,比如drools这种
public enum State {
STATE_ONE,
STATE_TWO,
STATE_THREE
}
public class StateMachine {
private State state;
public StateMachine() {
state = State.STATE_ONE;
}
public void processInput(String input) {
switch (state) {
case STATE_ONE:
if (input.equals("A")) {
state = State.STATE_TWO;
}
break;
case STATE_TWO:
if (input.equals("B")) {
state = State.STATE_THREE;
} else {
state = State.STATE_ONE;
};
break;
case STATE_THREE:
if (input.equals("C")) {
state = State.STATE_ONE;
}
break;
default:
break;
}
}
}
在这个状态机中,我们有三个状态: STATE_ONE,STATE_TWO和STATE_THREE。在构造函数中,我们将初始状态设置为STATE_ONE。
processInput方法接受输入,并根据当前状态进行转换。在每个状态中,我们检查输入并根据需要更新状态。
例如,如果我们处于STATE_ONE状态,并且输入是“A”,我们将转换到STATE_TWO状态。如果我们处于STATE_TWO状态并且输入是“B”,我们将转换到STATE_THREE状态。如果我们处于STATE_TWO状态但输入不是“B”,我们将返回到STATE_ONE状态。在STATE_THREE状态中,如果输入是“C”,我们将返回到STATE_ONE状态。否则,我们将保持在STATE_THREE状态中。
可以根据需要修改此状态机,例如,添加更多状态或更改状态之间的转换条件。
以下是一个电商中的DDD代码案例:
假设我们正在开发一个电商网站的下单功能,我们需要识别用户是否有足够的库存、确认订单信息是否正确、扣除相应金额、生成订单等等。我们可以先定义一个 Order
实体类表示订单,在这个实体类中定义一些重要属性和方法:
public class Order {
private String orderId;
private User user;
private List<Item> items;
private BigDecimal totalPrice;
private OrderStatus status;
public void createOrder() {
//生成订单的具体实现逻辑
}
public void confirmOrder() {
//确认订单的具体实现逻辑
}
//getter和setter方法
}
在这里,Order
类是我们的聚合根(Aggregate Root),其他所有相关的实体(如 User
和 Item
)都是 Order
的子对象。我们可以通过调用 createOrder
方法来生成订单,同时该方法中可以调用其他相关实体的方法。例如,检查库存、计算订单总价、生成订单号等等。当确认订单之后,我们可以调用 confirmOrder
方法来将订单状态改为已确认、扣除相应的金额、生成订单等。
除此之外,我们还可以定义一个 OrderRepository
接口来处理订单的持久化操作:
public interface OrderRepository {
void save(Order order);
void delete(Order order);
List<Order> findByUserId(String userId);
Order findByOrderId(String orderId);
}
在这里,我们通过定义接口来实现订单的数据存储和检索。这个接口可以被不同类型的实例去实现,例如内存数据库、关系数据库、NoSQL数据库等等。对于某些特殊情况(如并发冲突、分布式环境下的多线程冲突等),我们可以通过引入领域事件(Domain Event)来处理这些问题,进一步增强我们的代码的稳定性和可扩展性。
容器编排 流程拆分 限界上下文、
在微服务架构中,服务划分可以基于多种因素,例如业务功能、数据域、可扩展性、可维护性等。以下是一些常用的划分方法:
在面试时,应该清楚地解释您所选择的划分方法,并说明其优缺点以及在什么情况下该方法适用。此外,您应该能够描述如何将这些服务组合成一个完整的应用程序,并讨论在不同服务之间通信的方式。最后,您可能需要讨论一些与微服务相关的挑战,例如服务发现、服务治理、数据一致性等,并说明您如何解决这些挑战
网络传输时间+逻辑运行时间(缓存+消息引擎)+数据库连接时间+数据库的查询时间
DNS的解析+通过网关的时间 +网络传输时间+逻辑运行时间(缓存+消息引擎)+数据库连接时间+数据库的查询时间
在微服务架构下,网关的效率问题往往受到以下几个方面的影响:
综上所述,网关效率问题需要从多个方面进行考虑和优化,避免某个环节出现性能瓶颈导致整个网关性能下降。在实际应用中,可以使用性能测试工具对网关进行测试评估,发现性能瓶颈并及时进行优化。
互联网项目中,接口性能指标可以从不同的角度进行考虑,以下是一些常用的指标:
综上所述,接口性能指标有很多,需要根据具体业务场景来选择和权衡。在实际项目中,可以使用一些专业的性能测试工具,如JMeter、Gatling等来进行性能测试,并根据测试结果进行适当的调整和优化。
在微服务架构下,判别接口性能的标准一般可以从以下几个方面进行评估:
在实际的性能测试中,除了以上几个方面,还可以根据具体业务需求进行评估。同时,在进行性能测试时,需要考虑到并发场景、请求量、负载均衡、缓存等因素对服务性能的影响,综合评估服务的性能表现。