分布式事务
分布式一致性在分布式系统中,为了保证数据的高可用,通常,我们会将数据保留多个副本(replica),这些副本会放置在不同的物理的机器上。为了对用户提供正确的 CRUD 等语义,我们需要保证这些放置在不同物理机器上的副本是一致的。
为了解决这种分布式一致性问题,前人在性能和数据一致性的反反复复权衡过程中总结了许多典型的协议和算法。其中比较著名的有二阶提交协议(Two Phase Commitment Protocol)、三阶提交协议(Three Phase Commitment Protocol) 和 Paxos 算法。
分布式事务
分布式事务是指会涉及到操作多个数据库的事务。其实就是将对同一库事务的概念扩大到了对多个库的事务。目的是为了保证分布式系统中的数据一致性。分布式事务处理的关键是必须有一种方法可以知道事务在任何地方所做的所有动作,提交或回滚事务的决定必须产生统一的结果(全部提交或全部回滚)
在分布式系统中,各个节点之间在物理上相互独立,通过网络进行沟通和协调。由于存在事务机制,可以保证每个独立节点上的数据操作可以满足 ACID。但是,相互独立的节点之间无法准确的知道其他节点中 ...
分布式锁的场景与实现
使用场景首先,我们看这样一个场景:客户下单的时候,我们调用库存中心进行减库存,那我们一般的操作都是:
update store set num = $num where id = $id
这种通过设置库存的修改方式,我们知道在并发量高的时候会存在数据库的丢失更新,比如 a, b 当前两个事务,查询出来的库存都是 5,a 买了 3 个单子要把库存设置为 2,而 b 买了 1 个单子要把库存设置为 4,那这个时候就会出现 a 会覆盖 b 的更新,所以我们更多的都是会加个条件:
update store set num = $num where id = $id and num = $query_num
即乐观锁的方式来处理,当然也可以通过版本号来处理乐观锁,都是一样的,但是这是更新一个表,如果我们牵扯到多个表呢,我们希望和这个单子关联的所有的表同一时间只能被一个线程来处理更新,多个线程按照不同的顺序去更新同一个单子关联的不同数据,出现死锁的概率比较大。对于非敏感的数据,我们也没有必要去都加乐观锁处理,我们的服务都是多机器部署的,要保证多进程多线程同时只能有一个进程的一个线程去处理,这个 ...
Session 分布式方案
基于 nfs(net filesystem) 的 Session 共享将共享服务器目录 mount 各服务器的本地 session 目录,session 读写受共享服务器 io 限制,不能满足高并发。
基于关系数据库的 Session 共享这种方案普遍使用。使用关系数据库存储 session 数据,对于 mysql 数据库,建议使用 heap 引擎。这种方案性能取决于数据库的性能,在高并发下容易造成表锁(虽然可以采用行锁的存储引擎,性能会下降),并且需要自己实现 session 过期淘汰机制。
基于 Cookie 的 Session 共享这种方案也在大型互联网中普遍使用,将用户的 session 加密序列化后以 cookie 的方式保存在网站根域名下(比如 taobao.com),当用户访问所有二级域名站点式,浏览器会传递所有匹配的根域名的 cookie 信息,这样实现了用户 cookie 化 session 的多服务共享。此方案能够节省大量服务器资源,缺点是存储的信息长度受到 http 协议限制;cookie 的信息还需要做加密解密;请求任何资源时都会将 cookie 附加到 htt ...
谈谈业务中使用分布式的场景
首先,需要了解系统为什么使用分布式。
随着互联网的发展,传统单工程项目的很多性能瓶颈越发凸显,性能瓶颈可以有几个方面:
应用服务层:随着用户量的增加,并发量增加,单项目难以承受如此大的并发请求导致的性能瓶颈。
底层数据库层:随着业务的发展,数据库压力越来越大,导致的性能瓶颈。
场景1:应用系统集群的 Session 共享应用系统集群最简单的就是服务器集群,比如:Tomcat 集群。应用系统集群的时候,比较凸显的问题是 Session 共享,Session 共享我们一是可以通过服务器插件来解决。另外一种也可以通过 Redis 等中间件实现。
场景2:应用系统的服务化拆分服务化拆分,是目前非常火热的一种方式。现在都在提微服务。通过对传统项目进行服务化拆分,达到服务独立解耦,单服务又可以横向扩容。服务化拆分遇到的经典问题就是分布式事务问题。目前,比较常用的分布式事务解决方案有几种:消息最终一致性、TCC 补偿型事务等。
场景3:底层数据库的压力分摊如果系统的性能压力出现在数据库,那我们就可以读写分离、分库分表等方案进行解决。
Spring 框架中用到了哪些设计模式
代理模式:在 AOP 和 Remoting 中被用的比较多。
单例模式:在 Spring 配置文件中定义的 Bean 默认为单例模式。
模板方法:用来解决代码重复的问题。比如. RestTemplate, JmsTemplate, JpaTemplate。
前端控制器:Spring 提供了 DispatcherServlet 来对请求进行分发。
视图帮助(View Helper ):Spring 提供了一系列的 JSP 标签,高效宏来辅助将分散的代码整合在视图里。
依赖注入:贯穿于 BeanFactory / ApplicationContext 接口的核心理念。
工厂模式:BeanFactory 用来创建对象的实例。
Spring 的单例实现原理
Spring 对 Bean 实例的创建是采用单例注册表的方式进行实现的,而这个注册表的缓存是 ConcurrentHashMap 对象。
Spring MVC 启动流程
在 web.xml 文件中给 Spring MVC 的 Servlet 配置了 load-on-startup,所以程序启动的时候会初始化 Spring MVC,在 HttpServletBean 中将配置的 contextConfigLocation 属性设置到 Servlet 中,然后在 FrameworkServlet 中创建了 WebApplicationContext,DispatcherServlet 根据 contextConfigLocation 配置的 classpath 下的 xml 文件初始化了 Spring MVC 总的组件。
Spring MVC 运行流程
Spring MVC 将所有的请求都提交给 DispatcherServlet,它会委托应用系统的其他模块负责对请求进行真正的处理工作。
DispatcherServlet 查询一个或多个 HandlerMapping,找到处理请求的 Controller.
DispatcherServlet 请求提交到目标 Controller
Controller 进行业务逻辑处理后,会返回一个 ModelAndView
Dispatcher 查询一个或多个 ViewResolver 视图解析器,找到 ModelAndView 对象指定的视图对象
视图对象负责渲染返回给客户端。
Spring 事务底层原理
划分处理单元 IOC由于 Spring 解决的问题是对单个数据库进行局部事务处理的,具体的实现首相用 Spring 中的 IOC 划分了事务处理单元。并且将对事务的各种配置放到了 IOC 容器中(设置事务管理器,设置事务的传播特性及隔离机制)。
AOP 拦截需要进行事务处理的类Spring 事务处理模块是通过 AOP 功能来实现声明式事务处理的,具体操作(比如事务实行的配置和读取,事务对象的抽象),用 TransactionProxyFactoryBean 接口来使用 AOP 功能,生成 proxy 代理对象,通过 TransactionInterceptor 完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。读取 IOC 容器事务配置属性,转化为 Spring 事务处理需要的内部数据结构(TransactionAttributeSourceAdvisor),转化为 TransactionAttribute 表示的数据对象。
对事物处理实现(事务的生成、提交、回滚、挂起)Spring 委托给具体的事务处理器实现。实现了一个抽象和适配。适配的具体事务处理器:DataSource ...