网站优化

面对并发是如何优化网站性能的?

每个项目都会随着用户和数据的增长调整架构,来面对未来的问题

随着用户的增加,平台开始变得卡顿,开始了问题排查和优化,下面就和大家聊聊是如何处理的吧。

Nginx

一个网站,核心会分为几部分:前端、后台服务、数据库,服务器。

我们最开始项目是打的jar包 ,一个tomcat支撑不了多少并发,

Tomcat 默认配置的最大请求数是 150,也就是说同时支持 150 个并发,当然了,也可以将其改大。所以只能开始搭建集群。

搭建集群后引入了Nginx做反向代理,负载均衡也解决了,根据不同的服务器的性能做了权重,

果然增加了Nginx,做了负载之后,网站访问快了不少。

但是又迎来了Session共享的问题,我们将用户的会话信息放入redis,session共享搞定。

或者使用IPHash

IPhash对客户端请求的IP进行hash操作,然后根据hash结果将同一个客户端ip的请求分发给同一台服务器进行处理,可以解决session不共享的问题。

接入层搞定了之后,发现论坛模块还是很慢。

慢SQL

开始排查日志,发现了一些SQL处理竟然要大于1S。

根本问题是做了联表查询,关联的表比较多,于是我们开始优化数据库结构,增加了许多冗余字段,

后面只用查询一个表了,从蜗速到现在几乎秒开了。

关于分类

从数据库查询优化到使用静态数据管理,因为几乎不会发生变化。

主从复制、读写分离

接入层的问题解决后,发现项目的压力瓶颈转移到了数据库上面,

开始还是单个数据库,但是读和写都在一个数据库,性能完全不太够用,

于是又用一台服务器开始做主从(吐槽:果然只要有钱,问题就好解决一些了),

MySQL的主从还是比较简单的,几个命令就搭建好了,然后我们使用了sharding jdbc来做读写分离。

写完之后,网站整体的性能都提高了。

mysql配置主从数据库

1.修改主服务器master:

  #vi /etc/my.cnf
   [mysqld]
   log-bin=mysql-bin   //[必须]启用二进制日志
   server-id=222      //[必须]服务器唯一ID,默认是1,一般取IP最后一段

2.修改从服务器slave:

   #vi /etc/my.cnf
   [mysqld]
   log-bin=mysql-bin   //[不是必须]启用二进制日志
   server-id=226      //[必须]服务器唯一ID,默认是1,一般取IP最后一段

3.重启两台服务器的mysql

service mysqld restart;

4.在主服务器上建立帐户并授权slave:

   #/usr/local/mysql/bin/mysql -uroot -pmttang   
   mysql>GRANT REPLICATION SLAVE ON *.* to 'mysync'@'%' identified by 'password'; //一般不用root帐号

“%”表示所有客户端都可能连,只要帐号,密码正确,此处可用具体客户端IP代替,如192.168.145.226,加强安全。

5.登录主服务器的mysql,查询master的状态

   mysql>show master status;
   +------------------+----------+--------------+------------------+
   | File             | Position | Binlog_Do_DB | Binlog_Ignore_DB |
   +------------------+----------+--------------+------------------+
   | mysql-bin.000004 |      308 |              |                  |
   +------------------+----------+--------------+------------------+
   1 row in set (0.00 sec)

注:执行完此步骤后不要再操作主服务器MYSQL,防止主服务器状态值变化

6.配置从服务器Slave

   mysql>change master to master_host='192.168.145.222',master_user='username',master_password='password',
         master_log_file='mysql-bin.000004',master_log_pos=308;   //注意不要断开,308数字前后无单引号。
   Mysql>start slave;    //启动从服务器复制功能

7.检查从服务器复制功能状态:

 mysql> show slave status\G

   *************************** 1. row ***************************

              Slave_IO_State: Waiting for master to send event
              Master_Host: 192.168.2.222  //主服务器地址
              Master_User: mysync   //授权帐户名,尽量避免使用root
              Master_Port: 3306    //数据库端口,部分版本没有此行
              Connect_Retry: 60
              Master_Log_File: mysql-bin.000004
              Read_Master_Log_Pos: 600     //#同步读取二进制日志的位置,大于等于Exec_Master_Log_Pos
              Relay_Log_File: ddte-relay-bin.000003
              Relay_Log_Pos: 251
              Relay_Master_Log_File: mysql-bin.000004
              Slave_IO_Running: Yes    //此状态必须YES
              Slave_SQL_Running: Yes     //此状态必须YES
                    ......

注:Slave_IO及Slave_SQL进程必须正常运行,即YES状态,否则都是错误的状态(如:其中一个NO均属错误)。

以上操作过程,主从服务器配置完成。

Sharding-JDBC实现读写分离

技术选型:SpringBoot + Sharding-JDBC + MyBatis

使用Sharding-JDBC配置读写分离,优点在于数据源完全有Sharding托管,写操作自动执行master库,读操作自动执行slave库。不需要程序员在程序中关注这个实现了。

1. 核心jar包

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.6.RELEASE</version>
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <!-- sharding -->
    <dependency>
        <groupId>org.apache.shardingsphere</groupId>
        <artifactId>sharding-jdbc-spring-boot-starter</artifactId>
        <version>4.0.0-RC1</version>
    </dependency>
    <!-- mybatis-plus -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.2.0</version>
    </dependency>
    <!--阿里数据库连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.14</version>
    </dependency>
    <!-- mysql -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.18</version>
     </dependency>
     <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.60</version>
     </dependency>
 </dependencies>

2. yml文件配置

spring:
  main:
    allow-bean-definition-overriding: true
  shardingsphere:
    datasource:
      names:
        master,slave
      # 主数据源
      master:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_master?characterEncoding=utf-8
        username: ****
        password: ****
      # 从数据源
      slave:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/db_slave?characterEncoding=utf-8
        username: ****
        password: ****
    masterslave:
      # 读写分离配置, 用于配置从库负载均衡算法类型,可选值:ROUND_ROBIN(轮询),RANDOM(随机)
      load-balance-algorithm-type: round_robin
      # 最终的数据源名称
      name: dataSource
      # 主库数据源名称
      master-data-source-name: master
      # 从库数据源名称列表,多个逗号分隔
      slave-data-source-names: slave
    props:
      # 开启SQL显示,默认false,在执行SQL时,会打印SQL,并显示执行库的名称
      sql:
        show: true

问题:读写分离架构中经常出现,那就是读延迟的问题如何解决?

刚插入一条数据,然后马上就要去读取,这个时候有可能会读取不到?

归根到底是因为主节点写入完之后数据是要复制给从节点的,读不到的原因就是说数据还没复制到从节点,你就已经去从节点读取了,肯定读不到。

mysql5.7 的主从复制是多线程了,意味着速度会变快,但是不一定能保证百分百马上读取到,这个问题我们可以有两种方式解决:

  (1)是否立马读取,业务层面妥协,是否操作完之后马上要进行读取

  (2)控制是否直接走主库,对于操作完马上要读出来的,且业务上不能妥协的,我们可以对于这类的读取直接走主库,当然Sharding-JDBC也是考虑到这个问题的存在,所以给我们提供了一个功能,可以让用户在使用的时候指定要不要走主库进行读取。在读取前使用下面的方式进行设置就可以了:

public List<UserInfo> getList() {
        // 强制路由主库
        HintManager.getInstance().setMasterRouteOnly();
        return this.list();
    }
posted @ 2021-08-19 13:27  Ricardo_ML  阅读(110)  评论(0编辑  收藏  举报