发表于: 2017-10-24 23:17:28

3 744


一.今日完成

1.把任务5发布到线上的项目bug排除,解决了页面跳转出现的404错误,在controller类返回的逻辑视图名里加入项目名称,同时把JSP页面的<form action>标签中内嵌<c:url>标签,实现了注册.登录等功能的连续性.(http://www.jnshujavatask.com:8080/quagga/student/home)

2.重新把nginx的负载均衡知识点梳理了一遍

Nginx的负载均衡功能依赖于ngx_http_upstream_module模块,所支持的代理方式有proxy_pass,fastcgi_pass,memcached_pass。

Nginx常用负载均衡算法:

(1)轮询(默认算法)——每个请求会依次分配给后端不同的应用程序服务器,不理会后端服务器的实际压力

(2)加权轮询——权重越大的服务器,被分配到的次数就会越多,通常用于后端服务器性能不一致的情况

(3)IP HASH——当同IP进行重复访问时会被指定到上次访问到的服务器,可以解决动态网站SESSION共享问题

实现方法:  

vim /usr/local/nginx/nginx.conf

默认的负载均衡:

http {        

    upstream jnshujavatask{        

        server 39.108.61.3;      

        server 120.78.25.115;       

    }

    server {

        listen 80;

        server name www.jnshujavatask.com;

        location / {

            proxy_pass http://39.108.61.3;      

        }

    }

}

加权负载均衡:

http {        

    upstream jnshujavatask{        

        server 39.108.61.3  weight=3 ;      

        server 120.78.25.115;       

    }

    server {

        listen 80;

        server name www.jnshujavatask.com;

        location / {

            proxy_pass http://39.108.61.3;      

        }

    }

}

在上面配置中,每3个请求分配给39.108.61.3 ,然后第4个请求会分配给120.78.25.115,如此循环下去。

IP HASH负载均衡:

upstream linuxidc {

    ip_hash;        #采用IP HASH算法    

        server 39.108.61.3;      

        server 120.78.25.115; 

}

如果需要将客户与后端一台服务器“绑定”起来,可以使用ip-hash负载平衡机制。这样可以确保来自相同客户机的请求总是指向相同的服务器除非该服务器不可用。

Nginx高可用的实现,利用backup标签,可以实现高可用,当主服务挂掉后,backup服务器会自动接管服务,当主服务恢复后,backup也会自动放弃服务

http {        

    upstream jnshujavatask{        

        server 39.108.61.3;      

        server 120.78.25.115  backup ;       

    }

    server {

        listen 80;

        server name www.jnshujavatask.com;

        location / {

            proxy_pass http://39.108.61.3;      

        }

    }

}

3.对登录功能进行并发测试,把线程组分别设置为100,200,300,500,1000,以下是结果表:

4.整合memcached到spring,创建memcached工具类,使用@Conponent注解将其标注为一个Bean,以便实现属性注入

@Component
public class MemcachedUtil {
private  static Logger logger= LoggerFactory.getLogger(MemcachedUtil.class);
private static MemCachedClient cachedClient;
static {
if (cachedClient == null)
cachedClient = new MemCachedClient();
}

private MemcachedUtil() {
}

/**
    * 向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @return
    */
   public static boolean set(String key, Object value) {
return setExp(key, value, null);
}

/**
    * 向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   public static boolean set(String key, Object value, Date expire) {
return setExp(key, value, expire);
}

/**
    * 向缓存添加新的键值对。如果键已经存在,则之前的值将被替换。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   private static boolean setExp(String key, Object value, Date expire) {
boolean flag = false;
try {
flag = cachedClient.set(key, value, expire);
} catch (Exception e) {
// 记录Memcached日志
           MemcachedLog.writeLog("Memcached set方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
}
return flag;
}

/**
    * 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @return
    */
   public static boolean add(String key, Object value) {
return addExp(key, value, null);
}

/**
    * 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   public static boolean add(String key, Object value, Date expire) {
return addExp(key, value, expire);
}

/**
    * 仅当缓存中不存在键时,add 命令才会向缓存中添加一个键值对。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   private static boolean addExp(String key, Object value, Date expire) {
boolean flag = false;
try {
flag = cachedClient.add(key, value, expire);
} catch (Exception e) {
// 记录Memcached日志
           MemcachedLog.writeLog("Memcached add方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
}
return flag;
}

/**
    * 仅当键已经存在时,replace 命令才会替换缓存中的键。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @return
    */
   public static boolean replace(String key, Object value) {
return replaceExp(key, value, null);
}

/**
    * 仅当键已经存在时,replace 命令才会替换缓存中的键。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   public static boolean replace(String key, Object value, Date expire) {
return replaceExp(key, value, expire);
}

/**
    * 仅当键已经存在时,replace 命令才会替换缓存中的键。
    *
    * @param key
    *            键
    * @param value
    *            值
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   private static boolean replaceExp(String key, Object value, Date expire) {
boolean flag = false;
try {
flag = cachedClient.replace(key, value, expire);
} catch (Exception e) {
MemcachedLog.writeLog("Memcached replace方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
}
return flag;
}

/**
    * get 命令用于检索与之前添加的键值对相关的值。
    *
    * @param key
    *            键
    * @return
    */
   public static Object get(String key) {
Object obj = null;
try {
obj = cachedClient.get(key);
} catch (Exception e) {
MemcachedLog.writeLog("Memcached get方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
}
return obj;
}

/**
    * 删除 memcached 中的任何现有值。
    *
    * @param key
    *            键
    * @return
    */
   public static boolean delete(String key) {
return deleteExp(key, null);
}

/**
    * 删除 memcached 中的任何现有值。
    *
    * @param key
    *            键
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   public static boolean delete(String key, Date expire) {
return deleteExp(key, expire);
}

/**
    * 删除 memcached 中的任何现有值。
    *
    * @param key
    *            键
    * @param expire
    *            过期时间 New Date(1000*10):十秒后过期
    * @return
    */
   private static boolean deleteExp(String key, Date expire) {
boolean flag = false;
try {
flag = cachedClient.delete(key, expire);
} catch (Exception e) {
MemcachedLog.writeLog("Memcached delete方法报错,key值:" + key + "\r\n" + exceptionWrite(e));
}
return flag;
}

/**
    * 清理缓存中的所有键/值对
    *
    * @return
    */
   public static boolean flashAll() {
boolean flag = false;
try {
flag = cachedClient.flushAll();
} catch (Exception e) {
MemcachedLog.writeLog("Memcached flashAll方法报错\r\n" + exceptionWrite(e));
}
return flag;
}

/**
    * 返回异常栈信息,String类型
    *
    * @param e
    * @return
    */
   private static String exceptionWrite(Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
return sw.toString();
}

/**

    *
    */
   private static class MemcachedLog {
private final static String LINUX_MEMCACHED_LOG = "/home/data/logs/memcached.log";
private static FileWriter fileWriter;
private static BufferedWriter logWrite;
// 获取PID,可以找到对应的JVM进程
       private final static RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
private final static String PID = runtime.getName();

/**
        * 初始化写入流
        */
       static {
try {
String osName = System.getProperty("os.name");
if (osName.indexOf("Windows") !== -1) {
fileWriter = new FileWriter(LINUX_MEMCACHED_LOG, true);
}
logWrite = new BufferedWriter(fileWriter);
} catch (IOException e) {
logger.error("memcached 日志初始化失败", e);
closeLogStream();
}
}

/**
        * 写入日志信息
        *
        * @param content
        *            日志内容
        */
       public static void writeLog(String content) {
try {
logWrite.write("[" + PID + "] " + "- [" + (new Date().getTime()) + "]\r\n"
                       + content);
logWrite.newLine();
logWrite.flush();
} catch (IOException e) {
logger.error("memcached 写入日志信息失败", e);
}
}

/**
        * 关闭流
        */
       private static void closeLogStream() {
try {
fileWriter.close();
logWrite.close();
} catch (IOException e) {
logger.error("memcached 日志对象关闭失败", e);
}
}
}
}

5.创建Jedis工具类

@Component
public class RedisUtil {
//Redis服务器IP
   private static String ADDR = "39.108.61.3";
//Redis的端口号
   private static int PORT = 9966;
//"admin";//访问密码
   private static String AUTH = null;
//可用连接实力的最大数目,默认值为8;如果复制为-1则表示不限制,
   //如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
   private static int MAX_ACTIVE = 1024;
//控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
   private static int MAX_IDLE = 200;
//等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;
   private static int MAX_WAIT = 10000;

private static int TIMEOUT = 10000;
//在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
   private static boolean TEST_ON_BORROW = true;

private static JedisPool jedisPool = null;


static {
try {
JedisPoolConfig config = new JedisPoolConfig();
//config.setMaxActive(MAX_ACTIVE);
           config.setMaxIdle(MAX_IDLE);
config.setMaxWaitMillis(MAX_WAIT);
config.setTestOnBorrow(TEST_ON_BORROW);
jedisPool = new JedisPool(config, ADDR, PORT, TIMEOUT, AUTH);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
    * 获取Jedis实例
    */
   public synchronized static Jedis getJedis() {
try {
if (jedisPool != null) {
Jedis resource = jedisPool.getResource();
return resource;
} else {
return null;
}
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
/**
    * 释放jedis资源
    */
   public static void returnResource(final Jedis jedis) {
if (jedis != null) {
jedisPool.returnResource(jedis);
}
}

}


二.明日计划

1.使用memcached和redis缓存技术,测试高并发环境下服务器性能变化

2.提交任务6


三.遇到问题i

1.nginx反向代理,设置监听8080端口,tomcat服务未启动的前提下,经常提醒8080和80端口被占用;

2.如何在业务逻辑中调用memcached或者Jedis缓存方法好缺少练习.


四.收获

以上.



返回列表 返回列表
评论

    分享到