首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Spring系列第十六讲 Spring中的Java动态代理技术(下)

Spring系列第十六讲 Spring中的Java动态代理技术(下)

作者头像
易兮科技
发布于 2020-10-29 02:36:43
发布于 2020-10-29 02:36:43
1.7K00
代码可运行
举报
文章被收录于专栏:CSDN博客专栏CSDN博客专栏
运行总次数:0
代码可运行

什么是cglib

jdk动态代理只能为接口创建代理,使用上有局限性。实际的场景中我们的类不一定有接口,此时如果我们想为普通的类也实现代理功能,我们就需要用到cglib来实现了。

cglib是一个强大、高性能的字节码生成库,它用于在运行时扩展Java类和实现接口;本质上它是通过动态的生成一个子类去覆盖所要代理的类(非final修饰的类和方法)。Enhancer可能是CGLIB中最常用的一个类,和jdk中的Proxy不同的是,Enhancer既能够代理普通的class,也能够代理接口。Enhancer创建一个被代理对象的子类并且拦截所有的方法调用(包括从Object中继承的toString和hashCode方法)。Enhancer不能够拦截final方法,例如Object.getClass()方法,这是由于Java final方法语义决定的。基于同样的道理,Enhancer也不能对final类进行代理操作。

CGLIB作为一个开源项目,其代码托管在github,地址为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
https://github.com/cglib/cglib

cglib组成结构

CGLIB底层使用了ASM(一个短小精悍的字节码操作框架)来操作字节码生成新的类。除了CGLIB库外,脚本语言(如Groovy和BeanShell)也使用ASM生成字节码。ASM使用类似SAX的解析器来实现高性能。我们不鼓励直接使用ASM,因为它需要对Java字节码的格式足够的了解。

spring已将第三方cglib jar包中所有的类集成到spring自己的jar包中,本系列内容都是和spring相关的,为了方便,我们直接使用spring内部已集成的来讲解

5个案例来演示cglib常见的用法

案例1:拦截所有方法(MethodInterceptor)

创建一个具体的类,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.javacode2018.lesson001.demo17;

public class Service1 {
    public void m1() {
        System.out.println("我是m1方法");
    }

    public void m2() {
        System.out.println("我是m2方法");
    }
}

下面我们为这个类创建一个代理,代理中实现打印每个方法的调用日志。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.javacode2018.lesson001.demo17;

import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CglibTest {

    @Test
    public void test1() {
        //使用Enhancer来给某个类创建代理类,步骤
        //1.创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        //2.通过setSuperclass来设置父类型,即需要给哪个类创建代理类
        enhancer.setSuperclass(Service1.class);
        /*3.设置回调,需实现org.springframework.cglib.proxy.Callback接口,
        此处我们使用的是org.springframework.cglib.proxy.MethodInterceptor,也是一个接口,实现了Callback接口,
        当调用代理对象的任何方法的时候,都会被MethodInterceptor接口的invoke方法处理*/
        enhancer.setCallback(new MethodInterceptor() {
            /**
             * 代理对象方法拦截器
             * @param o 代理对象
             * @param method 被代理的类的方法,即Service1中的方法
             * @param objects 调用方法传递的参数
             * @param methodProxy 方法代理对象
             * @return
             * @throws Throwable
             */
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("调用方法:" + method);
                //可以调用MethodProxy的invokeSuper调用被代理类的方法
                Object result = methodProxy.invokeSuper(o, objects);
                return result;
            }
        });
        //4.获取代理对象,调用enhancer.create方法获取代理对象,这个方法返回的是Object类型的,所以需要强转一下
        Service1 proxy = (Service1) enhancer.create();
        //5.调用代理对象的方法
        proxy.m1();
        proxy.m2();
    }
}

上面代码中的注释很详细,列出了给指定的类创建代理的具体步骤,整个过程中主要用到了Enhancer类和MethodInterceptor接口。

enhancer.setSuperclass用来设置代理类的父类,即需要给哪个类创建代理类,此处是Service1

enhancer.setCallback传递的是MethodInterceptor接口类型的参数,MethodInterceptor接口有个intercept方法,这个方法会拦截代理对象所有的方法调用。

还有一个重点是Object result = methodProxy.invokeSuper(o, objects);可以调用被代理类,也就是Service1类中的具体的方法,从方法名称的意思可以看出是调用父类,实际对某个类创建代理,cglib底层通过修改字节码的方式为Service1类创建了一个子类。

运行输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
调用方法:public void com.javacode2018.lesson001.demo17.Service1.m1()
我是m1方法
调用方法:public void com.javacode2018.lesson001.demo17.Service1.m2()
我是m2方法

从输出中可以看出Service1中的2个方法都被MethodInterceptor中的invoke拦截处理了。

案例2:拦截所有方法(MethodInterceptor)

在创建一个类,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.javacode2018.lesson001.demo17;


public class Service2 {
    public void m1() {
        System.out.println("我是m1方法");
        this.m2(); //@1
    }

    public void m2() {
        System.out.println("我是m2方法");
    }
}

这个类和上面的Service1类似,有点不同是@1,在m1方法中调用了m2方法。

下面来采用案例1中同样的方式来给Service2创建代理,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test2() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Service2.class);
    enhancer.setCallback(new MethodInterceptor() {
        @Override
        public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("调用方法:" + method);
            Object result = methodProxy.invokeSuper(o, objects);
            return result;
        }
    });
    Service2 proxy = (Service2) enhancer.create();
    proxy.m1(); //@1
}

注意上面@1的代码,只调用了m1方法,看一下输出效果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
调用方法:public void com.javacode2018.lesson001.demo17.Service2.m1()
我是m1方法
调用方法:public void com.javacode2018.lesson001.demo17.Service2.m2()
我是m2方法

从输出中可以看出m1和m2方法都被拦截器处理了,而m2方法是在Service1的m1方法中调用的,也被拦截处理了。

spring中的@configuration注解就是采用这种方式实现的,给大家上个@configuration案例眼熟一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.javacode2018.lesson001.demo17;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Config {

    @Bean
    public C1 c1(){
        return new C1();
    }
    @Bean
    public C2 c2(){
        C1 c1 = this.c1(); //@1
        return new C2(c1);
    }
    @Bean
    public C3 c3(){
        C1 c1 = this.c1(); //@2
        return new C3(c1);
    }

    public static class C1{}

    public static class C2{
        private C1 c1;

        public C2(C1 c1) {
            this.c1 = c1;
        }
    }
    public static class C3{
        private C1 c1;

        public C3(C1 c1) {
            this.c1 = c1;
        }
    }

}

上面代码中C2和C3依赖于C1,都是通过构造器注入C1,注意代码中的@1和@2都是调用c1方法获取容器中的C1,如何确保多次获取的C1都是一个的?这个地方就是使用cglib代理拦截@Bean注解的方法来实现的。

案例3:拦截所有方法并返回固定值(FixedValue)

当调用某个类的任何方法的时候,都希望返回一个固定的值,此时可以使用FixedValue接口,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
enhancer.setCallback(new FixedValue() {
            @Override
            public Object loadObject() throws Exception {
                return "路人甲";
            }
        });

上面创建的代理对象,调用其任意方法返回的都是"路人甲"。

案例代码如下:

创建一个类Service3,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.javacode2018.lesson001.demo17;

public class Service3 {
    public String m1() {
        System.out.println("我是m1方法");
        return "hello:m1";
    }

    public String m2() {
        System.out.println("我是m2方法");
        return "hello:m2";
    }
}

对用的测试用例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test3() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Service3.class);
    enhancer.setCallback(new FixedValue() {
        @Override
        public Object loadObject() throws Exception {
            return "路人甲";
        }
    });
    Service3 proxy = (Service3) enhancer.create();
    System.out.println(proxy.m1());//@1
    System.out.println(proxy.m2()); //@2
    System.out.println(proxy.toString());//@3
}

@1、@2、@3调用了代理对象的3个方法,运行输出:

运行输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
路人甲
路人甲
路人甲

可以看出输出的都是一个拱顶的值。

案例4:直接放行,不做任何操作(NoOp.INSTANCE)

Callback接口下面有个子接口org.springframework.cglib.proxy.NoOp,将这个作为Callback的时候,被调用的方法会直接放行,像没有任何代理一样,感受一下效果:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test6() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Service3.class);
    enhancer.setCallback(NoOp.INSTANCE);
    Service3 proxy = (Service3) enhancer.create();
    System.out.println(proxy.m1());
    System.out.println(proxy.m2());
}

运行输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
我是m1方法
hello:m1
我是m2方法
hello:m2

从输出中可以看出,被调用的方法没有被代理做任何处理,直接进到目标类Service3的方法中了。

案例5:不同的方法使用不同的拦截器(CallbackFilter)

有个类如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.javacode2018.lesson001.demo17;

public class Service4 {
    public void insert1() {
        System.out.println("我是insert1");
    }

    public void insert2() {
        System.out.println("我是insert2");
    }

    public String get1() {
        System.out.println("我是get1");
        return "get1";
    }

    public String get2() {
        System.out.println("我是get2");
        return "get2";
    }
}

需求,给这个类创建一个代理需要实现下面的功能:

  1. 以insert开头的方法需要统计方法耗时
  2. 以get开头的的方法直接返回固定字符串欢迎和【易兮科技】一起学spring!

下来看代码,然后再解释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test4() {
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(Service4.class);
    //创建2个Callback
    Callback[] callbacks = {
            //这个用来拦截所有insert开头的方法
            new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    long starTime = System.nanoTime();
                    Object result = methodProxy.invokeSuper(o, objects);
                    long endTime = System.nanoTime();
                    System.out.println(method + ",耗时(纳秒):" + (endTime - starTime));
                    return result;
                }
            },
            //下面这个用来拦截所有get开头的方法,返回固定值的
            new FixedValue() {
                @Override
                public Object loadObject() throws Exception {
                    return "易兮科技";
                }
            }
    };
    enhancer.setCallbackFilter(new CallbackFilter() {
        @Override
        public int accept(Method method) {
            return 0;
        }
    });
    //调用enhancer的setCallbacks传递Callback数组
    enhancer.setCallbacks(callbacks);
    /**
     * 设置过滤器CallbackFilter
     * CallbackFilter用来判断调用方法的时候使用callbacks数组中的哪个Callback来处理当前方法
     * 返回的是callbacks数组的下标
     */
    enhancer.setCallbackFilter(new CallbackFilter() {
        @Override
        public int accept(Method method) {
            //获取当前调用的方法的名称
            String methodName = method.getName();
            /**
             * 方法名称以insert开头,
             * 返回callbacks中的第1个Callback对象来处理当前方法,
             * 否则使用第二个Callback处理被调用的方法
             */
            return methodName.startsWith("insert") ? 0 : 1;
        }
    });
    Service4 proxy = (Service4) enhancer.create();
    System.out.println("---------------");
    proxy.insert1();
    System.out.println("---------------");
    proxy.insert2();
    System.out.println("---------------");
    System.out.println(proxy.get1());
    System.out.println("---------------");
    System.out.println(proxy.get2());

}

运行输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
---------------
我是insert1
public void com.javacode2018.lesson001.demo17.Service4.insert1(),耗时(纳秒):15396100
---------------
我是insert2
public void com.javacode2018.lesson001.demo17.Service4.insert2(),耗时(纳秒):66200
---------------
易兮科技
---------------
易兮科技

代码说明:

由于需求中要对不同的方法做不同的处理,所以需要有2个Callback对象,当调用代理对象的方法的时候,具体会走哪个Callback呢,此时会通过CallbackFilter中的accept来判断,这个方法返回callbacks数组的索引。

上面这个案例还有一种简单的实现,见案例6

案例6:对案例5的优化(CallbackHelper)

cglib中有个CallbackHelper类,可以对案例5的代码进行有环,CallbackHelper类相当于对一些代码进行了封装,方便实现案例5的需求,实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test5() {
    Enhancer enhancer = new Enhancer();
    //创建2个Callback
    Callback costTimeCallback = (MethodInterceptor) (Object o, Method method, Object[] objects, MethodProxy methodProxy) -> {
        long starTime = System.nanoTime();
        Object result = methodProxy.invokeSuper(o, objects);
        long endTime = System.nanoTime();
        System.out.println(method + ",耗时(纳秒):" + (endTime - starTime));
        return result;
    };
    //下面这个用来拦截所有get开头的方法,返回固定值的
    Callback fixdValueCallback = (FixedValue) () -> "路人甲Java";
    CallbackHelper callbackHelper = new CallbackHelper(Service4.class, null) {
        @Override
        protected Object getCallback(Method method) {
            return method.getName().startsWith("insert") ? costTimeCallback : fixdValueCallback;
        }
    };
    enhancer.setSuperclass(Service4.class);
    //调用enhancer的setCallbacks传递Callback数组
    enhancer.setCallbacks(callbackHelper.getCallbacks());
    /**
     * 设置CallbackFilter,用来判断某个方法具体走哪个Callback
     */
    enhancer.setCallbackFilter(callbackHelper);
    Service4 proxy = (Service4) enhancer.create();
    System.out.println("---------------");
    proxy.insert1();
    System.out.println("---------------");
    proxy.insert2();
    System.out.println("---------------");
    System.out.println(proxy.get1());
    System.out.println("---------------");
    System.out.println(proxy.get2());

}

运行输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
---------------
我是insert1
public void com.javacode2018.lesson001.demo17.Service4.insert1(),耗时(纳秒):9777500
---------------
我是insert2
public void com.javacode2018.lesson001.demo17.Service4.insert2(),耗时(纳秒):50600
---------------
路人甲Java
---------------
路人甲Java

输出效果和案例4一模一样的,上面重点在于CallbackHelper,里面做了一些封装,有兴趣的可以去看一下源码,比较简单。

案例6:实现通用的统计任意类方法耗时代理类

直接上代码,比较简单,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.javacode2018.lesson001.demo17;


import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class CostTimeProxy implements MethodInterceptor {
    //目标对象
    private Object target;

    public CostTimeProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        long starTime = System.nanoTime();
        //调用被代理对象(即target)的方法,获取结果
        Object result = method.invoke(target, objects); //@1
        long endTime = System.nanoTime();
        System.out.println(method + ",耗时(纳秒):" + (endTime - starTime));
        return result;
    }

    /**
     * 创建任意类的代理对象
     *
     * @param target
     * @param <T>
     * @return
     */
    public static <T> T createProxy(T target) {
        CostTimeProxy costTimeProxy = new CostTimeProxy(target);
        Enhancer enhancer = new Enhancer();
        enhancer.setCallback(costTimeProxy);
        enhancer.setSuperclass(target.getClass());
        return (T) enhancer.create();
    }
}

我们可以直接使用上面的静态方法createProxy来为目标对象target创建一个代理对象,被代理的对象自动实现方法调用耗时统计。

@1:调用被代理对象的方法获取真正的结果。

使用非常简单,来个测试用例,如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Test
public void test7() {
    //创建Service1代理
    Service1 service1 = CostTimeProxy.createProxy(new Service1());
    service1.m1();

    //创建Service3代理
    Service3 service3 = CostTimeProxy.createProxy(new Service3());
    System.out.println(service3.m1());
}

运行输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
我是m1方法
public void com.javacode2018.lesson001.demo17.Service1.m1(),耗时(纳秒)53200
我是m1方法
public java.lang.String com.javacode2018.lesson001.demo17.Service3.m1(),耗时(纳秒)49200
hello:m1

CGLIB和Java动态代理的区别

  1. Java动态代理只能够对接口进行代理,不能对普通的类进行代理(因为所有生成的代理类的父类为Proxy,Java类继承机制不允许多重继承);CGLIB能够代理普通类;
  2. Java动态代理使用Java原生的反射API进行操作,在生成类上比较高效;CGLIB使用ASM框架直接对字节码进行操作,在类的执行过程中比较高效
  3. 代理的就介绍到这里,spring中很多地方会用到这块,所以大家一定要熟悉,欢迎大家留言交流
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/10/25 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
大厂都在用的MySQL主从复制、读写分离及高可用方案
随着数据量的增大,读写并发的增加,系统可用性要求的提升,单机 MySQL 出现危机:
JavaEdge
2021/02/20
8.9K0
MySQL高可用方案MHA的一些总结和思考
MySQL高可用方案中MHA绝地是一个相当成熟的实现。对于数据的切换,其实MGR也能很好的完成,也就是说,数据层面的角色切换已经刻意很平滑的做好了,但是对于访问IP的处理,还是有很大的空间,MHA提供了很多可选的空间来支持。 常见的组合方式有: MHA+VIP MHA+keepalive MHA+Zookeeper 当然MHA+VIP是一种很成熟和经典的方案了。 一般来说都有以下类似的架构方式,假设架构模式为一主两从。对于应用访问来说,提供的IP信息就依据绑定的VIP地址为准。VIP
jeanron100
2018/03/21
1.5K0
MySQL高可用方案MHA的一些总结和思考
一文搞懂MySQL主从复制方案、读写分离及高可用
随着数据量的增大,读写并发的增加,系统可用性要求的提升,单机 MySQL 出现危机:
JavaEdge
2021/02/03
1.4K0
一文搞懂MySQL主从复制方案、读写分离及高可用
MySQL高可用架构探秘:主从复制剖析、切换策略、延迟优化与架构选型
在分布式系统中,单机节点在发生故障时无法提供服务,这可能导致长期的服务不可用,从而影响其他节点的运作,导致的后果非常严重
菜菜的后端私房菜
2024/06/28
6540
【云顾问最佳实践】CLB高可用设计:如何化解负载均衡宕机引发的服务雪崩?
腾讯云负载均衡(CLB)作为云上架构的"交通枢纽",通过智能分发流量保障业务连续性。其秒级弹性伸缩、跨可用区容灾、四层/七层协议全支持等特性,使其成为电商、金融等行业应对高并发流量的核心组件。在典型三层架构中,CLB如同数字世界的红绿灯系统,协调着前端请求与后端服务的精准对接。
Georgezzz
2025/04/25
2150
【云顾问最佳实践】CLB高可用设计:如何化解负载均衡宕机引发的服务雪崩?
给系统打针高可用疫苗,鹅的数据库就是稳!
如今是数据驱动时代,数据库作为企业的核心资产之一,其安全性和稳定性显得尤为重要。然而,面对复杂多变的业务场景和不断演变的技术挑战,如何把握现有数据库架构可承受故障的故障级别、发生故障后的高可用性方案是否有效,成为了许多数据库用户关注的焦点,也是腾讯云MySQL在服务众多重保用户时思考的问题。
腾讯云数据库 TencentDB
2023/10/20
4730
给系统打针高可用疫苗,鹅的数据库就是稳!
MySQL主从如何保证高可用
通过主备同步我们能够保证数据的可靠性(最终一致性),MySQL的主备可用性主要依赖于主备切换的时间,越短越好,但前提是切换完成以后数据要一致。
shysh95
2022/04/07
5480
MySQL主从如何保证高可用
【云顾问-混沌】Redis故障演练-主从切换
随着企业对数据处理和存储需求的不断增长,Redis作为一款高性能的内存数据结构存储系统,已成为业界的首选。然而,在Redis中的使用中,会面对一些潜在的故障风险,其中主节点故障,发生主从切换最为常见。
冷淡然
2023/12/19
8650
爱奇艺 MySQL 高可用方案到底有多牛?
爱奇艺每天都为数以亿计的用户提供7x24小时不间断的视频服务。通过爱奇艺的平台,用户可以方便的获取海量、优质、高清的视频资源。但如果服务平台出现故障,会有大量的用户将无法正常播放视频,因此我们的应用服务以及数据库服务都必须具备高可用架构。
开发者技术前线
2020/11/23
1.1K0
爱奇艺 MySQL 高可用方案到底有多牛?
数据库高可用架构了解一下
数据存储高可用的方案本质都是通过将数据复制到多个存储设备,通过数据冗余的方式来实现高可用。常见的高可用架构有主备、主从、主从切换、主主等接下来我们聊聊每种架构的优缺点。
JAVA日知录
2019/11/19
1K0
数据库高可用架构了解一下
【云顾问-混沌演练】阅文游戏:新游上线混沌演练实践
阅文集团是一家以数字阅读为基础,IP培育与开发为核心的综合性文化产业集团。集团汇聚了强大的创作者阵营、丰富的作品储备,覆盖200多种内容品类,触达数亿用户,已成功输出《斗罗大陆》《斗破苍穹》《鬼吹灯》《盗墓笔记》《琅琊榜》《庆余年》等网文IP改编的动漫、影视、游戏等多业态产品。
怡然自得
2024/05/29
5520
【云顾问-混沌演练】阅文游戏:新游上线混沌演练实践
MySQL高可用架构
“高可用”是互联网一个永恒的话题,先避开MySQL不谈,为了保证各种服务的高可用有几种常用的解决方案。
一行舟
2022/08/25
1.5K0
MySQL高可用架构
【架构设计复习】高可用,高扩展实现方案
通过心跳检测并实施主备切换(比如redis的哨兵模式或者集群模式、MySQL的主从切换等)。
韩旭051
2021/04/14
1.1K0
【云顾问最佳实践】电商大促期间CVM性能波动如何破?揭秘高可用架构的混沌验证之道
作为腾讯云弹性计算的核心产品,云服务器CVM承载着电商平台的核心业务负载。在典型的三层电商架构中:
Georgezzz
2025/04/25
2240
【云顾问最佳实践】电商大促期间CVM性能波动如何破?揭秘高可用架构的混沌验证之道
【云顾问-混沌演练】欢乐互娱:新游上线混沌演练实践
欢乐互娱(上海)科技股份有限公司(以下简称“欢乐互娱”),是一家全球游戏研发和发行公司,聚焦于MMORPG和MMOACT两大品类,成功出品了众多知名游戏如《街机三国》、《龙之谷》和《英雄杀》等。2023年4月,欢乐互娱重磅新游大作《RO仙境传说》计划在东南亚发行,该项目开服规模大、影响用户范围广,做好游戏上线前的容灾准备以保障上线后的稳定性至关重要。
四方.
2023/09/13
1K0
【云顾问-混沌演练】欢乐互娱:新游上线混沌演练实践
企业云上网络服务规划全面指南:基于腾讯云产品的架构设计与实践
在数字化转型浪潮中,企业上云已成为提升业务敏捷性和竞争力的关键举措。然而,云上网络服务的规划与设计直接关系到企业业务的安全性、可用性和扩展性。本文将基于腾讯云产品体系,从网络架构设计原则、核心产品选型、安全防护策略、性能优化方法到运维管理实践,为企业提供一套完整的云上网络服务规划方案。通过深入分析腾讯云的网络基础设施、安全加速能力以及混合云解决方案,帮助企业构建高性能、高可用的云网络环境,同时实现成本优化与合规管理,为业务创新提供坚实的网络基础。
徐关山
2025/06/27
4370
【云顾问-混沌演练】乐元素 x 腾讯云混沌演练平台:游戏业务同城双活改造最佳实践
乐元素是国内休闲益智游戏领域领航企业。为了给用户提供更稳定可靠的使用体验,在2023年Q2开始,乐元素运维、业务团队联合腾讯云售后专家和技术专家,基于针对乐元素旗下休闲游戏产品《开心消消乐》展开同城双活改造项目,目的是了解并改善业务容灾部署状况,进一步强化云上业务系统的容灾能力。
ainsley@tencentcloud
2024/01/29
7690
【云顾问-混沌演练】精细演练,稳定云端——腾讯云助阵金蝶云,守护小微业务稳定高可用
为了给客户提供更优质、更可靠的服务,金蝶业务团队从2022年开始,就已经在腾讯云售后专家的协助下,陆续对业务系统完成双活改造。改造完成后,业务团队通过腾讯云混沌演练平台进行故障注入,以检验业务系统的容灾效果,从而提升业务系统韧性。本次演练主要针对金蝶小微业务线(精斗云&KIS云),涉及10大业务故障场景,是财务、新零售、电商等领域行业提高系统可用性的一次最佳实践。
Isainsley
2024/02/02
5080
【云顾问-混沌演练】精细演练,稳定云端——腾讯云助阵金蝶云,守护小微业务稳定高可用
云数据库MySql故障切换下的应用重连配置最佳实践
云数据库 MySQL 支持单节点、双节点、三节点、集群版等架构,配合多可用区部署,可为用户业务提供高可用性支持,保证用户可以快速恢复数据库操作而无需管理干预,如出现可用区中断、主数据库实例故障(主实例因负载过高 hang 住、硬件故障等),数据库可以自动处理故障转移(实例切换),即主数据库实例(节点)会自动切换到备可用区的备用副本。日常的数据库运维过程中,数据库实例规格调整、数据库引擎版本升级等操作,也会可能涉及到实例切换。
云顾问-为您服务
2024/05/03
1.5K0
mysql高可用架构设计,处理高并发,大流量!
主要介绍:复制功能介绍、mysql二进制日志、mysql复制拓扑、高可用框架、单点故障、读写分离和负载均衡介绍等 mysql复制功能介绍 mysql复制功能提供分担读负载 复制解决的问题 实现在不同服务器上的数据分布 利用二进制日志增量进行 不需要太多的带宽 但是使用基于行的复制在进行大批量的更改时会对带宽带来一定得压力,特别是跨IDC环境下进行复制 实现在不同服务器上的数据分布 实现数据读取的负载均衡 需要其他组件配合完成 利用DNS轮询的方式把程序的读连接到不同的备份数据库, 使用LVS,haproxy
思梦php
2018/03/09
2.6K0
mysql高可用架构设计,处理高并发,大流量!
推荐阅读
相关推荐
大厂都在用的MySQL主从复制、读写分离及高可用方案
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档