• 网站性能优化小结和spring整合redis


    现在越来越多的地方需要非关系型数据库了,最近网站优化,当然从页面到服务器做了相应的优化后,通过在线网站测试工具与之前没优化对比,发现有显著提升。

    服务器优化目前主要优化tomcat,在tomcat目录下的server.xml文件配置如下内容:

    <Connector port="1818"
      protocol="HTTP/1.1"
      maxHttpHeaderSize="8192"
      maxThreads="1000"
      minSpareThreads="100"
      maxSpareThreads="1000"
      minProcessors="100"
      maxProcessors="1000"
      enableLookups="false"
      compression="on"
      compressionMinSize="2048"
    compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain"
      connectionTimeout="20000"
      URIEncoding="utf-8"
      acceptCount="1000"
      redirectPort="8443"
      disableUploadTimeout="true"/>
    
    参数说明:
    Protocol  采用的协议//可将HTTP/1.1改为org.apache.coyote.http11.Http11NioProtocol 启动NIO模式
    maxHttpHeaderSize 代表请求和响应的HTTP首部的最大长度,单位是字节。如果不指定,该属性将被设为4096(4K)。
    maxThreads 客户请求最大线程数 
      minSpareThreads Tomcat初始化时创建的 socket 线程数 
      maxSpareThreads Tomcat连接器的最大空闲 socket 线程数 
      enableLookups 若设为true, 则支持域名解析,可把 ip 地址解析为主机名 
      redirectPort 在需要基于安全通道的场合,把客户请求转发到基于SSL 的 redirectPort 端口 
      acceptAccount 监听端口队列最大数,满了之后客户请求会被拒绝(不能小于maxSpareThreads ) 
      connectionTimeout 连接超时 
      minProcessors 服务器创建时的最小处理线程数 
      maxProcessors 服务器同时最大处理线程数 
      URIEncoding URL统一编码
    compression 打开压缩功能 
      compressionMinSize 启用压缩的输出内容大小,这里面默认为2KB 
      compressableMimeType 压缩类型 
      connectionTimeout 定义建立客户连接超时的时间. 如果为 -1, 表示不限制建立客户连接的时间
    

     

    网站性能优化,参照了《高性能网站建设指南》这本书和部分知识博客

    就我们项目而言,我参照这本书,按照这么几个规范进行,书上提出了,优化十四个建议,不过,并不是十四建议通通采纳,网站性能一定能上升的非常好,要结合项目的实际情况。

    这是我们采取的前端性能优化措施:

    1.减少http请求 比如外部的css,js和图片等组件,访问一个网站时,这些组件都会被加载,组件过多,加载时间长,特别是图片等,所以减少http请求,可有效提高网站性能

    2.头部引用外部css和底部引用js 初次点击进入网站,网站的背景图和其他非js效果的css效果会最先加载,j如果不放在头部的话,首先看到的就是空白,然后就有相应的css渲染效果,底部引用js,在视觉上让用户觉得加载快了,而且外部的css和js方便管理,内联的js和css过度使用,会导致页面代码重构和后续其他人开发,会比较吃力。同时这样做也是一种很好的规范。js放在尾部也就是</body>标签前,它会被最后加载,如果统统放在<head></head>下,并行加载,会导致阻塞后面文件的下载和会导致后面的css渲染变慢。因此放在尾部是比较好的选择。

    3.压缩组件。目前通过tomcat中的上述配置实行gzip压缩

    4.合并css和js文件 大家要知道加载一个js和加载两个js文件的速度完全是不一样的,尽快前者js文件的容量大于后者两个。总之一个请求的速度总会大于两个请求的速度。

    从http请求的角度解析,客户端发出请求给服务器,服务器响应数据返回给客户端。一个请求到响应的速度始终大于两个请求。还是回到之前的减少http请求。另外合并不代表一个无关的js和另外好几个无关js合在一起,这样不利于后面管理,合并应该是相关js函数合在一起,不相关js文件如果内容很多,可不必合并,如果只有单独的一两个函数,可与另外一两个函数合并,切记要写注释,同时合并js,不可合并过多

    后台采取的措施:

    1.sql优化 查询尽量查出符合需要的字段,严禁用*,同时in和not in尽可能用exists和not exists替换等

    2.Java代码复用,减少冗余,特别是后台很多重复的service,将其公共通用部分写成一个函数,以供用到的Controller进行复用(当然这对于优化网站性能方面,可能帮助不大,但有利于后续开发的进行)

    下面进行正式的spring整合redis:

    为什么要用redis?

    就目前我们项目而言,打开pms后台加载过慢,当然原因包括没用的js过多引用进来加载时间长,自然速度慢,频繁的http请求,布局不合理(js全部放在头部),sql没有优化等。

    上述问题都可以解决。

    回到上述问题,为什么使用redis。使用redis做缓存,R可以将所有的数据先保存到缓存中,然后再存入mysql中,减小数据库压力,提高效率 。

    redis为什么访问数据的速度大于mysql?

    因为前者访问的是内存,后者是磁盘

    因为cpu是直接与内存进行数据交互的

    演示实例:

    注意ssm框架,jdk8,tomcat8服务器

    一、pom依赖

            <!-- redis -->
             <dependency>  
                <groupId>redis.clients</groupId>  
                <artifactId>jedis</artifactId>  
                <version>2.1.0</version>  
            </dependency>
            <!-- spring-data-redis -->
             <dependency>
                    <groupId>org.springframework.data</groupId>
                  <artifactId>spring-data-redis</artifactId>
                 <version>1.0.2.RELEASE</version>
            </dependency>
                <!-- mybatis-ehcache -->
            <dependency>
                <groupId>org.mybatis.caches</groupId>
                <artifactId>mybatis-ehcache</artifactId>
                <version>1.0.3</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.24</version>
            </dependency>

    二、对应的application-config.xml配置

     <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
            <property name="maxIdle" value="1000" />
            <property name="testOnBorrow" value="true"/>
        </bean>
    
    <!-- 连接池配置,类似数据库连接池 -->
        <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
            <property name="hostName" value="192.168.126.128"></property>
            <property name="port" value="6379"></property>
            <property name="password" value="123456"></property>
            <property name="poolConfig"  ref="poolConfig"></property> 
            
        </bean>
    
        <!-- 调用连接池工厂配置 -->
        <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
            <property name="connectionFactory" ref="connectionFactory"></property>
    
           <!--  如果不配置Serializer,那么存储的时候智能使用String,如果用User类型存储,那么会提示错误User can't cast   
            to String!!!   -->
             <property name="keySerializer">  
                <bean  
                class="org.springframework.data.redis.serializer.StringRedisSerializer" />  
            </property>  
            <property name="valueSerializer">  
                <bean  
                    class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />  
            </property> 
    </bean>
     
    
        
    
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> 
            <!-- 基本属性 url、user、password -->
            <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
            <property name="url" value="jdbc:mysql://localhost:3306/test" />
            <property name="username" value="root" />
            <property name="password" value="1234" />
            <property name="filters" value="stat,config" />
            
            <!-- 配置初始化大小、最小、最大 -->
            <property name="initialSize" value="1" />
            <property name="minIdle" value="1" /> 
            <property name="maxActive" value="40" />
         
            <!-- 配置获取连接等待超时的时间 -->
            <property name="maxWait" value="60000" />
         
            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis" value="60000" />
         
            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis" value="300000" />
          
            <property name="validationQuery" value="SELECT 'x' FROM DUAL" />
            <property name="testWhileIdle" value="true" />
            <property name="testOnBorrow" value="false" />
            <property name="testOnReturn" value="false" />
         
            <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
            <property name="poolPreparedStatements" value="true" />
            <property name="maxPoolPreparedStatementPerConnectionSize" value="20" />
            
            <!-- 超过时间限制是否回收 --> 
            <property name="removeAbandoned" value="true" /> 
            <!-- 超时时间;单位为秒。180秒=3分钟 --> 
            <property name="removeAbandonedTimeout" value="180" /> 
            <!-- 关闭abanded连接时输出错误日志 --> 
            <property name="logAbandoned" value="true" />
         
            <!-- 配置监控统计拦截的filters,去掉后监控界面sql无法统计 -->
            <!-- property name="filters" value="stat" /--> 
        </bean>
        
    
        

    三、JavaBean

    记得一定要实现序列化,否则会报错

    package com.tp.soft.entity;
    
    import java.io.Serializable;
    
    public class User implements Serializable{
    
        /**
         * 
         */
        private static final long serialVersionUID = -1695973853274402680L;
        
        private int userid;
        
        private String login_name;
        
        private String login_pwd;
    
        
        public User() {
            
        }
    
    
        public User(int userid, String login_name, String login_pwd) {
            super();
            this.userid = userid;
            this.login_name = login_name;
            this.login_pwd = login_pwd;
        }
    
    
        public int getUserid() {
            return userid;
        }
    
    
        public void setUserid(int userid) {
            this.userid = userid;
        }
    
    
        public String getLogin_name() {
            return login_name;
        }
    
    
        public void setLogin_name(String login_name) {
            this.login_name = login_name;
        }
    
    
        public String getLogin_pwd() {
            return login_pwd;
        }
    
    
        public void setLogin_pwd(String login_pwd) {
            this.login_pwd = login_pwd;
        }
    
    
    }

    四、接口类

    package com.tp.soft.dao;
    
    import com.tp.soft.entity.User;
    
    public interface UserMapper {
        public User getUserById(int id);
    }

    五、接口对应的xml文件

    <?xml version="1.0" encoding="UTF-8" ?>  
    <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
    <mapper namespace="com.tp.soft.dao.UserMapper">
        <!-- 缓存类配置 -->
        <cache type="com.tp.soft.redis.RedisCache" />
        
        <select id="getUserById" parameterType="int" resultType="user" useCache="true"> 
            select * from AU_USER where userid = #{id}
        </select>
    </mapper>

    六、mybatis-config.xm配置

    <?xml version="1.0" encoding="UTF-8"?>  
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"  
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <settings>
         
            <!-- 二级缓存开启 -->
            <setting name="cacheEnabled" value="true"/>
            <setting name="lazyLoadingEnabled" value="false"/>
            <setting name="aggressiveLazyLoading" value="true"/>
        </settings>
        <!-- 配置映射类的别名 -->
        
        <typeAliases>
            <!-- 配置entity下的所有别名 别名首字母小写 -->
            <package name="com.tp.soft.entity" />
        </typeAliases>
    </configuration>

    七、service和service实现类

    package com.tp.soft.service;
    
    import com.tp.soft.entity.User;
    
    public interface UserSvc {
        public User getUser(int id);
    }
    package com.tp.soft.service.impl;
    
    import javax.annotation.Resource;
    
    import org.springframework.dao.DataAccessException;
    import org.springframework.stereotype.Service;
    
    import com.tp.soft.dao.UserMapper;
    import com.tp.soft.entity.User;
    import com.tp.soft.service.UserSvc;
    
    @Service("userService")
    public class UserSvcImpl implements UserSvc{
    
        @Resource
        private UserMapper userMapper;
        
        public User getUser(int id) {
            User user = null;
            try{
                user = userMapper.getUserById(id);
            }catch (DataAccessException e) {
                System.out.println(e.getLocalizedMessage());
            }
            return user;
        }
    
    }

    八、Controller

    package com.tp.soft.controller;
    
    
    
    import javax.annotation.Resource;
    
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import com.tp.soft.entity.User;
    import com.tp.soft.service.UserSvc;
    
    @Controller
    public class UserController {
        
        @Resource
        private UserSvc userSvc;
        
        @RequestMapping(value="/QueryUser")
        public String toQueryUser(int id,Model model){
     
            
            User user = userSvc.getUser(id);
    
            System.out.println(user.getLogin_name());
            model.addAttribute("user", user);
            return "/pc/userTest";
        }
    }

    九、需用到的util

    package com.tp.soft.redis;
    
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    public class JedisUtil {
        private static String ADDR = "192.168.126.128";
        private static int PORT = 6379;
        private static String AUTH = "123456";
        
        private static int MAX_ACTIVE = 1024;
        
        private static int MAX_IDLE = 200;
        
        private static int MAX_WAIT = 10000;
        
        private static int TIMEOUT = 10000;
        
        private static boolean TEST_ON_BORROW = true;
        
        private static JedisPool jedisPool = null;
        
        static {
            try{
                JedisPoolConfig config = new JedisPoolConfig();
                config.setMaxIdle(MAX_IDLE);
    
                config.setTestOnBorrow(TEST_ON_BORROW);
                jedisPool = new JedisPool(config,ADDR,PORT,TIMEOUT,AUTH);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        public synchronized static Jedis getJedis(){
            try{
                if(jedisPool != null){
                    Jedis jedis = jedisPool.getResource();
                    return jedis;
                }else{
                    return null;
                }
            }catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }
        
        public static void returnResource(final Jedis jedis){
            if(jedis != null){
                jedisPool.returnResource(jedis);
            }
        }
    }
    package com.tp.soft.redis;
    
    import java.util.concurrent.locks.ReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    
    import org.apache.ibatis.cache.Cache;
    
    /*
     * 使用第三方缓存服务器,处理二级缓存
     */
    public class RedisCache implements Cache {
        private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    
        private String id;
    
        public RedisCache(final String id) {
            if (id == null) {
                throw new IllegalArgumentException("Cache instances require an ID");
            }
            this.id = id;
    
        }
    
        public String getId() {
            return this.id;
        }
    
        public void putObject(Object key, Object value) {
            JedisUtil.getJedis().set(SerializeUtil.serialize(key.toString()),
                    SerializeUtil.serialize(value));
    
        }
    
        public Object getObject(Object key) {
            Object value = SerializeUtil.unserialize(JedisUtil.getJedis().get(
                    SerializeUtil.serialize(key.toString())));
            return value;
    
        }
    
        public Object removeObject(Object key) {
            return JedisUtil.getJedis().expire(
                    SerializeUtil.serialize(key.toString()), 0);
    
        }
    
        public void clear() {
            JedisUtil.getJedis().flushDB();
        }
    
        public int getSize() {
            return Integer.valueOf(JedisUtil.getJedis().dbSize().toString());
        }
    
        public ReadWriteLock getReadWriteLock() {
            return readWriteLock;
        }
    
    }
    package com.tp.soft.redis;
    
    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class SerializeUtil {
        public static byte[] serialize(Object object) {
            ObjectOutputStream oos = null;
            ByteArrayOutputStream baos = null;
            try {
                // 序列化
                baos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(baos);
                oos.writeObject(object);
                byte[] bytes = baos.toByteArray();
                return bytes;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static Object unserialize(byte[] bytes) {
            if (bytes == null)
                return null;
            ByteArrayInputStream bais = null;
            try {
                // 反序列化
                bais = new ByteArrayInputStream(bytes);
                ObjectInputStream ois = new ObjectInputStream(bais);
                return ois.readObject();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    十、演示效果

    目前本人也是刚刚用到没多久,如果那里有问题,欢迎大家指教

    其实性能的瓶颈和mysql有关系,目前对于mysql相关的原理等不是特别了解,需后面多加努力学习

  • 相关阅读:
    arm64 boot
    python学习笔记
    字符编码问题详解
    Restful 架构设计
    调度器学习总结
    从0开始学习maven搭建spring+mybatis框架
    java内存管理
    linux 基础
    自学有感
    echart 图表显示技术
  • 原文地址:https://www.cnblogs.com/youcong/p/8511735.html
Copyright © 2020-2023  润新知