lagou 爪哇 2-2 分布式集群架构场景化解决⽅案 笔记

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
RDS MySQL DuckDB 分析主实例,基础系列 4核8GB
简介: 第⼀部分:⼀致性Hash算法第⼆部分:集群时钟同步问题第三部分:分布式ID解决⽅案

第⼀部分:⼀致性Hash算法


image.png


第⼆部分:集群时钟同步问题



第三部分:分布式ID解决⽅案



数据表A(ID),A的数据量很⼤的情况下,我们会进⾏分表操作,A(ID)表拆分成了A1表


(ID)+A2表(ID),需要⼀种在分布式集群架构中能够产⽣全局唯⼀ID的⽅案


第四部分:分布式调度问题(定时任务的分布式)



1.下列对定时任务描述正确的是()


您的回答: A可以实现异步处理B可以实现应用解耦:C可以实现流量削峰


2.以下属于服务器端定时任务主要实现方式的是()


您的回答: A JDK中的Timer机制 c线程机制 D Quartz任务调度框架


3.分布式调度体现的两层主要含义是()


您的回答: B任务的多实例高可用机制: D任务的拆分机制(任务分片),并行执行


4.下列属于轻量级体现的是()


您的回答: A使用简便,不需安装过多过重的其他服务或者组件B使用一个框架的时候,只把其Jar包引入调用即可ic开发


完成后不需要独立部署


5.下列属于ElasticJob无中心化体现的是()


您的回答: A执行节点对等!C服务自发现


第五部分:Session共享(⼀致性)问题



浏览器—>Nginx—>Tomcat1(Session中记录⽤户信息)


分布式和集群


分布式和集群是不⼀样的,分布式⼀定是集群,但是集群不⼀定是分布式(因为集群就是多个实例⼀起⼯作,分布式将⼀个系统拆分之后那就是多个实例;集群并不⼀定是分布式,因为复制型的集群不是拆分⽽是复制)


作业



作业一:


1)基于SpringBoot整合SSS(Spring+SpringMVC+SpringDataJPA)框架(即整合第一阶段模块三作业第二题内容,含有登录拦截验证)


2)在 1 的基础上开发SpringSession进行Session一致性控制


3)将工程打成war包


4)将war包部署到分布式集群架构中,要求一个Nginx节点,两个Tomcat节点

—> Nginx(轮询策略) —> Tomcat1—> Tomcat2


5)完成测试


思路和原理:


请求通过 tomcat到达 servlet容器的时候,通过过滤器对请求做了一次封装,如果没有过滤器, servet就会从 tomcat中获取 Session


有了过滤器之后,取出来的 Session就是 Redis 中的 Session,有的话就从 Redis中获取,没有的话就创建并提交到 Redis中去


  1. 使用数据库 test, 执行以下 sql 脚本, 创建了 tb_resume 表, 以及一些初始数据.

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for tb_resume
-- ----------------------------
DROP TABLE IF EXISTS `tb_resume`;
CREATE TABLE `tb_resume` (
 `id` bigint(20) NOT NULL AUTO_INCREMENT,
 `address` varchar(20) DEFAULT NULL,
 `name` varchar(20) DEFAULT NULL,
 `phone` varchar(20) DEFAULT NULL,
 PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
-- ----------------------------
-- Records of tb_resume
-- ----------------------------
BEGIN;
INSERT INTO `tb_resume` VALUES (1, '北京', '张三', '131000000'), (2, '上海', '李四', '151000000'), (3, '⼴州', '王五', '153000000'), (4, '深圳', '小不点', '157000000'), (5, '九江', '大王八', '158000000'), (6, '衡阳', '绿豆汤', '159000000'), (7, '永州', '凉拌粉', '188000000'), (8, '南昌', '南昌拌粉', '18812345566');
COMMIT;
SET FOREIGN_KEY_CHECKS = 1;


  1. 配置 nginx 反向代理

upstream myProxy {
            server 127.0.0.1:8080;
            server 127.0.0.1:8081;
    }
    server {
        listen       80;
        server_name  localhost;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        #location / {
        #    root   html;
        #    index  index.html index.htm;
       # }
        location / {
            proxy_pass   http://myProxy;
            proxy_set_header Host $host;
        }
        location /favicon.ico {          
        }


  1. 修改 conf/server.xml, 配置两个 tomcat。
    8080的保持默认, 8081的修改一下两个端口.

<Server port="8006" shutdown="SHUTDOWN">
...
<Connector port="8081" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />


  1. 配置 redis


yum install redis -y, 并修改配置文件  /etc/redis.conf,重启 redis 服务

redis.conf 修改说明


  1. bind 127.0.0.1 ::1 绑定的主机地址这一行注释掉 或者将127.0.0.1改为0.0.0.0。


  1. protected-mode 要设置成no (默认为yes的, 防止了远程访问,在redis3.2.3版本后)


  1. 按需设置密码


  1. 开启守护进程 daemonize no redis默认是yes ,以守护进程的方式. 所以无需修改.
    若在 docker run命令里边有一个参数 -d 这个参数也是以守护进程执行。则需要打开配置文件把守护进程修改为 no

# bind 127.0.0.1
protected-mode no
requirepass 12345
daemonize yes


  1. 将模块 1-3 的作业转换为 spring boot 项目


以下分别从代码 和 配置文件 进行阐述.


代码讲解


配置拦截器从 xml 改为 java 代码中配置

package com.lagou.edu.sss.interceptor;
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
    @Autowired
    private MyInterceptor myInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/user/**")
                .excludePathPatterns("/page/login.htm");
    }
}


在这里新建了 ServletInitializer 类. 因为若打包成war包,则需要继承 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer 类,覆盖其configure(SpringApplicationBuilder)方法


package com.lagou.edu.sss;
public class ServletInitializer extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(SssApplication.class);
    }
}


Application 上加入 @EnableCaching 和 @EnableRedisHttpSession 注解.

@SpringBootApplication
@EnableCaching
@EnableRedisHttpSession
public class SssApplication {
    public static void main(String[] args) {
        SpringApplication.run(SssApplication.class, args);
    }
}


文件配置讲解


修改 WEB-INF 下的 web.xml 信息


因为打包成war的话,如果打包之后的文件中没有web.xml文件的话自己可以加进去一个最简单的web.xml(只有根节点的定义,而没有子元素),防止因缺乏web.xml文件而部署失败

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
  <display-name>作业2</display-name>
</web-app>


application 配置文件配置

spring.http.encoding.force=true
# jsp 支持
spring.mvc.view.suffix=.jsp
spring.mvc.view.prefix=/WEB-INF/jsp/
# 关闭默认模板引擎
spring.thymeleaf.cache=false
spring.thymeleaf.enabled=false
# mysql 配置
spring.datasource.url=jdbc:mysql:///test?characterEncoding=utf-8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456
# redis 配置
spring.redis.database=0
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.timeout=5000
spring.redis.password=


建立 webapp 和 page子文件夹,从原项目中拷贝edit.jsp, list.jsp, login.jsp.


image.png

pom 文件中引入 jsp 相关支持 和 session支持

<!-- servlet 依赖. -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <scope>provided</scope>
        </dependency>
        <!--jstl-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
        </dependency>
        <!-- tomcat 的支持.-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>
        <!--引入springBoot 内嵌的Tomcat对JSP的解析包-->
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-jasper</artifactId>
            <scope>provided</scope>
        </dependency>
        <!-- session 支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.session</groupId>
            <artifactId>spring-session-data-redis</artifactId>
        </dependency>


  1. 通过spring-boot:run 先自行验证功能是否一切正常


  1. 打 war 包,  最好在每次 mvn pacakge 前 clear一下, 打好包后重点查看 classes下是否类文件为空, 否则部署会确认内容. 最终重命名为 sss.war. 然后分别发送到对应的 webapp 目录下。部署好以后等待片刻即可访问。


外网版演示地址


http://117.50.94.8/sss/page/list.htm


这次的主要坑点:


  • docker 下启动nginx, 但是配置反代理后, 两台tomcat 报502, 最后索性还是 yum 安装 nginx 靠谱. 自己用低配版的1G 版云服务器, 启动两个tomcat 和 一个redis,  一个 mysql8. 最后 docker 强制把我的mysql 销毁了,  感觉是不是扛不住压力, 所以最终docker 下只跑一个 mysql.  然后把 redis 容器, 两 tomcat 容器先停止, 然后直接部署在云服务器上. 最终结果部署花了很多时间.


  • 部署war包访问 controller 一直访问 404, 竟然发现 classes 下没有类文件. 所以以后打好 war 包以后一定要检查内容是否确认


  • 一定要有java 类继承 org.springframework.boot.web.servlet.support.SpringBootServletInitializer 类,覆盖其configure(SpringApplicationBuilder)方法, 否则 tomcat 的日志不走.


  • 程序查看 tomcat 日志是否有异常信息, 因为部署完后不代表成功了.


linux 服务器如何查看日志

1、先切换到:cd usr/local/tomcat5/logs

2、tail -f catalina.out

3、这样运行时就可以实时查看运行日志了


作业二:


请描述你对分布式调度的理解(结合Elastic-Job-lite图文并茂描述)

什么是分布式任务调度?有两层含义


1)运⾏在分布式集群环境下的调度任务(同⼀个定时任务程序部署多份,只应该有⼀个定时任务在执 ⾏)


2)分布式调度—>定时任务的分布式—>定时任务的拆分(即为把⼀个⼤的作业任务拆分为多个⼩的作业任务,同时执⾏)


image.png


ElasticJob - 分布式作业调度解决方案



官方网站: http://shardingsphere.apache.org/elasticjob/


ElasticJob 是一个分布式调度解决方案,由 2 个相互独立的子项目 ElasticJob Lite 和 ElasticJob Cloud 组成。


ElasticJob Lite 定位为轻量级无中心化解决方案,使用 jar 的形式提供分布式任务的协调服务;


ElasticJob Cloud 使用 Mesos + Docker(TODO)的解决方案,额外提供资源治理、应用分发以及进程隔离等服务。


ElasticJob 的各个产品使用统一的作业 API,开发者仅需要一次开发,即可随意部署。


架构图

ElasticJob Lite


image.png

功能列表


  • 弹性调度


  • 支持任务在分布式场景下的分片和高可用


  • 能够水平扩展任务的吞吐量和执行效率


  • 任务处理能力随资源配备弹性伸缩


  • 资源分配


  • 在适合的时间将适合的资源分配给任务并使其生效


  • 相同任务聚合至相同的执行器统一处理


  • 动态调配追加资源至新分配的任务


  • 作业治理


  • 失效转移


  • 错过作业重新执行


  • 自诊断修复


  • 作业依赖(TODO)


  • 基于有向无环图(DAG)的作业间依赖


  • 基于有向无环图(DAG)的作业分片间依赖


  • 作业开放生态


  • 可扩展的作业类型统一接口


  • 丰富的作业类型库,如数据流、脚本、HTTP、文件、大数据等


  • 易于对接业务作业,能够与 Spring 依赖注入无缝整合


  • 可视化管控端


  • 作业管控端


  • 作业执行历史数据追踪


  • 注册中心管理


快速入门


引入maven依赖

<!-- 引入elasticjob-lite核心模块 -->
<dependency>
    <groupId>org.apache.shardingsphere.elasticjob</groupId>
    <artifactId>elasticjob-lite-core</artifactId>
    <version>${latest.release.version}</version>
</dependency>
<!-- 使用springframework自定义命名空间时引入 -->
<dependency>
    <groupId>org.apache.shardingsphere.elasticjob</groupId>
    <artifactId>elasticjob-lite-spring</artifactId>
    <version>${latest.release.version}</version>
</dependency>


作业开发

public class MyElasticJob implements SimpleJob {
    @Override
    public void execute(ShardingContext context) {
        switch (context.getShardingItem()) {
            case 0: 
                // do something by sharding item 0
                break;
            case 1: 
                // do something by sharding item 1
                break;
            case 2: 
                // do something by sharding item 2
                break;
            // case n: ...
        }
    }
}


作业配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:elasticjob="http://shardingsphere.apache.org/schema/elasticjob"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://shardingsphere.apache.org/schema/elasticjob
                           http://shardingsphere.apache.org/schema/elasticjob/elasticjob.xsd
                           ">
    <!--配置作业注册中心 -->
    <elasticjob:zookeeper id="regCenter" server-lists="yourhost:2181" namespace="elastic-job" base-sleep-time-milliseconds="1000" max-sleep-time-milliseconds="3000" max-retries="3" />
    <!--配置任务快照服务 -->
    <elasticjob:snapshot id="jobSnapshot" registry-center-ref="regCenter" dump-port="9999"/>
    <!--配置作业类 -->
    <bean id="simpleJob" class="xxx.MyElasticJob" />
    <!--配置作业 -->
    <elasticjob:simple id="oneOffElasticJob" job-ref="simpleJob" registry-center-ref="regCenter" cron="0/10 * * * * ?" sharding-total-count="3" sharding-item-parameters="0=A,1=B,2=C" />
</beans>


其他笔记


拦截器与Filter的区别


Spring的拦截器与Servlet的Filter有相似之处,比如二者都是AOP编程思想的体现,

都能实现权限检查、日志记录等。不同的是:


  • 使用范围不同: Filter 是Servlet 规范规定的,只能用于Web程序中。而拦截器既
    可以用于Web程序,也可以用于Application、Swing 程序中。


  • 规范不同: Filter 是在Servlet规范中定义的,是Servlet容器支持的。而拦截器是
    在Spring容器内的,是Spring框架支持的。


  • 使用的资源不同:同其他的代码块一样, 拦截器也是一个Spring的组件,归Spring
    管理,配置在Spring文件中,因此能使用Spring里的任何资源、对象,例如Service
    对象、数据源、事务管理等,通过IoC注入到拦截器即可;而 Filter 过滤器不能。


  • 深度不同: Filter 在只在Servlet前后起作用。而拦截器能够深入到方法前后、异常抛出前后等,因此拦截器的使用具有更大的弹性。所以在 Spring 构架的程序中,要优先使用拦截器


目录
相关文章
|
11月前
|
人工智能 Kubernetes 数据可视化
Kubernetes下的分布式采集系统设计与实战:趋势监测失效引发的架构进化
本文回顾了一次关键词监测任务在容器集群中失效的全过程,分析了中转IP复用、调度节奏和异常处理等隐性风险,并提出通过解耦架构、动态IP分发和行为模拟优化采集策略,最终实现稳定高效的数据抓取与分析。
233 2
Kubernetes下的分布式采集系统设计与实战:趋势监测失效引发的架构进化
|
10月前
|
监控 Java API
Spring Boot 3.2 结合 Spring Cloud 微服务架构实操指南 现代分布式应用系统构建实战教程
Spring Boot 3.2 + Spring Cloud 2023.0 微服务架构实践摘要 本文基于Spring Boot 3.2.5和Spring Cloud 2023.0.1最新稳定版本,演示现代微服务架构的构建过程。主要内容包括: 技术栈选择:采用Spring Cloud Netflix Eureka 4.1.0作为服务注册中心,Resilience4j 2.1.0替代Hystrix实现熔断机制,配合OpenFeign和Gateway等组件。 核心实操步骤: 搭建Eureka注册中心服务 构建商品
1422 3
|
11月前
|
消息中间件 负载均衡 中间件
⚡ 构建真正的高性能即时通讯服务:基于 Netty 集群的架构设计与实现
本文介绍了如何基于 Netty 构建分布式即时通讯集群。随着用户量增长,单体架构面临性能瓶颈,文章对比了三种集群方案:Nginx 负载均衡、注册中心服务发现与基于 ZooKeeper 的消息路由架构。最终选择第三种方案,通过 ZooKeeper 实现服务注册发现与消息路由,并结合 RabbitMQ 支持跨服务器消息广播。文中还详细讲解了 ZooKeeper 搭建、Netty 集群改造、动态端口分配、服务注册、负载均衡及消息广播的实现,构建了一个高可用、可水平扩展的即时通讯系统。
1141 0
|
8月前
|
缓存 Cloud Native 中间件
《聊聊分布式》从单体到分布式:电商系统架构演进之路
本文系统阐述了电商平台从单体到分布式架构的演进历程,剖析了单体架构的局限性与分布式架构的优势,结合淘宝、京东等真实案例,深入探讨了服务拆分、数据库分片、中间件体系等关键技术实践,并总结了渐进式迁移策略与核心经验,为大型应用架构升级提供了全面参考。
|
8月前
|
存储 NoSQL 前端开发
【赵渝强老师】MongoDB的分布式存储架构
MongoDB分片通过将数据分布到多台服务器,实现海量数据的高效存储与读写。其架构包含路由、配置服务器和分片服务器,支持水平扩展,结合复制集保障高可用性,适用于大规模生产环境。
556 1
|
9月前
|
存储 监控 NoSQL
Redis高可用架构全解析:从主从复制到集群方案
Redis高可用确保服务持续稳定,避免单点故障导致数据丢失或业务中断。通过主从复制实现数据冗余,哨兵模式支持自动故障转移,Cluster集群则提供分布式数据分片与水平扩展,三者层层递进,保障读写分离、容灾切换与大规模数据存储,构建高性能、高可靠的Redis架构体系。
|
12月前
|
监控 算法 关系型数据库
分布式事务难题终结:Seata+DRDS全局事务一致性架构设计
在分布式系统中,CAP定理限制了可用性、一致性与分区容错的三者兼得,尤其在网络分区时需做出取舍。为应对这一挑战,最终一致性方案成为常见选择。以电商订单系统为例,微服务化后,原本的本地事务演变为跨数据库的分布式事务,暴露出全局锁失效、事务边界模糊及协议差异等问题。本文深入探讨了基于 Seata 与 DRDS 的分布式事务解决方案,涵盖 AT 模式实践、分片策略优化、典型问题处理、性能调优及高级特性实现,结合实际业务场景提供可落地的技术路径与架构设计原则。通过压测验证,该方案在事务延迟、TPS 及失败率等方面均取得显著优化效果。
600 61
|
9月前
|
消息中间件 缓存 监控
中间件架构设计与实践:构建高性能分布式系统的核心基石
摘要 本文系统探讨了中间件技术及其在分布式系统中的核心价值。作者首先定义了中间件作为连接系统组件的&quot;神经网络&quot;,强调其在数据传输、系统稳定性和扩展性中的关键作用。随后详细分类了中间件体系,包括通信中间件(如RabbitMQ/Kafka)、数据中间件(如Redis/MyCAT)等类型。文章重点剖析了消息中间件的实现机制,通过Spring Boot代码示例展示了消息生产者的完整实现,涵盖消息ID生成、持久化、批量发送及重试机制等关键技术点。最后,作者指出中间件架构设计对系统性能的决定性影响,
|
监控 Linux 应用服务中间件
Linux多节点多硬盘部署MinIO:分布式MinIO集群部署指南搭建高可用架构实践
通过以上步骤,已成功基于已有的 MinIO 服务,扩展为一个 MinIO 集群。该集群具有高可用性和容错性,适合生产环境使用。如果有任何问题,请检查日志或参考MinIO 官方文档。作者联系方式vx:2743642415。
3930 57
|
NoSQL 算法 安全
redis分布式锁在高并发场景下的方案设计与性能提升
本文探讨了Redis分布式锁在主从架构下失效的问题及其解决方案。首先通过CAP理论分析,Redis遵循AP原则,导致锁可能失效。针对此问题,提出两种解决方案:Zookeeper分布式锁(追求CP一致性)和Redlock算法(基于多个Redis实例提升可靠性)。文章还讨论了可能遇到的“坑”,如加从节点引发超卖问题、建议Redis节点数为奇数以及持久化策略对锁的影响。最后,从性能优化角度出发,介绍了减少锁粒度和分段锁的策略,并结合实际场景(如下单重复提交、支付与取消订单冲突)展示了分布式锁的应用方法。
948 3