项目架构简介
服务器两台,一台上面搭载nginx和tomcat1
另一台上有一个tomcat2和redis
ngixn集群下图片上传的问题:当图片上传到tomcat1下,再次请求图片的时候nginx有可能把请求转发到tomcat2上,导致获取不到图片
解决方案:用tomcat1作为一台图片服务器,利用ftp将图片都上传到tomcat1下,配置nginx图片转发路径到tomcat1下。
nginx配置
location / {
proxy_pass http://tomcat_server;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
root /usr/share/nginx/html;
index index.html index.htm;
}
location ~ .*\.(gif|jpg|jpeg|png)$ {
proxy_pass http://127.0.0.1:8080;
}
ftp配置文件
ftp_host=192.168.0.116
ftp_port=22
ftp_username=shuheng
ftp_password=sh123456
ftp_path=/usr/tomcat8/apache-tomcat-8.5.24/webapps/SHYL/
ftp_timeout=500000
ftp_init_pool_size=1
ftp_max_pool_size=10
sshsession连接池代码,因为每次连接时间都特别长,所以写了一个连接池.
尝试过使用反射,在session 调用 disconnect()方法的时候自动将session返回连接池,但是没有成功,可能是因为session继承的是Runnable接口。
package com.shyl.framework.util.ftp;
import java.util.LinkedList;
import java.util.Properties;
import java.util.ResourceBundle;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.shyl.framework.util.Logger;
public class SSHSessionPool {
protected static Logger logger = Logger.getLogger(SSHSessionPool.class);
private static LinkedList<Session> sessionList = new LinkedList<Session>();
private static final ResourceBundle resource = ResourceBundle.getBundle("globalconfig");
//ftp主机地址
private static final String host = resource.getString("ftp_host");
//端口
private static final int port = Integer.valueOf(resource.getString("ftp_port"));
//ftp用户名
private static final String username = resource.getString("ftp_username");
//ftp密码
private static final String password = resource.getString("ftp_password");
//ftp连接超时时间
private static final int timeout = Integer.parseInt(resource.getString("ftp_timeout"));
//初始化session池大小
private static final int initPoolSize = Integer.parseInt(resource.getString("ftp_init_pool_size"));
//session池最大大小
private static final int maxPoolSize = Integer.parseInt(resource.getString("ftp_max_pool_size"));
private static int total = 0;
//静态方法初始化连接池
static{
logger.info("sshsession pool创建开始");
for(int i=0;i<initPoolSize;i++){
Session session = createSession();
sessionList.add(session);
total++;
}
logger.info("sshsession pool创建完成");
}
/**
* 创建session
* @return
*/
private static synchronized Session createSession(){
JSch jsch = new JSch();
Session session = null;
try {
System.out.println("Session creating。。。。。。");
jsch.getSession(username, host, port);
session = jsch.getSession(username, host, port);
session.setPassword(password);
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
session.setConfig(sshConfig);
session.setTimeout(timeout);
session.connect();
System.out.println("Session created");
} catch (JSchException e) {
e.printStackTrace();
}
return session;
}
/**
* 获取session
* 如果连接池用尽,总量小于最大值,继续创建
* @return
*/
public Session getSession(){
Session session = null;
if(sessionList.size()>0){
session = sessionList.removeFirst();
}else{
if(total < maxPoolSize){
session = createSession();
sessionList.add(session);
total++;
}
}
return session;
}
/**
* 释放,将连接还回连接池
* @param session
*/
public void release(Session session){
sessionList.add(session);
}
public int poolSize() {
return sessionList.size();
}
}
配置在spring环境中,这样在tomcat启动的时候会变慢,但是用户上传图片的时候变快了
<bean id="sshSessionPool" class="com.shyl.framework.util.ftp.SSHSessionPool"></bean>
上传工具类
package com.shyl.framework.util.ftp;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ResourceBundle;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.SftpException;
import com.shyl.framework.util.Logger;
public class SFtpUtil {
protected static Logger logger = Logger.getLogger(SFtpUtil.class);
public static final ResourceBundle resource = ResourceBundle.getBundle("globalconfig");
public static String basePath = resource.getString("ftp_path");
/**
* 连接sftp服务器
* @param host 主机
* @param port 端口
* @param username 用户名
* @param password 密码
* @return
*/
public static ChannelSftp connect(Session session) {
ChannelSftp sftp = null;
try {
if(session.isConnected()){
Channel channel = session.openChannel("sftp");
channel.connect();
sftp = (ChannelSftp) channel;
System.out.println("Connected to " + session.getHost());
}
} catch (Exception e) {
e.printStackTrace() ;
}
return sftp;
}
/**
* 上传文件
* @param directory 上传的目录
* @param uploadFile 要上传的文件
* @param sftp
* @throws SftpException
*/
public static void upload(String directory, InputStream input,String fileName, ChannelSftp sftp) throws SftpException {
try {
sftp.ls(directory);
} catch (Exception e) {
sftp.mkdir(directory);
}
sftp.cd(directory);
sftp.put(input, fileName);
System.out.println("上传 完毕");
}
/**
* 下载文件
* @param directory 下载目录
* @param downloadFile 下载的文件
* @param saveFile 存在本地的路径
* @param sftp
*/
public static void download(String directory, String downloadFile,String saveFile, ChannelSftp sftp) {
try {
sftp.cd(directory);
File file=new File(saveFile);
sftp.get(downloadFile, new FileOutputStream(file));
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除文件
* @param directory 要删除文件所在目录
* @param deleteFile 要删除的文件
* @param sftp
*/
public static void delete(String directory, String deleteFile, ChannelSftp sftp) {
try {
sftp.cd(directory);
sftp.rm(deleteFile);
} catch (Exception e) {
e.printStackTrace();
}
}
// public static void main(String[] args) throws FileNotFoundException, SftpException {
// ChannelSftp channelSftp = SFtpUtil.connect();
// File file = new File("D://aaa.txt");
// FileInputStream fileInputStream = new FileInputStream(file);
//
// SFtpUtil.upload("/usr/tomcat8/apache-tomcat-8.5.24/webapps/SHYL/uploadFiles/wechat4", fileInputStream,"ccc", channelSftp);
// //new ImageUtil().resize(ctxPath + fileName, 0.5);
// }
}
上传代码
@Resource(name = "sshSessionPool")
private SSHSessionPool sshSessionPool;
@RequestMapping(value = "/Upload")
@ResponseBody
public void upload(HttpServletResponse response,
HttpServletRequest request) throws IOException, SftpException {
// 图片路径
String imgPath = Const.BLANK;
// 图片名称
String fileName = null;
// 图片后缀
String fileExt = null;
// 文件格式错误信息
String fileExtError = null;
MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
PrintWriter pw=response.getWriter();
for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
// 上传文件
MultipartFile mf = entity.getValue();
// 获取图片大小
int picSize = Integer.parseInt(String.valueOf(mf.getSize()));
// 获取原文件名
fileName = mf.getOriginalFilename();
// 获取图片后缀
fileExt = fileName.substring(fileName.lastIndexOf(".")+1).toLowerCase();
if(!Const.JPG.equals(fileExt) && !Const.PNG.equals(fileExt) && !Const.JPEG.equals(fileExt) && !Const.GIF.equals(fileExt)){
fileExtError = "no";
pw.write(fileExtError);
} else if(picSize > Const.INT_TEN_MB){
fileExtError = "nosize";
pw.write(fileExtError);
} else {
// 对原文件名进行重命名
fileName = this.get32UUID()+"."+fileExt;
// 返回图片路径
imgPath = Const.FILMPATH + fileName;
try {
//上传至ftp
logger.info("获取前"+sshSessionPool.poolSize());
com.jcraft.jsch.Session session = sshSessionPool.getSession();
ChannelSftp sftp = SFtpUtil.connect(session);
logger.info("获取后"+sshSessionPool.poolSize());
SFtpUtil.upload(SFtpUtil.basePath+Const.FILMPATH, mf.getInputStream(),fileName, sftp);
sshSessionPool.release(session);
logger.info("归还后"+sshSessionPool.poolSize());
// new ImageUtil(ctxPath + fileName).resize(ctxPath + fileName, 0.5);
pw.write(imgPath);
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
备注:jcraft官网:http://www.jcraft.com/jsch/
使用的是jsch-0.1.54.jar这个版本
在maven上下载过0.1.50这个版本,总是报session is down的错误