【架构】如何借助Proxy代理,提升架构扩展性

本文探讨了如何通过使用Proxy代理来提高架构的扩展性,以解决分布式环境中数据存储位置的问题。介绍了在消费方和服务方的设计,以及如何利用Spring的BeanPostProcessor和ApplicationContextAware实现代理类的注入。文章还提到了Redis Cluster的分布式的hash slot策略,并讨论了客户端重定向带来的网络IO消耗,以及JedisCluster的解决方案。最后,文章鼓励读者深入学习并发、架构、微服务等相关技术。
摘要由CSDN通过智能技术生成

我们都知道HTTP协议本身是无状态的,前后两次请求没有直接关联。

但有些业务功能比较特殊,比如发起一次http请求创建一笔订单,前提要求用户先登录,为了解决这个问题,http协议header中引入了Cookie,存储上下文信息,传递登录状态。

同理,服务器也有状态之分,取决于服务器是否有存储数据,还是纯计算节点

图片

场景:

现在有这么一个业务场景,用户发出请求,指令随机打到了一台服务器,比如174.56.102.101,但根据索引条件,数据实际存储在 174.56.102.102 或者 174.56.102.103,此时174.56.102.101 需要将请求转发给真实的目标服务器,以便获取数据。

当然也有一定概率,174.56.102.101就是真实的数据存储服务器,此时只需要调用本地方法,直接获取数据即可。

思考:

那么问题来了,一个系统会提供很多功能函数,每个函数在执行时,都要先判断数据的真实存储位置,然后再发起远程网络请求,获取数据。这样编写存在大量的代码冗余。

有没有一种方式,只管调用对应的funcion函数,至于底层真实数据在哪里,由框架层来处理

我们想到了RPC框架,比如 Dubbo,对于开发者而言,调用一个远程服务跟调用本地方法一样,简单方便。

图片

如何来设计这个框架层

从大的角色划分来看,分为服务提供方和消费方,首先我们来看看消费方如何设计?

消费方

定义注解类 @RPCReference,作为Field字段的属性说明,如果有此标识说明注入的是一个代理类。

@Service
@Slf4j
public class ComputeService {

    @RPCReference
    private IResourceService iResourceService;
    
省略。。。。

 public Object method(param){
   // 正常方法调用
   iResourceService.m1();
 }

特别说明:

1、IResourceService 需要定义为接口类型

2、根据Spring的IOC注入机制,iResourceService指向的是一个代理类实例地址

那么这个代理类如何创建?

首先,定义一个增强类 ConsumerProxyFactory,实现InvocationHandler接口

@Slf4j
public class ConsumerProxyFactory implements InvocationHandler {

    /**
     * 复写InvocationHandler类提供的方法,业务类方法调用会触发执行invoke增强逻辑
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Class<?> clazz = proxy.getClass().getInterfaces()[0];
        if (method.getName().contains("toString")) {
            return Boolean.TRUE;
        }
        // 根据args参数做判断
        if (当前节点) {
            // 调用本地方法
            return invodeMethod(clazz, method, args);
        }
        // 否则走rpc远程调用

        // 构造请求体
        RPCRequest req = buildRpcReq(clazz, method, args);
        // 构造请求头
        Map<String, String> headerMap = buildHeaderMap( requestString);

        // 访问远程服务器的接口,查询结果
        String responseString = HttpClientUtil.postRequest(url, req, headerMap);

        // 本地ThreadLocal资源清理、释放

        // 反序列化,解析出Return对象
        return JSONObject.parseObject(responseString, method.getGenericReturnType());
    }

    /**
     * 执行当前节点的本地方法
     */
    private Object invodeMethod(Class<?> clazz, Method method, Object[] args) {
        try {
            // 根据Class模板查询Bean实例
            Object bean =ProviderConte
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值