精华内容
下载资源
问答
  • 1.架构图 2.nginx 2.1 nginx支持htpps openssl生成证书私钥(这里需要输入两次密码,请谨记) openssl genrsa -des3 -out 《证书名称》.key 2048 openssl生成不需要密码的密钥 openssl rsa -in test.key -...

    1.架构图

    在这里插入图片描述

    2.nginx

    2.1 nginx支持htpps

    • openssl生成私钥(这里需要输入两次密码,请谨记)
      在这里插入图片描述
    openssl genrsa -des3 -out 《私钥名称》.key 2048
    
    • openssl生成不需要密码的密钥
      在这里插入图片描述
    openssl rsa -in 《私钥名称》.key -out 《要生成的无密码公钥名称》.key
    
    • openssl创建证书签名文件(根据要求填写信息)
      在这里插入图片描述
    openssl req -new -key 《私钥名称》.key -out 《要生成的签名文件名称》.csr
    
    • 生成证书
    openssl x509 -req -days 365 -in 《签名文件名称》.csr -signkey 《私钥名称》.key -out 《要生成的证书名称》.crt
    

    2.2 nginx https分流配置

    server {
            #端口后边+ ssl 意思是开启ssl支持https
            listen       10086 ssl;
            server_name  <项目名称要和生成私钥的compony对应上才可>;
    		
    		#SSL配置
    		ssl_certificate      /ssl/test.crt; # 配置证书地址
    		ssl_certificate_key  /ssl/test_nopass.key; # 配置证书私钥地址
    		ssl_protocols        TLSv1 TLSv1.1 TLSv1.2; # 配置SSL协议版本
    		ssl_ciphers          ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; # 配置SSL加密算法
    		ssl_prefer_server_ciphers  on; # 优先采取服务器算法
    		ssl_session_cache    shared:SSL:10m; # 配置共享会话缓存大小
    		ssl_session_timeout  10m; # 配置会话超时时间
    
    
            charset utf-8;
    
    		location / {
    			proxy_pass  https://webgroup;
               # 如下的配置很重要不然会发现有些前后端未分离的项目页面请求路径前缀会变成proxy_pass
    			proxy_redirect off;
    			proxy_set_header Host $http_host;
    			proxy_set_header X-Real-IP $remote_addr;
    			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
    }
    

    2.3 完整的nginx conf

    user  nginx;
    worker_processes  auto;
    
    error_log  /var/log/nginx/error.log notice;
    pid        /var/run/nginx.pid;
    
    
    events {
        worker_connections  1024;
    }
    
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
    
        access_log  /var/log/nginx/access.log  main;
    
        sendfile        on;
        #tcp_nopush     on;
    
        keepalive_timeout  65;
    
        #gzip  on;
    
        include /etc/nginx/conf.d/*.conf;
    	
    	upstream webgroup{
    		ip_hash;
    		server 192.168.1:81 weight=1;
    		server 192.168.1:82 weight=1;
    	}
    	server {
    	 #端口后边+ ssl 意思是开启ssl支持https
            listen       10086 ssl;
            server_name  <项目名称要和生成私钥的compony对应上才可>;
    		
    		#SSL配置
    		ssl_certificate      /ssl/test.crt; # 配置证书地址
    		ssl_certificate_key  /ssl/test_nopass.key; # 配置证书私钥地址
    		ssl_protocols        TLSv1 TLSv1.1 TLSv1.2; # 配置SSL协议版本
    		ssl_ciphers          ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE; # 配置SSL加密算法
    		ssl_prefer_server_ciphers  on; # 优先采取服务器算法
    		ssl_session_cache    shared:SSL:10m; # 配置共享会话缓存大小
    		ssl_session_timeout  10m; # 配置会话超时时间
    
    
            charset utf-8;
    
    		location / {
    			proxy_pass  https://webgroup;
               # 如下的配置很重要不然会发现有些前后端未分离的项目页面请求路径前缀会变成proxy_pass
    			proxy_redirect off;
    			proxy_set_header Host $http_host;
    			proxy_set_header X-Real-IP $remote_addr;
    			proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            }
    
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }
    
    

    2.4 nginx docker-componse

     # nginx ---------------------------------------------
      nginx:
        labels:
          service: nginx
        logging:
          options:
            labels: "service"
        restart: always
        image: nginx
        container_name: nginx
        ports:
          - 8080:80
          - 80:1080
        volumes:
          - /nginx/nginx.conf:/etc/nginx/nginx.conf
          - /nginx/log:/var/log/nginx
          - /ssl:/ssl
        networks:
          - soil-net
        environment:
          - TZ=Asia/Shanghai
    

    3.web服务自动切换数据源配置

    前言: 这里使用的阿里的数据库连接池druid,灵感来自于他的主从分离,我一想你可以主从分离那肯定是哪里可以该数据库的url地址啊,然后我一行一行debug终于找到了一个办法可以改,但是这样只是个临时凑合的办法会慢,我的服务切换会有五六秒的时间才可以切换过来,再此建议增加中间件keepalive+双主备份的情况让服务和mysql解耦

    3.1拦截异常

    @ControllerAdvice(value = "要拦截的目录例如com.test.controller")
    @Slf4j
    public class DefaultGlobalExceptionHandlerAdvice {
        /**
         * 数据库连接超时
         *
         * @param ex
         * @return
         */
        @ResponseBody
        @ExceptionHandler(RecoverableDataAccessException.class)
        public ReturnMsg dataAccessResourceFailureException(RecoverableDataAccessException ex) {
            //发生异常切换数据源
            CustomizeDruidDataSource.switchDbType();
            return "系统异常!";
        }
    }
    

    3.2切换url的工具类

    前言: 我还做了读写分离的一些工作,但没必要展示,这里的urls可以自己往里边传,我是有个配置文件自己拼装了一个数组放进来的

    import com.alibaba.druid.pool.DruidDataSource;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    /**
     * @explain 替换掉alibaba数据源类,动态切换数据库,一旦数据库挂掉切换到另一台
     * @Classname CustomizeDruidDataSource
     * @Date 2021/10/11 12:20
     * @Created by hanzhao
     */
    public class CustomizeDruidDataSource extends DruidDataSource {
        private boolean lastInited;
    
        private static boolean dbStatus = true; //true代表主库运行正常,false代表主库运行异常
    
    
        private String[] urls;
    
        public static void switchDbType() {
            if(dbStatus){
                dbStatus = false;
            }else{
                dbStatus = true;
            }
        }
    
        public String[] getUrls() {
            return urls;
        }
    
        public void setUrls(String[] urls) {
            this.urls = urls;
        }
    
        @Override
        public void init() throws SQLException {
            lastInited = inited;
            super.init();
            if (!lastInited && inited) {
                new Thread(new ValidateUrlTask()).start();
            }
        }
    
        class ValidateUrlTask implements Runnable {
    
            @Override
            public void run() {
                while (true) {
                    // 如果这个数据源被关闭了,就结束这个定时任务
                    if (isClosed()) {
                        break;
                    }
                    //如果这个数据源已经被初始化了,同时连接异常才进行处理
                    if (isInited() && !dbStatus) {
                        for (String thisUrl : urls) {
                            Connection connection = null;
                            try {
                                connection = DriverManager.getConnection(thisUrl, username, password);
                                jdbcUrl = thisUrl;
                                CustomizeDruidDataSource.switchDbType();
                            } catch (Exception ignored) {
                            } finally {
                                try {
                                    connection.close();
                                } catch (Exception ignored) {
                                }
                            }
                        }
                    }
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException ignored) {
                    }
                }
            }
        }
    }
    

    3.3springboot配置

    spring:
      #数据源地址
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        druid:
          # 主库数据源
          master:
            url: jdbc:mysql://url?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true
            username: root
            password: 密码
          # 从库数据源
          slave:
            #从数据源开关/默认关闭
            enabled: true
            url: jdbc:mysql://url?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8&useSSL=true
            username: root
            password: 密码
          # 初始连接数
          initialSize: 5
          # 最小连接池数量
          minIdle: 10
          # 最大连接池数量
          maxActive: 20
          # 配置获取连接等待超时的时间
          maxWait: 60000
          # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
          timeBetweenEvictionRunsMillis: 60000
          # 配置一个连接在池中最小生存的时间,单位是毫秒
          minEvictableIdleTimeMillis: 300000
          # 配置一个连接在池中最大生存的时间,单位是毫秒
          maxEvictableIdleTimeMillis: 900000
          # 配置检测连接是否有效
          validationQuery: SELECT 1 FROM DUAL
          testWhileIdle: true
          testOnBorrow: false
          testOnReturn: false
          webStatFilter:
            enabled: true
          statViewServlet:
            enabled: true
            # 设置白名单,不填则允许所有访问
            allow:
            url-pattern: /monitor/druid/*
          filter:
            stat:
              enabled: true
              # 慢SQL记录
              log-slow-sql: true
              slow-sql-millis: 1000
              merge-sql: true
            wall:
              config:
                multi-statement-allow: true
    

    4.mysql主从备份

    4.1 mysql配置文件

    [mysqld]
    # [必须]服务器唯一ID,默认是1,一般取IP最后一段
    server-id=1
    
    # [必须]启用二进制日志
    log-bin=mysql-bin 
    
    # 复制过滤:也就是指定哪个数据库不用同步(mysql库一般不同步)
    binlog-ignore-db=mysql
    # 数据目录
    datadir		= /var/lib/mysql
    # 错误日志位置
    log-error	= /var/log/mysql/error.log
    
    # 设置需要同步的数据库 binlog_do_db = 数据库名; 
    # 如果是多个同步库,就以此格式另写几行即可。
    # 如果不指明对某个具体库同步,表示同步所有库。除了binlog-ignore-db设置的忽略的库
    # binlog_do_db = test #需要同步test数据库。
    
    # 确保binlog日志写入后与硬盘同步
    sync_binlog = 1
    
    # 跳过所有的错误,继续执行复制操作
    slave-skip-errors = all    
    
    sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION 
    

    4.2 docker-componse文件

    soilmysql_master:
        labels:
          service: soilmysql_master
        logging:
          options:
            labels: "service"
        user: "root"
        restart: always
        image: mysql:5.7
        container_name: "mysql_master"
        ports:
          - "10086:3306"
        volumes:
          - 《将数据库日志数据等信息存储到宿主的磁盘中》:/var/lib/mysql
          - 《宿主mysql配置文件路径》:/etc/mysql/mysql.conf.d/mysqld.cnf
        environment:
          MYSQL_ROOT_PASSWORD: 初始root账户密码
        networks:
          - soil-net
    soilmysql_slave:
        labels:
          service: mysql_slave
        logging:
          options:
            labels: "service"
        user: "root"
        restart: always
        image: mysql:5.7
        container_name: "soilmysql_slave"
        ports:
          - "10010:3306"
        volumes:
          - 《将数据库日志数据等信息存储到宿主的磁盘中》:/var/lib/mysql
          - 《宿主mysql配置文件路径》:/etc/mysql/mysql.conf.d/mysqld.cnf
        environment:
          MYSQL_ROOT_PASSWORD: 初始root账户密码
        networks:
          - soil-net
    

    4.3 mysql双主命令

    1. 将my.cnf配置文件拷贝到docker-componse挂载的目录下
    2. 记得修改server-id
    3. 分别进入容器中执行以下命令
      mysql -uroot -p<密码>
      CREATE USER ‘《同步账户》’@’%’ IDENTIFIED BY ‘《同步账户的密码》’;
      GRANT ALTER, SHOW VIEW, SHOW DATABASES, SELECT, PROCESS, EXECUTE, ALTER ROUTINE, CREATE, CREATE ROUTINE, CREATE TABLESPACE, CREATE TEMPORARY TABLES, CREATE VIEW, DELETE, DROP, EVENT, INDEX, INSERT, REFERENCES, TRIGGER, UPDATE, CREATE USER, FILE, LOCK TABLES, RELOAD, REPLICATION CLIENT, REPLICATION SLAVE, SHUTDOWN, SUPER ON . TO ‘《同步账户》’@’%’ WITH GRANT OPTION;
      FLUSH PRIVILEGES;
      CHANGE MASTER TO master_host=’<另一台机器的ip地址>’, master_port=<另一台机器的端口号>, master_user=’《同步账户》’, master_password=’《同步账户的密码》’;
      START SLAVE;
    4. 上述步骤在两台机器上全部执行完成后,查看状态
      SHOW SLAVE STATUS;
      Slave_IO_Running | Slave_SQL_Running都为yes 才算成功

    5.参考文献

    5.1 nginx+ssl

    http://nginx.org/en/
    https://www.nginx.cn/doc/
    https://www.jianshu.com/p/06952c316f0c
    https://www.runoob.com/w3cnote/nginx-setup-intro.html
    https://blog.csdn.net/u011659193/article/details/85778764
    https://blog.csdn.net/zhenghongcs/article/details/109302331

    5.2 mysql双主备份

    https://www.cnblogs.com/a1304908180/p/10351930.html
    https://blog.csdn.net/zhangguanghui002/article/details/78959816
    https://www.jianshu.com/p/70ca1ef79cd4
    https://help.aliyun.com/knowledge_detail/41106.html?spm=a2c6h.13066369.0.0.5ae84055BKlrw9#XACzT

    展开全文
  • 高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。 假设系统一直能够提供服务,我们说系统的可用性是100%。 如果系统每运行100个时间...

     一、什么是高可用

    高可用HAHigh Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。

    假设系统一直能够提供服务,我们说系统的可用性是100%。

    如果系统每运行100个时间单位,会有1个时间单位无法提供服务,我们说系统的可用性是99%。

    很多公司的高可用目标是4个9,也就是99.99%,这就意味着,系统的年停机时间为8.76个小时。

    百度的搜索首页,是业内公认高可用保障非常出色的系统,甚至人们会通过www.baidu.com 能不能访问来判断“网络的连通性”,百度高可用的服务让人留下啦“网络通畅,百度就能访问”,“百度打不开,应该是网络连不上”的印象,这其实是对百度HA最高的褒奖。

    二、如何保障系统的高可用

    我们都知道,单点是系统高可用的大敌,单点往往是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点。方法论上,高可用保证的原则是“集群化”,或者叫“冗余”:只有一个单点,挂了服务会受影响;如果有冗余备份,挂了还有其他backup能够顶上。

    保证系统高可用,架构设计的核心准则是:冗余。

    有了冗余之后,还不够,每次出现故障需要人工介入恢复势必会增加系统的不可服务实践。所以,又往往是通过“自动故障转移”来实现系统的高可用

    接下来我们看下典型互联网架构中,如何通过冗余+自动故障转移来保证系统的高可用特性。

    三、常见的互联网分层架构


    常见互联网分布式架构如上,分为:

    (1)客户端层:典型调用方是浏览器browser或者手机应用APP

    (2)反向代理层:系统入口,反向代理

    (3)站点应用层:实现核心应用逻辑,返回html或者json

    (4)服务层:如果实现了服务化,就有这一层

    (5)数据-缓存层:缓存加速访问存储

    (6)数据-数据库层:数据库固化数据存储

    整个系统的高可用,又是通过每一层的冗余+自动故障转移来综合实现的。

    四、分层高可用架构实践

    【客户端层->反向代理层】的高可用


    【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余来实现的。以nginx为例:有两台nginx,一台对线上提供服务,另一台冗余以保证高可用,常见的实践是keepalived存活探测,相同virtual IP提供服务。


    自动故障转移:当nginx挂了的时候,keepalived能够探测到,会自动的进行故障转移,将流量自动迁移到shadow-nginx,由于使用的是相同的virtual IP,这个切换过程对调用方是透明的。

    【反向代理层->站点层】的高可用


    【反向代理层】到【站点层】的高可用,是通过站点层的冗余来实现的。假设反向代理层是nginx,nginx.conf里能够配置多个web后端,并且nginx能够探测到多个后端的存活性。


    自动故障转移:当web-server挂了的时候,nginx能够探测到,会自动的进行故障转移,将流量自动迁移到其他的web-server,整个过程由nginx自动完成,对调用方是透明的。

    【站点层->服务层】的高可用


    【站点层】到【服务层】的高可用,是通过服务层的冗余来实现的。“服务连接池”会建立与下游服务多个连接,每次请求会“随机”选取连接来访问下游服务。


    自动故障转移:当service挂了的时候,service-connection-pool能够探测到,会自动的进行故障转移,将流量自动迁移到其他的service,整个过程由连接池自动完成,对调用方是透明的(所以说RPC-client中的服务连接池是很重要的基础组件)。

    【服务层>缓存层】的高可用


    【服务层】到【缓存层】的高可用,是通过缓存数据的冗余来实现的。

    缓存层的数据冗余又有几种方式:第一种是利用客户端的封装,service对cache进行双读或者双写。


    缓存层也可以通过支持主从同步的缓存集群来解决缓存层的高可用问题。

    以redis为例,redis天然支持主从同步,redis官方也有sentinel哨兵机制,来做redis的存活性检测。


    自动故障转移:当redis主挂了的时候,sentinel能够探测到,会通知调用方访问新的redis,整个过程由sentinel和redis集群配合完成,对调用方是透明的。

    说完缓存的高可用,这里要多说一句,业务对缓存并不一定有“高可用”要求,更多的对缓存的使用场景,是用来“加速数据访问”:把一部分数据放到缓存里,如果缓存挂了或者缓存没有命中,是可以去后端的数据库中再取数据的。

    这类允许“cache miss”的业务场景,缓存架构的建议是:


    将kv缓存封装成服务集群,上游设置一个代理(代理可以用集群冗余的方式保证高可用),代理的后端根据缓存访问的key水平切分成若干个实例,每个实例的访问并不做高可用。


    缓存实例挂了屏蔽:当有水平切分的实例挂掉时,代理层直接返回cache miss,此时缓存挂掉对调用方也是透明的。key水平切分实例减少,不建议做re-hash,这样容易引发缓存数据的不一致。

    【服务层>数据库层】的高可用

    大部分互联网技术,数据库层都用了“主从同步,读写分离”架构,所以数据库层的高可用,又分为“读库高可用”与“写库高可用”两类。

    【服务层>数据库层“读”】的高可用


    【服务层】到【数据库读】的高可用,是通过读库的冗余来实现的。

    既然冗余了读库,一般来说就至少有2个从库,“数据库连接池”会建立与读库多个连接,每次请求会路由到这些读库。


    自动故障转移:当读库挂了的时候,db-connection-pool能够探测到,会自动的进行故障转移,将流量自动迁移到其他的读库,整个过程由连接池自动完成,对调用方是透明的(所以说DAO中的数据库连接池是很重要的基础组件)。

    【服务层>数据库层“写”】的高可用


    【服务层】到【数据库写】的高可用,是通过写库的冗余来实现的。

    以mysql为例,可以设置两个mysql双主同步,一台对线上提供服务,另一台冗余以保证高可用,常见的实践是keepalived存活探测,相同virtual IP提供服务。


    自动故障转移:当写库挂了的时候,keepalived能够探测到,会自动的进行故障转移,将流量自动迁移到shadow-db-master,由于使用的是相同的virtual IP,这个切换过程对调用方是透明的。

    五、总结

    高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。

    方法论上,高可用是通过冗余+自动故障转移来实现的。

    整个互联网分层系统架构的高可用,又是通过每一层的冗余+自动故障转移来综合实现的,具体的:

    (1)【客户端层】到【反向代理层】的高可用,是通过反向代理层的冗余实现的,常见实践是keepalived + virtual IP自动故障转移

    (2)【反向代理层】到【站点层】的高可用,是通过站点层的冗余实现的,常见实践是nginx与web-server之间的存活性探测与自动故障转移

    (3)【站点层】到【服务层】的高可用,是通过服务层的冗余实现的,常见实践是通过service-connection-pool来保证自动故障转移

    (4)【服务层】到【缓存层】的高可用,是通过缓存数据的冗余实现的,常见实践是缓存客户端双读双写,或者利用缓存集群的主从数据同步与sentinel保活与自动故障转移;更多的业务场景,对缓存没有高可用要求,可以使用缓存服务化来对调用方屏蔽底层复杂性

    (5)【服务层】到【数据库“读”】的高可用,是通过读库的冗余实现的,常见实践是通过db-connection-pool来保证自动故障转移

    (6)【服务层】到【数据库“写”】的高可用,是通过写库的冗余实现的,常见实践是keepalived + virtual IP自动故障转移

    展开全文
  • 高可用架构设计之无状态服务 笑谈架构设计 事故的发生是量的积累的结果,任何事情都没有表面看起来那么简单,在软件运行的过程中,随着用户量的增加,不考虑可用,迟早有一天会发生故障,不得事先考虑可用设计,...

    高可用架构设计之无状态服务

    笑谈架构设计

    事故的发生是量的积累的结果,任何事情都没有表面看起来那么简单,在软件运行的过程中,随着用户量的增加,不考虑高可用,迟早有一天会发生故障,不得事先考虑高可用设计,而高可用是一门庞大的学问

    你想知道我在设计一个高可用系统会考虑哪些内容吗?在架构设计的过程中

    • 考虑方案选型会带来哪些坑,最差的情况下需要考虑故障发生的紧急解决方案
    • 需要监控系统,在故障发生时、发生时有所感知
    • 需要自动化恢复方案,自动化提前处理预警方案
    • 在代码层面需要考虑处理速度、代码性能、报错处理
    • 还要考虑把故障降低到最小:服务降级、限流、熔断
    • 等等

    这篇文章主要介绍无状态服务在架构层面,如何保证可高用

    无状态服务:在任何时候服务都不存储数据(除缓存),可以任意销毁创建,用户数据不会发生丢失,可以任意切换到任何一个副本,不影响用户

    无状态服务的高可用旨在任何情况下数据都不丢失,服务都不发生故障,在某些服务发生故障时保证影响最小,并可以快速恢复

    可以从这几个方面考虑

    • 冗余部署:至少多部署一个节点,避免单点问题
    • 垂直扩展:增加单机性能
    • 水平扩展:流量激增可快速扩容

    冗余部署

    在单点架构中,随着数据数据量增加,单点负载压力过大,容易产生服务崩溃不可用的情形,对于无状态服务,可以考虑部署多个节点的服务来分散压力

    对于如何调度来临的请求,可以参考负载均衡的方式,尽可能的保证充分的利用服务器的资源

    • 无状态服务:不需要存储数据的服务,即使节点挂掉再重启,不会发生数据丢失
    • 负载均衡:把大量请求分散到不同节点上的一种算法

    无状态服务的负载均衡

    可以使用负载均衡中提供的四种算法

    • 随机均衡算法:已知后端服务器列表,随机请求,数据量越大越趋近于均衡
    • 轮询算法:轮流请求后端服务器

    前两种算法存在的问题是后端服务器在负载压力不同或服务器配置不同时,不能保证压力小的多分配,压力大的小分配,于是引入

    • 加权轮循算法:按照后端服务器的抗压能力,负载情况分配更高的权重,更容易命中,减少宕机风险,按权重顺序的分配到后端服务器上
    • 加权随机法:和加权轮训算法一样,不同的是分配是按权重随机的,比如有多台权重一致的情况,随机访问,那就和随机算法有同样的问题,数据量大时才趋近于均衡,数据量小时有可能重复访问同一台权重一致的机器
    • [加权]最小连接数算法:这是最智能的一种算法,根据服务器当前的连接数来选取,更容易命中处理速度快的服务器

    上面的算法使用于无状态应用,假如要保存通信状态,需要使用

    • 源地址哈希算法:对源地址做hash,可以保证相同的请求最终都是落在同一台机器上,不需要重复建立连接

    负载均衡算法如何选择?

    首先抛弃随机算法,最简单的配置可以使用基本的轮训算法,它适用于服务器配置一致,比如使用虚拟机,可以动态调整服务器配置的场景,同时要保证专用虚拟机,上面不会部署其他应用的情况

    但是服务器上往往会安装多个应用,那就要考虑在加权轮训最小连接数中做选择

    加权轮训适用于短连接场景,比如HTTP服务,在k8s中因为每个pod都是独立的,默认service策略是非加权轮训

    • 最小连接数适用于长连接,比如FTP等

    如果系统架构中考虑到无cookie功能的场景,可以用源地址hash算法,把源IP一直映射到同一台rs上,在k8s中叫会话保持模式,每次转发到同一个pod上

    建议:

    • 如果上了容器直接交给k8s来做调度,使用cookie做会话保持,算法使用默认轮训,具体调度未来k8s文章里会做详细介绍
    • 使用长连接的应用(FTP、socket,或者用于下载连接),选择加权最小连接数
    • 短连接应用(静态网站、微服务组件等),选择加权轮训,用cookie来做会话保持,减少session的设计,不仅会提高代码复杂度,也会增加服务端负载情况,不利于分布式应用

    高并发应用的识别

    主要指标QPS每秒处理响应数,比如每天有10w的pv

    公式 (100000 * 80%) / (86400*20%) = 4.62 QPS(峰值QPS)
    

    公式原理:每天80%的访问集中在20%的时间里,这20%时间叫做峰值时间。

    比如我做的系统托管了最高5w台机器,每台机器每次分钟有一次PV,时间比较均匀那就是

    ((60*24)*50000)/(86400)=833 QPS
    

    一般上百的量级就可以叫高并发了,网上查到的资料微博每天1亿多pv的系统一般也就1500QPS,5000QPS峰值。

    除了QPS还有服务响应时间、并发用户数指标可以参考

    在服务器负载高的时候,表现在处理速度变慢、网络断连、服务处理失败、异常报错等问题,具体问题要具体分析,不可一概而论

    可以通过监控,来获得服务器性能状态,动态调整、重试,达到服务可用性的保证,减少维护成本,通常单纯服务器压力大的时候可以考虑垂直扩展

    垂直扩展

    垂直扩展是增加服务器单机的处理能力,主要有三种方式

    • 服务器升配:集中在CPU、内存、swap、磁盘容量或者网卡等
    • 硬件性能:磁盘SSD、调整系统参数等
    • 架构调整:软件层面使用异步、缓存、无锁结构等

    增强单机性能的方式是最快最容易的方式,但是单机性能之中是存在极限,同时单机部署时如果产生故障,对应用来说打击是致命的,我们应该保证应用时刻处于可用的状态,也就是俗话说的保证5个9的可靠性

    水平自动伸缩

    知道了单机的局限以后,考虑使用水平伸缩的方式

    水平伸缩就是压力增加的时候,增加新的节点来分担压力,但仅仅多点部署还是不够的,对于持续增长的业务,始终有一天会突破服务的压力上限,如果遇到流量激增的场景,人工应对肯定会措手不及,所以需要一种自动伸缩的手段

    • 对于私有云部署来说可以手动实现调度器,检测系统状态,连通iaas层实现伸缩
    • 也可以直接使用云服务器提供的弹性伸缩服务
    • 对于容器而言,可以在iaas层弹性伸缩的情况下或者有充足node节点的情况下,配置自动伸缩和调度的策略,预防单机故障

    名词解释:iaas 基础设施即服务,代表对服务器、存储、网络等硬件资源管理的服务

    注意:弹性伸缩针对的业务场景是无状态服务

    另外无状态机器不足以承载请求流量,需要进行水平扩展的阈值一般QPS是千级,同时在这里对数据库也会有压力,所以建议水平伸缩的服务器不要部署有状态服务

    对于有状态服务压力分散在后续的文章会有所介绍

    CDN和OSS

    对于一个网站来说,用户交互页面,是一个特殊的服务,包含很多静态资源,比如图片、视频、页面(html/css/js),这些资源在用户请求的时候需要现场下载,下载速度决定了加载速度,在web服务故障的时候,同样应该对用户做出相应

    在这一层面可以考虑使用CDN内容分发网络的方式,详见[xxx],把前端静态数据缓存到边缘服务器上

    名词解释:边缘服务器(边缘节点),可以理解为和用户交互的服务器,也可理解为靠近用户的服务器节点,因为靠近用户,减少了网络传输使用的时间

    使用了CDN的web服务,可以把https证书绑定到cdn上,在回源策略可以配置回源超时、回源跟随301/302状态码等配置,还可以智能压缩网页、自定义错误页面,非常方便

    oss是一种特殊的存储方案,以对象的形式进行存储,理论上可以存储无限的文件

    考虑使用oss对象存储并结合cdn,把媒体资源存储在对象存储上面,也可以把冷数据压缩归档到oss上

    常见的视频网站大多会用到oss,微博n年以前的数据应该就是归档到对象存储中了

    总结

    本文介绍的无状态服务常见的高可用架构设计,他们是

    • 冗余部署

    • 负载均衡的6种算法与算法选择

    • 垂直扩展的好处与弊端

    • 水平扩展与水平自动伸缩

    • 哪些服务可以使用CDN和OSS

    要注意无状态应用不应该存储session,也不存储数据

    本文对负载均衡的6种算法做了介绍,但是没有介绍每个算法具体的实现方式,这个留给你下来研究,这些方案在实际使用的时候会有一定难度,服务不可用的故障原因任何一门都是博大精深的学问,程序员不仅是写代码

    这里也仅仅写了无状态服务的部分高可用方案,不管是什么服务还是从代码层级的设计,你还知道哪些呢?

    有时候比较苛刻的情况下,没有更多的服务器资源,如何在有限服务器的情况下提高更多的代码性能呢?

    关注我,知道更多不知道的技术

    展开全文
  • GitLab高可用架构部署

    2021-07-01 18:05:52
    GitLab是利用Ruby on Rails一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。与Github类似,GitLab能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它...

    一、概述

    GitLab是利用Ruby on Rails一个开源的版本管理系统,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目。与Github类似,GitLab能够浏览源代码,管理缺陷和注释。可以管理团队对仓库的访问,它非常易于浏览提交过的版本并提供一个文件历史库。团队成员可以利用内置的简单聊天程序(Wall)进行交流。它还提供一个代码片段收集功能可以轻松实现代码复用,便于日后有需要的时候进行查找。

    Gitlab的服务构成

    Nginx:静态web服务器。

    gitlab-shell:用于处理Git命令和修改authorized keys列表。

    gitlab-workhorse: 轻量级的反向代理服务器。

    logrotate:日志文件管理工具。

    postgresql:数据库。

    redis:缓存数据库。

    sidekiq:用于在后台执行队列任务(异步执行)。

    unicorn:An HTTP server for Rack applications,GitLab Rails应用是托管在这个服务器上面的。

    二、系统架构跟规划

    2.1 架构图

    2.2  节点规划

            因为服务器资源限制,目前只有两台机器,所有 gitlab  redis  pg 都安装在这两台服务器上(资源充足的话建议分开),nfs 是在云平台购买的一块nas 盘

    Gitlab Rail Server

    192.168.1.205(主)  192.168.1.207(主)

    Redis

    192.168.1.205(从)  192.168.1.207(主)

    PostgreSQL

    192.168.1.205(主)  192.168.1.207(从)

    NFS

    192.168.100.4:/csp_vol1001_prd

    三、部署安装

    3.1 PG主从安装

    master  192.168.1.205

    slave   192.168.1.207

    #postgres 安装
    
    yum -y install readline readline-devel zlib-devel
    
    
    tar -xvf postgresql-10.3.tar.gz
    
    cd postgresql-10.3
    
     ./configure
    
    make && make install

    PostgreSQL默认安装目录为 /usr/local/pgsql/

    #创建用户:
    
    groupadd -g 1004  postgres
    
    useradd postgres -u 1004 -g postgres
    
    pass@pg
    
    
    
    #建议数据及日志目录
    
    mkdir -p /data/pgsql/5432
    
    mkdir -p /data/logs/pgsql
    
    mkdir /data/pgsql/5432/arch
    
    mkdir /data/pgsql/5432/arch_master

    更改文件夹所有者为用户postgres

    chown postgres.postgres -R /data/pgsql/

    chown postgres.postgres -R /data/logs/pgsql

    chown postgres.postgres -R /usr/local/pgsql

    1. 设置 profile

    export PGHOME="/usr/local/pgsql/"

    export PGDATA="/data/pgsql/5432/"

    PATH=$PATH:$HOME/.local/bin:$HOME/bin:$PGHOME/bin

    export PATH

    1. 初始化数据库

    su "postgres"

    /usr/local/pgsql/bin/initdb -D /data/pgsql/5432

    1. 设置开机自启

    cd /data/xjk/software/mysql/postgresql-10.3/contrib/start-scripts

    cp linux /etc/init.d/postgresql

    chkconfig --add postgresql

    chkconfig  postgresql on

    上面安装步骤需要在主备库都安装

    #在主库操作:

    su postgres

    cd /usr/local/pgsql/bin

    ./psql

    --创建replication 用户 同步数据库

    CREATE ROLE repl login replication password 'repl123';

    创建 gitlab 用户设置

    ALTER ROLE gitlab CREATEROLE CREATEDB

    CREATE USER gitlab WITH PASSWORD 'password@gitlab';

    CREATE DATABASE gitlabhq_production OWNER gitlab;

    GRANT ALL PRIVILEGES ON DATABASE gitlabhq_production TO gitlab;

    ALTER ROLE gitlab CREATEROLE SUPERUSER;

    --修改Master库的pg_hba.conf,把Master库和Standby库的IP地址添加进Master库网络策略白名单中,使Standby库可以连上Master库,同时便于主备切换。

    host    all             all             192.168.1.205/32         trust

    host    all             all             192.168.1.207/32         trust

    host    replication     repl            192.168.1.205/32         md5

    host    replication     repl            192.168.1.207/32         md5

    --修改参数文件

    vi postgresql.conf

    ************************************

    wal_level= logical

    max_wal_senders = 10   # at least the number of standby

    archive_mode = on

    archive_command =  'test ! -f /data/pgsql/5432/arch/%f && cp %p /data/pgsql/5432/arch/%f'

    synchronous_standby_names = ''   #standby application name, in recover.conf

    hot_standby=on

    $ vi recovery.done

    ******************************************

    standby_mode=on

    restore_command = 'cp /data/pgsql/5432/arch_master/%f %p'

    primary_conninfo='application_name=pg2 host=192.168.1.207 port=5432 user=repl password=repl123'

    archive_cleanup_command ='pg_archivecleanup /data/pgsql/5432/arch_master %r'

    recovery_target_timeline = 'latest'

    *********************************************

    重启数据库

    /usr/local/pgsql/bin/pg_ctl -D /data/pgsql/5432  -l /data/logs/pgsql/postgres.log restart

    查看服务是否启动成功

    ps -ef | grep postgres

    在备库操作:

    同步pg到 备库

    scp -r postgres@192.168.1.205: /data/pgsql/5432  /data/pgsql/5432

    /usr/local/pgsql/bin/pg_basebackup -h 192.168.1.205 -U repl -D  /data/pgsql/5432 -X stream –P

    psql -h 192.168.1.205 -U gitlab -d gitlabhq_production -p 5432

    3.2 redis 主从安装

    1. 下载

     wget http://download.redis.io/releases/redis-4.0.11.tar.gz

    1. 安装redis和依赖

            yum -y install gcc

            tar zxvf redis-4.0.11.tar.gz

            mv redis-4.0.11 /usr/local/redis

            cd /usr/local/redis

      make && make install

           

           

    1. 配置

       vim /usr/local/redis/redis.conf

      #修改如下几行信息

      bind 0.0.0.0#不限制访问ip和远程连接

      protected-mode no#保护模式

      daemonize yes#后台运行线程

        dir /usr/local/redis/

           

            requirepass password

    1. 安装启动

     /usr/local/redis/src/redis-server /usr/local/redis/redis.conf

    开机启动:

     (1)编辑redis.service文件

        cd /usr/lib/systemd/system #进入service文件目录

                     vim ./redis.service

                    

                    

                     [Unit]

                     Description=redis

                     After=network.target remote-fs.target nss-lookup.target

                     [Service]

                     Type=forking

                     ExecStart=/usr/local/redis/src/redis-server /usr/local/redis/redis.conf

                     ExecReload=/usr/local/redis/src/redis-cli -p 6379 shutdown | /usr/local/redis/src/redis-server /usr/local/redis/redis.conf

                     ExecStop=/usr/local/redis/src/redis-cli -p 6379 shutdown

                     [Install]

                     WantedBy=multi-user.target

                    

     (2) 生效

            systemctl daemon-reload              

           

           

    (3)改变文件权限

        chmod 777 ./redis.service

      (4)建立软连接

    ln -s /usr/lib/systemd/system/redis.service /etc/systemd/system/multi-user.target.wants/redis.service

      (5)systemctl开机启动redis

        systemctl enable redis.service

    主从设置

    redis 安装:

    https://www.cnblogs.com/zwcry/p/9505949.html

    3.3 GitLab 安装配置

    1. NFS 挂载

    在nas创建相关目录

    mount –t nfs 192.168.100.4:/csp_vol1001_prd /mnt

    cd /mnt

    mkdir git-data

    mkdir .ssh

    mkdir –p gitlab-rails/uploads

    mkdir –p gitlab-rails/shared

    mkdir –p gitlab-ci/builds

    在 /etc/rc.local 把nfs上面 目录 挂载在 /var/opt/gitlab 下的相关目录下

     

    chmod a+x /etc/rc.local

    1. gitlab安装

    卸载 

             gitlab-ctl stop

             rpm -e gitlab-ee

             ps aux | grep gitlab

             systemctl stop gitlab-runsvdir

             kill -9 18777

             find / -name gitlab | xargs rm -rf

    安装

            export http_proxy=http://192.168.1.197:80

            export https_proxy=http://192.168.1.197:80

            yum install -y curl policycoreutils-python openssh-server

            getenforce 0

            systemctl status firewall

            systemctl disabled firewalld

            systemctl stop firewalld

            yum install postfix

            systemctl status postfix

            systemctl enable postfix

            systemctl start postfix

         curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.rpm.sh | bash

            EXTERNAL_URL="http://test.datafile.cn" yum install -y gitlab-ee-11.4.3

    安装完成以后把文件同步到 另外一台 gitlab 服务器,启动

    /opt/gitlab

    /var/opt/gitlab   (nfs 文件不需要)

    1. gitlab配置

    【需要在 192.168.1.205 192.168.1.207 都修改】

    gitlab 配置文件:

    常用操作命令

    #初始化gitlab

    gitlab-rake gitlab:setup

    如果驱动安装成功后,执行gitlab-rake gitlab:check,如果是表不存在,可以执行上面代码,来创建表。

    # 重新加载配置文件:

            systemctl restart gitlab-runsvdir

            gitlab-ctl reconfigure

            gitlab-ctl start

            gitlab-rake gitlab:check

            gitlab-rake gitlab:ldap:check

    #恢复备份:

             gitlab-ctl stop unicorn

             gitlab-ctl stop sidekiq

             gitlab-rake gitlab:backup:restore

             

    #定时备份    

            gitlab-rake gitlab:backup:create

            操作步骤

            修改 /etc/gitlab/gitlab.rb

             

             gitlab_rails['backup_path'] = "/data/backups"

             

             # 保存30

             gitlab_rails['backup_keep_time'] = 2592000

             

             

             gitlab-ctl reconfigure

             

             0 1 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create CRON=1 

             

     #恢复备份:

             gitlab-ctl stop unicorn

             gitlab-ctl stop sidekiq

             gitlab-rake gitlab:backup:restore

             或者

             gitlab-rake gitlab:backup:restore BACKUP=1558492132_2019_05_22_11.4.3-ee

           

     部署遇到的问题:

    Error executing action `create` on resource 'ruby_block[restart redis svlogd configuration]'

    https://gitlab.com/gitlab-org/omnibus-gitlab/issues/160

    systemctl restart gitlab-runsvdir

    gitlab-ctl reconfigure

    https://svolence.github.io/gitlab/ha/

    http://www.cnblogs.com/topicjie/p/7106960.html

    https://www.cnblogs.com/tangqiwen/p/8342918.html

    https://svolence.github.io/gitlab/ha/

    展开全文
  • 并发业务架构设计高可用业务架构设计实践系统设计的一些原则海恩法则墨菲定律警示软件架构中的高可用设计什么是高可用可用性度量和考核如何保障系统的高可用?负载均衡DNS&nginx负载均衡upstream配置负载...
  • 简介:阿里巴巴在多年双11并发、可用和客户体验要求背景下积累了相应的技术体系,本文将依据并发用户、突发流量场景下的真实案例,分享阿里在高可用架构建设过程中的经验总结,以期待帮助更多企业做好业务...
  • zabbix高可用架构

    2021-03-19 23:45:44
    zabbix监控从理论上来说,为了避免单点故障是需要配置高可用的。架构如下: 架构说明: 1、主备机通过inotify+rsync实现zabbix server端配置文件同步; 2、通过mysql主主复制实现数据同步; 3、同一时刻只有一台...
  • 系统架构高可用

    2021-09-27 11:03:41
    文章目录系统架构之高可用系统可用性的度量与考核高可用的系统架构高可用的应用通过负载均衡进行无状态的失效转移应用服务器集群的 Session 管理Session 复制Session 绑定利用 Cookie 记录 SessionSession 服务器高...
  • 高可用HA(High Availability)是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。 假设系统一直能够提供服务,我们说系统的可用性是100%。 如果系统每运行100个时间单位...
  • 基于LVS高可用架构实现Nginx集群分流

    千次阅读 2021-11-03 14:37:26
    本篇文章会继续讲解重要的概念 lvs高可用框架,怎么利用虚拟服务,使得nginx高可用,以及 负载均衡策略;基于Keepalived实现LVS高可用,负载均衡器LVS跟Nginx差别 也是源自对应请求量并发的情况才 nginx集群...
  • 企业架构LNMP高可用负载均衡服务器之Nginx一、背景描述及其方案设计1、业务背景描述2、模拟运维设计方案二、服务器基本环境部署1、克隆复制虚拟机2、基础环境配置三、负载均衡服务器搭建1、引入负载均衡技术2、负载...
  • zabbix高可用 1.zabbix高可用方案 高可用最常用的方案就是服务+keepalived,但是zabbix-server不能再两台机器上同时启动,因为配置了高可用后,我们对外提供的访问地址一定是keepalive的vip地址,vip只会把请求转发...
  • 云主机:鲲鹏云服务器Linux系统版本:NeoKylin Linux Advanced Server release V7Update6 (Chromium)MySQL源码版本:mysql-8.0.18keepalived版本:keepalived-1.3.5-6.el7.aarch64数据库架构元素IP地址DB1主机10.0....
  • 综合架构-高可用服务

    千次阅读 2021-11-07 11:49:52
    综合架构-高可用服务高可用服务介绍说明高可用服务工作原理如何实现部署高可用服务高可用keepalived服务部署流程高可用服务企业应用高可用服务常见异常问题 ----脑裂问题**如何实现keepalived自动释放vip地址资源***...
  • 爱奇艺高可用性能服务器编程架构实践2017.11背景• 对于可靠、高可用框架的要求• 1、应用服务的不间断性 :• 1.1、服务程序可在线热升级• 1.2、数据及配置可在线重新加载• 2、应用服务可运维可监控 :• 2.1...
  • 双点服务器HA架构双点服务器HA架构介绍(实现高可用高可用服务搭建介绍HA高可用keepalived 软件介绍keepalived组成和原理安装配置启动keepalived实现Web 服务高可用前置部署第一步: 双点服务器HA架构介绍(实现...
  • 高可用架构

    2021-03-03 23:34:51
    基于实际生产环境,从云原生平台集群的可用技术、传统技术的可用Linux集群构建、MySQL高可用架构设计等角度展现Linux集群之美! 【本书的主要内容和特色】 *基于真实的电子商务系统和CDN系统着重介绍了Nginx/...
  • 如果我们已经优化了SQL,但是读依旧还是瓶颈时,这时就可以选择“读写分离”架构了。 读写分离首先需要将数据库分为主从库,一个主库用于写数据,多个从库完成读数据的操作,主从库之间通过主从复制机制进行数据的...
  • #web 端口 "ListenAddress": ":3000", #被管理数据库用户 "MySQLTopologyUser": "orc_client_user", #被管理数据库密码 "MySQLTopologyPassword": "orc_client_password", #被管理的MySQL的用户密码配置文件 ...
  • Keepalive 高可用集群概述前言一、高可用集群技术二、Keepalived故障切换转移原理 -- VRRP三、Keepalive 的功能1、LVS directors failover2、LVS cluster nodes healthchecks 前言 我们通过LVS、Nginx、Haproxy可以...
  • 高可用: 任何时候项目都必须可用 可升缩: 大促,流量瞬间增大…. 可扩展: 开发角度(新需求进行迭代),扩展 安全性: 网络安全,硬件安全,软件安全 敏捷性: 可持续交付,可持续部署 性能 什么是性能? 较...
  • 1. Keepalived 简介 1. keepalived 的作用 Keepalived 的作用是检测服务器的状态。如果有一台 web 服务器宕机,或...
  • Part1 从0开始手把手实战Android Webview独立进程通信架构(上) 1、H5会替代Native么? 2、H5和Native的使用场景; 3、Webview和App其他组件的关系和通信; 4、WebView模块搭建; 5、WebView模块组件化; 6、...
  • 文章目录项目名称:基于keepalived的双vip高可用web集群架构图项目环境:CentOS 8.2(8台 1核1G),ansible 2.9.17,keepalived 2.0.10,Nginx 1.19.7,NFS项目描述:       &...
  • 架构_Deegue-CSDN博客_前端负载均衡火种培训,听了前端的架构分享,突然想知道前端是怎么处理并发,负载均衡的。网上找了一下,转载分享~---------------------------------------------------------------------...
  • LVS + Keepalived 高可用高性能负载均衡案例实战 前言 一、架构设计 二、环境准备 三、案例部署 四、测试 1、Keepalived 健康检查 2、Keepalived MASTER/BACKUP 切换 前言 Keepalived 作为一个性能的集群高可用...
  • rocketMQ组织架构①:NameServer②:Broker③:Producer**④:Consumer 1. MQ产品介绍          1.1 什么是MQ?为什么要用MQ?       &...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 198,815
精华内容 79,526
关键字:

web高可用架构