首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >MyBatis缓存机制详解

MyBatis缓存机制详解

作者头像
全栈程序员站长
发布于 2022-08-26 01:31:38
发布于 2022-08-26 01:31:38
65700
代码可运行
举报
运行总次数:0
代码可运行

大家好,又见面了,我是你们的朋友全栈君。

MyBatis缓存机制详解

1. MyBatis缓存

1.1 MyBatis缓存概述

MyBatis作为目前最常用的ORM数据库访问持久层框架,其本身支持动态SQL存储映射等高级特性也非常优秀,通过Mapper文件采用动态代理模式使SQL与业务代码相解耦,日常开发中使用也非常广泛,本文主要讨论mybatis缓存功能,mybatis缓存本身设计初衷是为了解决同一会话相同查询的效率问题,单机环境下也确实起到了提高查询效率的作用,但是随着业务场景变化以及分布式微服务的出现,其弊端也渐渐显现出来,不同会话间操作数据,关联查询数据采用mybatis缓存时会存在出现脏数据的风险。

1.2 MyBatis一二级缓存区别

1.Mybatis一级缓存是SQLSession级别的,一级缓存的作用域是SQlSession;Mabits一级缓存默认是开启的。 在同一个SqlSession中,执行相同的SQL查询时;第一次会去查询数据库,并写在缓存中,第二次会直接从缓存中取。 在同一次会话中执行两次相同查询中间执行了更新操作的时候,缓存会被清空,第二次相同查询仍然会去查询数据库。

2.Mybatis二级缓存是Mapper级别的,二级缓存的作用域是全局的,多个SQlSession共享的,二级缓存的作用域更大;Mybatis二级缓存默认是没有开启的。 第一次调用mapper下的SQL去查询用户的信息,查询到的信息会存放在该mapper对应的二级缓存区域。 第二次调用namespace下的mapper映射文件中,相同的sql去查询用户信息,会去对应的二级缓存内取结果。

2. MyBatis一级缓存

2.1 MyBatis一级缓存概述

默认情况下,只启用了本地的会话缓存,也就是一级缓存,它仅仅对一个会话中的数据进行缓存。 mybatis一级缓存指的是在应用运行过程中,一次数据库会话中,执行多次相同的查询,会优先查询缓存中的数据,减少数据库查询次数,提高查询效率。 每个SqlSession中持有了Executor,每个Executor中有一个LocalCache。当用户发起查询时,MyBatis根据当前执行的语句生成MappedStatement,在Local Cache进行查询,如果缓存命中的话,直接返回结果给用户,如果缓存没有命中的话,查询数据库,结果写入Local Cache,最后返回结果给用户。

2.2 MyBatis一级缓存配置

mybatis一级缓存默认是开启的,可根据需要选择级别是session或这statement。开发者只需在MyBatis的配置文件中,添加如下语句,就可以使用一级缓存。共有两个选项,session或者statement,默认是session级别,即在一个MyBatis会话中执行的所有语句,都会共享这一个缓存。一种是statement级别,可以理解为缓存只对当前执行的这一个Statement有效。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<setting name="localCacheScope" value="SESSION"/>

2.3 MyBatis一级缓存原理分析

1.在初始化SqlSesion时,会使用Configuration类创建一个全新的Executor,作为DefaultSqlSession构造函数的参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    // newExecutor 尤其可以注意这里,如果二级缓存开关开启的话,是使用CahingExecutor装饰BaseExecutor的子类
    if (cacheEnabled) { 
   
      executor = new CachingExecutor(executor);                      
    }

2.SqlSession创建完毕后,根据Statment的不同类型,会进入SqlSession的不同方法中,如果是Select语句的话,最后会执行到SqlSession的selectList,代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) { 
   
      MappedStatement ms = configuration.getMappedStatement(statement);
      return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
}

3.SqlSession把具体的查询职责委托给了Executor。如果只开启了一级缓存的话,首先会进入BaseExecutor的query方法。代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException { 
   
    BoundSql boundSql = ms.getBoundSql(parameter);
    CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
    return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

4.在上述代码中,会先根据传入的参数生成CacheKey,进入该方法查看CacheKey是如何生成的,代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(rowBounds.getOffset());
cacheKey.update(rowBounds.getLimit());
cacheKey.update(boundSql.getSql());
//后面是update了sql中带的参数
cacheKey.update(value);

在上述的代码中,将MappedStatement的Id、SQL的offset、SQL的limit、SQL本身以及SQL中的参数传入了CacheKey这个类,最终构成CacheKey。以下是这个类的内部结构:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public CacheKey() { 
   
    this.hashcode = DEFAULT_HASHCODE;
    this.multiplier = DEFAULT_MULTIPLYER;
    this.count = 0;
    this.updateList = new ArrayList<Object>();
}

首先是成员变量和构造函数,有一个初始的hachcode和乘数,同时维护了一个内部的updatelist。在CacheKey的update方法中,会进行一个hashcode和checksum的计算,同时把传入的参数添加进updatelist中。如下代码所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void update(Object object) { 
   
    int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object); 
    count++;
    checksum += baseHashCode;
    baseHashCode *= count;
    hashcode = multiplier * hashcode + baseHashCode;
    
    updateList.add(object);
}

除去hashcode、checksum和count的比较外,只要updatelist中的元素一一对应相等,那么就可以认为是CacheKey相等。只要两条SQL的下列五个值相同,即可以认为是相同的SQL。 Statement Id + Offset + Limmit + Sql + Params

5.BaseExecutor的query方法继续往下走,代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) { 
   
    // 这个主要是处理存储过程用的。
    handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
    } else { 
   
    list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}

如果查不到的话,就从数据库查,在queryFromDatabase中,会对localcache进行写入。

在query方法执行的最后,会判断一级缓存级别是否是STATEMENT级别,如果是的话,就清空缓存,这也就是STATEMENT级别的一级缓存无法共享localCache的原因。代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { 
   
        clearLocalCache();
}

在源码分析的最后,我们确认一下,如果是insert/delete/update方法,缓存就会刷新的原因。 SqlSession的insert方法和delete方法,都会统一走update的流程,代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public int insert(String statement, Object parameter) { 
   
    return update(statement, parameter);
  }
   @Override
  public int delete(String statement) { 
   
    return update(statement, null);
}

update方法也是委托给了Executor执行。BaseExecutor的执行方法如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
@Override
public int update(MappedStatement ms, Object parameter) throws SQLException { 
   
    ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
    if (closed) { 
   
      throw new ExecutorException("Executor was closed.");
    }
    clearLocalCache();
    return doUpdate(ms, parameter);
}

每次执行update前都会清空localCache。

2.4 MyBatis一级缓存总结

1.MyBatis一级缓存的生命周期和SqlSession一致。 2.MyBatis一级缓存内部设计简单,只是一个没有容量限定的HashMap,在缓存的功能性上有所欠缺。 3.MyBatis的一级缓存最大范围是SqlSession内部,有多个SqlSession或者分布式的环境下,数据库写操作会引起脏数据,建议设定缓存级别为Statement。

3. MyBatis二级缓存

3.1 MyBatis二级缓存概述

在上文中提到的一级缓存中,其最大的共享范围就是一个SqlSession内部,如果多个SqlSession之间需要共享缓存,则需要使用到二级缓存。开启二级缓存后,会使用CachingExecutor装饰Executor,进入一级缓存的查询流程前,先在CachingExecutor进行二级缓存的查询,具体的工作流程如下所示。

3.2 MyBatis二级缓存配置

要正确的使用二级缓存,需完成如下配置的。 1.在MyBatis的配置文件中开启二级缓存。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<setting name="cacheEnabled" value="true"/>

2.在MyBatis的映射XML中配置cache或者 cache-ref 。 cache标签用于声明这个namespace使用二级缓存,并且可以自定义配置。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<cache/>   
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
type:cache使用的类型,默认是PerpetualCache,这在一级缓存中提到过。
eviction: 定义回收的策略,常见的有FIFOLRU。
flushInterval: 配置一定时间自动刷新缓存,单位是毫秒。
size: 最多缓存对象的个数。
readOnly: 是否只读,若配置可读写,则需要对应的实体类能够序列化。
blocking: 若缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。

3.cache-ref代表引用别的命名空间的Cache配置,两个命名空间的操作使用的是同一个Cache。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<cache-ref namespace="mapper.StudentMapper"/>

3.3 MyBatis二级缓存原理分析

源码分析从CachingExecutor的query方法展开,源代码走读过程中涉及到的知识点较多,不能一一详细讲解,读者朋友可以自行查询相关资料来学习。 CachingExecutor的query方法,首先会从MappedStatement中获得在配置初始化时赋予的Cache。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Cache cache = ms.getCache();

本质上是装饰器模式的使用,具体的装饰链是: SynchronizedCache -> LoggingCache -> SerializedCache -> LruCache -> PerpetualCache。

以下是具体这些Cache实现类的介绍,他们的组合为Cache赋予了不同的能力。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SynchronizedCache:同步Cache,实现比较简单,直接使用synchronized修饰方法。
LoggingCache:日志功能,装饰类,用于记录缓存的命中率,如果开启了DEBUG模式,则会输出命中率日志。
SerializedCache:序列化功能,将值序列化后存到缓存中。该功能用于缓存返回一份实例的Copy,用于保存线程安全。
LruCache:采用了Lru算法的Cache实现,移除最近最少使用的Key/Value。
PerpetualCache: 作为为最基础的缓存类,底层实现比较简单,直接使用了HashMap。

3.4 MyBatis二级缓存总结

1.MyBatis的二级缓存相对于一级缓存来说,实现了SqlSession之间缓存数据的共享,同时粒度更加的细,能够到namespace级别,通过Cache接口实现类不同的组合,对Cache的可控性也更强。 2.MyBatis在多表查询时,极大可能会出现脏数据,有设计上的缺陷,安全使用二级缓存的条件比较苛刻。 3.在分布式环境下,由于默认的MyBatis Cache实现都是基于本地的,分布式环境下必然会出现读取到脏数据,需要使用集中式缓存将MyBatis的Cache接口实现,有一定的开发成本,直接使用Redis、Memcached等分布式缓存可能成本更低,安全性也更高。

4. MyBatis缓存测试

测试案例地址:https://gitee.com/rjzhu/opencode/tree/master/mybatis-cache-demo

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/** * MyBatis缓存测试类 */
public class StudentMapperTest { 
   

    private SqlSessionFactory factory;

    /** * 初始化SqlSessionFactory */
    @Before
    public void setUp() throws Exception { 
   
        factory = new SqlSessionFactoryBuilder().build(Resources.getResourceAsReader("mybatis-config.xml"));
    }

    /** * 查看缓存配置是否生效 * <setting name="localCacheScope" value="SESSION"/> * <setting name="cacheEnabled" value="true"/> */
    @Test
    public void showDefaultCacheConfiguration() { 
   
        System.out.println("本地缓存范围: " + factory.getConfiguration().getLocalCacheScope());
        System.out.println("二级缓存是否被启用: " + factory.getConfiguration().isCacheEnabled());
    }

    /** * MyBatis缓存测试一 * 测试:同一个会话,相同查询连续查询三次 * 结果:第一次查询数据库,二三次查询从缓存读取 * 结论:同一个会话,多次相同查询,只有第一次查询数据库,其他都是缓存中获取,提高了查询效率 */
    @Test
    public void testLocalCache() { 
   
        SqlSession sqlSession = factory.openSession(true); // 自动提交事务
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //第一次查询数据库,二三次查询直接从缓存读取
        System.out.println("第一次查询:" + studentMapper.getStudentById(1));
        System.out.println("第二次查询:" + studentMapper.getStudentById(1));
        System.out.println("第三次查询:" + studentMapper.getStudentById(1));

        sqlSession.close();
    }

    /** * MyBatis缓存测试二 * 测试:同一个会话,先查询,再新增,再次重复第一次查询 * 结果:第一次与第二次查询都查询数据库,修改操作后执行的相同查询,查询了数据库,一级缓存失效。 * 结论:同一个会话执行更新操作后缓存失效,源码中会清空缓存 */
    @Test
    public void testLocalCacheClear() { 
   
        SqlSession sqlSession = factory.openSession(true); // 自动提交事务
        StudentMapper studentMapper = sqlSession.getMapper(StudentMapper.class);

        //第一次与第二次查询都查询数据库,修改操作后执行的相同查询,查询了数据库,一级缓存失效。
        System.out.println("第一次查询:" + studentMapper.getStudentById(1));
        System.out.println("增加了" + studentMapper.addStudent(StudentEntity.builder().name("明明").age(20).build()) + "个学生");
        System.out.println("第二次查询:" + studentMapper.getStudentById(1));

        sqlSession.close();
    }

    /** * MyBatis缓存测试三 * 测试:同时开启两个会话,会话一连续两次查询,会话二更新操作,会话一再次相同查询,会话二相同查询 * 结果:会话一第一次查询数据库,第二次查询缓存,会话二更新完成,会话一再次相同查询仍然查询缓存(读取脏数据),会话二查询数据库获取最新数据。 * 结论:缓存作用范围是一个会话当中,当其中有会话更新数据,其他会话会读取到脏数据 */
    @Test
    public void testLocalCacheScope() { 
   
        //开启两个SqlSession,在sqlSession1中查询数据,使一级缓存生效,在sqlSession2中更新数据库
        //验证一级缓存只在数据库会话内部共享。
        SqlSession sqlSession1 = factory.openSession(true); // 自动提交事务
        SqlSession sqlSession2 = factory.openSession(true); // 自动提交事务

        StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
        StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);

        System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
        System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
        System.out.println("studentMapper2更新了" + studentMapper2.updateStudentName("小岑", 1) + "个学生的数据");
        System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
        System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));
    }

    /** * MyBatis缓存测试四 * 测试:同时开启两个会话,两个会话执行相同的查询 * 结果:两次都是查询数据库 * 结论:缓存作用范围是一个会话当中,不同会话,即使是相同查询,只使用各自的缓存 */
    @Test
    public void testCacheWithoutCommitOrClose() { 
   
        SqlSession sqlSession1 = factory.openSession(true); // 自动提交事务
        SqlSession sqlSession2 = factory.openSession(true); // 自动提交事务

        StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
        StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);

        //两次都是从数据库读取,说明需要提交事务,第二次查询才能走缓存
        System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
        System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));

    }

    /** * MyBatis缓存测试四 * 测试:同时开启两个会话,两个会话执行相同的查询 * 结果:两次都是查询数据库 * 结论:缓存作用范围是一个会话当中,不同会话,即使是相同查询,只使用各自的缓存 */
    @Test
    public void testCacheWithCommitOrClose() { 
   
        SqlSession sqlSession1 = factory.openSession(true); // 自动提交事务
        SqlSession sqlSession2 = factory.openSession(true); // 自动提交事务

        StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
        StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);

        //第一次提交以后,第二次走缓存
        System.out.println("studentMapper读取数据: " + studentMapper.getStudentById(1));
        sqlSession1.close();
        System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));

    }

    /** * MyBatis缓存测试五 * 测试:同时开启三个会话,通过接口方式,会话一查询后提交事务,会话二执行相同查询,缓存查询,会话三更新提交事务,会话二查询缓存 * 结果:只有第一次查询数据库,其余都是查询缓存 * 结论:只有提交事务以后,后续相同查询才会查询缓存,否则查询数据库 */
    @Test
    public void testCacheWithUpdate() { 
   
        SqlSession sqlSession1 = factory.openSession(true); // 自动提交事务
        SqlSession sqlSession2 = factory.openSession(true); // 自动提交事务
        SqlSession sqlSession3 = factory.openSession(true); // 自动提交事务

        StudentMapper studentMapper = sqlSession1.getMapper(StudentMapper.class);
        StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
        StudentMapper studentMapper3 = sqlSession3.getMapper(StudentMapper.class);

        System.out.println("studentMapper1读取数据: " + studentMapper.getStudentById(1));
        sqlSession1.close();
        System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));

        studentMapper3.updateStudentName("方方", 1);
        sqlSession3.commit();
        System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentById(1));
    }

    /** * MyBatis缓存测试六 * 测试:测试关联查询,出现脏数据问题, * 结论:不同会话之间关联查询的时候,其中会话更新单独更新关联的其中一个表,另一个会话感知不到,在不同的mapper文件中,缓存查询会出现脏数据情况 */
    @Test
    public void testCacheWithDiffererntNamespace() { 
   
        // 设置自动提交事务
        SqlSession sqlSession1 = factory.openSession(true);
        SqlSession sqlSession2 = factory.openSession(true);
        SqlSession sqlSession3 = factory.openSession(true);

        StudentMapper studentMapper1 = sqlSession1.getMapper(StudentMapper.class);
        StudentMapper studentMapper2 = sqlSession2.getMapper(StudentMapper.class);
        ClassMapper classMapper3 = sqlSession3.getMapper(ClassMapper.class);

        System.out.println("studentMapper1读取数据: " + studentMapper1.getStudentByIdWithClassInfo(1));
        sqlSession1.close();

        System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentByIdWithClassInfo(1));

        //更新数据
        classMapper3.updateClassName("特色一班", 1);
        sqlSession3.commit();

        //读取到脏数据,studentMapper2读取数据: StudentEntity(id=1, name=方方, age=16, className=一班)
        System.out.println("studentMapper2读取数据: " + studentMapper2.getStudentByIdWithClassInfo(1));
    }

}

5. 参考文档

MyBatis中文网:https://mybatis.net.cn/index.html MyBatis英文网:https://mybatis.org/mybatis-3/index.html MyBatis执行流程源码分析:https://blog.csdn.net/m0_37583655/article/details/122115750 聊聊MyBatis缓存机制 mybatis一级缓存和二级缓存的区别是什么

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/143317.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年5月1,如有侵权请联系 cloudcommunity@tencent.com 删除

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

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

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Serverless 风格微服务的持续交付(上):架构案例
本文所介绍的 Serverless 架构主要是以 AWS Lambda 以及 Amazon API Gateway 架构的应用,它同时也具备 BaaS 的特征。
码农架构
2020/10/29
1.2K0
Serverless 风格微服务的持续交付(上):架构案例
Serverless 微服务持续交付案例
“Serverless 风格微服务的持续交付(上):架构案例”中,我们介绍了一个无服务器风格的微服务的架构案例。这个案例中混合了各种风格的微服务
顾宇
2018/08/17
1.7K0
无服务器化的微服务持续交付
前言 我在刚进入 ThoughtWorks 的时候就做微服务,当时不知道什么叫做微服务,只是我们通过一个小的技术应用替换原先的大应用的一个部分,当时只是做一个解耦,后来等微服务的概念兴起的时候才知道我们当时做的是微服务,这是我做微服务的起因。 最近在做 DevOps 的一些咨询,在海外做一些互联网行业的并购,用了 DevOps 的相关技术。这次我就讲一下我之前做的一个案例,就是无服务化的微服务的持续交付。 一 什么是无服务器架构 无服务器架构,这个词2012年就已经出现了,当时是因为移动互联网兴起。大家会发
DevOps时代
2018/02/02
1.8K0
无服务器化的微服务持续交付
(译)无服务器架构
无服务器运算,或者简单说无服务器,是软件架构界的一个新热点。三大云——亚马逊、谷歌以及微软都在无服务器方面下了重注,我们会看到很多的书籍、开源项目、会议以及软件供应商,都不约而同的关注这一主题。但是什么是无服务器?是否值得重视?为什么值得重视?本文中我希望能在这一问题方面给读者一些启迪。
崔秀龙
2019/07/23
3.7K0
(译)无服务器架构
Serverless架构:用服务代替服务器
还记得在十多年前,SaaS鼻祖SalesForce喊出的口号『No Software』吗?SalesForce在这个口号声中开创了SaaS行业,并成为当今市值520亿美元的SaaS之王。今天谈谈『No Server』有关的事, 继OpenStack、Docker 、MiscroService、Unikernel、Kubernetes和Mesos之后,ServerLess正成为Google、AWS乃至创业公司暗战的新战场,它能否成为云计算领域的颠覆性趋势? 我相信大家也会存在一些疑问: Serverless到
yuanyi928
2018/04/02
3.9K0
Serverless架构:用服务代替服务器
Chris Richardson微服务翻译:微服务部署
Chris Richardson 微服务系列翻译全7篇链接: 微服务介绍 构建微服务之使用API网关 构建微服务之微服务架构的进程通讯 微服务架构中的服务发现 微服务之事件驱动的数据管理 微服务部署(本文) 重构单体应用为微服务 原文链接:Choosing a Microservices Deployment Strategy ---- 动机 部署一个单体应用意味着运行着庞大应用的多个副本,通常需要 N 台服务器(物理机或虚拟机),在每台服务器上运行 M 个应用实例。部署单体应用一般并不特别直接,但还是比部
butterfly100
2018/04/17
1.2K0
Chris Richardson微服务翻译:微服务部署
Serverless:微服务架构的终极模式
微服务的生态和实践已经比较成熟,其设计方法、开发框架、CI/CD工具、基础设施管理工具等,都可以帮助企业顺利实施微服务。然而,微服务远没有达到完美,它在架构、开发、基础设施方面仍然面临新的挑战。
程序猿DD
2021/12/01
1.1K0
Serverless:微服务架构的终极模式
《前端Serverless:面向全栈的无服务架构实战》-- 1.Serverless综述(笔记)
IaaS:Infrastructure as a Service,基础设施即服务。
爱学习的程序媛
2022/10/27
9640
《前端Serverless:面向全栈的无服务架构实战》-- 1.Serverless综述(笔记)
Serverless|Framework——图文玩转 AWS Lambda
| 好看请赞,养成习惯 你有一个思想,我有一个思想,我们交换后,一个人就有两个思想 If you can NOT explain it simply, you do NOT understand i
用户4172423
2020/10/23
2.8K0
Serverless|Framework——图文玩转 AWS Lambda
小心 Serverless
技术具有商品属性,这是常常被我们忽略的一个事实。且不谈垄断之后带来的商业利益,一方面技术依赖市场的认可来彰显它的价值,另一方面技术还需要依靠大众的反馈才得以完善自己,所以庞大的用户群体是它繁荣的基石,它需要尽可能的为人所知。无论你是想吸引更多的项目和开发者加入某个社区中,还是想让某个框架摆脱默默无闻乃至脱颖而出,过程都务必依赖于大量的运营活动,其中不少也要倚靠背后大厂的资源投入。从近乎寿终正寝的 Silverlight 到近些年大火的 Flutter,无不遵循着类似的模式。
ThoughtWorks
2021/11/15
2.6K0
小心 Serverless
Serverless 时代,这才是Web应用开发正确的打开方式 | Q推荐
如同 iPhone 当年颠覆了诺基亚,Serverless 的出现也带来了一种全新的、颠覆式的云开发架构模式。在 Serverless 出现前,开发者们根本无法想象几分钟就能快速部署一个 Web 应用上线。近日,亚马逊云科技 Tech Talk 特别邀请了资深无服务器技术专家孙华带来分享《 如何高效、极简构造无服务器 Web 应用》。孙华以 Amazon Lambda 的视角介绍了无服务器 Web 应用的构造方式,并讲述了如何利用最新发布的 Lambda Function URLs 和 Lambda Adapter 进一步简化无服务器 Web 应用的开发和调试并且实现 Web 应用在 Lambda,Fargate 和 EC2 等计算平台之间平滑迁移。
深度学习与Python
2022/06/13
4.2K0
Serverless 时代,这才是Web应用开发正确的打开方式 | Q推荐
Serverless当打之年
当前大多数公司在运营应用产品时,无论是选择公有云还是自建的数据中心,都会面临服务器数量预估、存储容量规划和数据库的选型等问题。同时需要在基础设施之上部署依赖软件,以运行应用程序。当前是否存在一种简单的架构模型能够满足我们这种应用场景?当然,这个架构已经存在许久,它就是今天软件架构世界中很热门的一个话题——Serverless。
zouyee
2021/02/01
7120
Serverless当打之年
从技术雷达看​DevOps的十年——容器技术和微服务
在上一篇文章中,我们讲到了基础设施即代码和云计算给运维领域带来的深远影响。而 DevOps 运动不仅仅改变了运维端,同时也改变了开发端,特别是 Docker 的兴起和微服务架构的流行。在这一篇,我们将通过技术雷达上相关条目的变化来考察 Docker 和微服务的发展。
ThoughtWorks
2019/07/14
9100
为什么选择微服务架构? 微服务架构的10个核心优势 总结
微服务架构我们没有一个明确的定义,但简单来说微服务架构是: 采用一组服务的方式来构建一个应用,服务独立部署在不同的进程中,不同服务通过一些轻量级交互机制来通信,例如 RPC、HTTP 等,服务可独立扩展伸缩,每个服务定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。
猫头虎
2024/04/08
2.8K0
为什么选择微服务架构? 微服务架构的10个核心优势 总结
主流云平台介绍之-AWS
目前云平台逐渐火热起来,国内如:阿里云、腾讯云、华为云等平台,国外如:AWS、Azure、Google GCP等平台,都有不少用户,并在持续的增加中。
用户7353950
2022/05/11
3.7K0
主流云平台介绍之-AWS
什么是无服务器架构?
无服务器计算(Severless computing,简称 Serverless)现在是软件架构圈中的热门话题,国外三大云计算供应商(Amazon、Google 和 Microsoft)都在大力投入这个领域,涌现了不计其数的相关书籍、开源框架、商业产品、技术大会。到底什么是 Serverless?它有什么长处/短处?我希望通过本文对这些问题提供一些启发。
物流IT圈
2019/07/16
4.9K0
什么是无服务器架构?
从微服务转为单体架构、成本降低 90%,亚马逊内部案例引发轰动!CTO:莫慌,要持开放心态
编译 | 明知山、Tina Ruby on Rails 之父:“即使是亚马逊也无法理解无服务器或微服务。” 来自亚马逊 Prime Video 团队的一个案例研究在开发者社区中掀起了轩然大波。 在该案例中,Prime Video 团队将一个监控系统从微服务架构迁移到单体架构,并避免使用昂贵的服务(如 AWS Step Functions 和 Lambda 无服务器函数),并对此举所带来的降本效果进行了评估。 他们的需求是使用一个监控工具来识别“用户查看的视频流”的质量问题,因为有“成千上万个并发流”,
深度学习与Python
2023/05/09
1.3K0
从微服务转为单体架构、成本降低 90%,亚马逊内部案例引发轰动!CTO:莫慌,要持开放心态
应用技术架构 —— 无服务器架构
2012 年,iron.io 首次提出 Serverless 概念。2014 年,AWS 发布 Lambda 开启 Serverless 商业化时代,AWS Lambda,最早被大众所认可的 Serverless 实现。随后各大云厂商争相推出自己的 Serverless 服务、框架或工具。
腾讯云 CODING
2022/03/16
2.3K0
应用技术架构 —— 无服务器架构
成功微服务实施的技术演进微服务演进的技术背景通过度量驱动架构的微服务化
在上一篇文章《我们如何衡量一个微服务实施的成功》里,我们介绍了衡量一个微服务改造成功的七个特征,分别是:
顾宇
2018/12/26
6360
Serverless简介
Serverless的全称是Serverless computing无服务器运算,又被称为函数即服务(Function-as-a-Service,缩写为 FaaS),是云计算的一种模型。以平台即服务(PaaS)为基础,无服务器运算提供一个微型的架构,终端客户不需要部署、配置或管理服务器服务,代码运行所需要的服务器服务皆由云端平台来提供。 国内外比较出名的产品有Tencent Serverless、AWS Lambda、Microsoft Azure Functions 等。
xiangzhihong
2020/12/21
2.7K0
推荐阅读
相关推荐
Serverless 风格微服务的持续交付(上):架构案例
更多 >
交个朋友
加入腾讯云官网粉丝站
蹲全网底价单品 享第一手活动信息
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档