基於servlet併發的日誌儲存(上)
由於servlet本身就是併發處理的,因此我們只需要處理好對應的呼叫函式就可以了。
考慮到對效率有要求,因此使用一個StringBuffer做緩衝區,將資料儲存在記憶體中,然後定時將資料寫入檔案。基本思路是先將檔名儲存在記憶體中,將url的filename與記憶體中的filename相比較,如果匹配,則向StringBuffer中寫入content內容,如果不匹配,則直接建立檔案,寫入content內容。使用StringBuffer的length作為判斷寫入檔案的條件。
以下是實現程式碼
servlet,簡單的實現了一個對url的控制,便於測試
package savelog.packagename.com;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class SaveLog
*/
@WebServlet("/SaveLog")
public class SaveLog extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public SaveLog() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("UTF-8");
PrintWriter writer = response.getWriter();
writer.println("DIR1:"+request.getParameter("dir1"));
writer.println("DIR2:"+request.getParameter("dir2"));
writer.println("DIR3:"+request.getParameter("dir3"));
writer.println("filename:"+request.getParameter("filename"));
writer.println("content:"+request.getParameter("content"));
writer.println(request.getCharacterEncoding());
if(request.getParameter("dir1")==null){
writer.println("dir1 muxt exist");
return;
}
//String path2=request.getParameter("dir1")+"\\"+request.getParameter("dir2")+"\\"+request.getParameter("dir3");
StringBuilder path=new StringBuilder();
path.append(request.getParameter("dir1"));
if(request.getParameter("dir2")!=null&&!request.getParameter("dir2").equals(""))
path.append("\\"+request.getParameter("dir2"));
if(request.getParameter("dir3")!=null&&!request.getParameter("dir3").equals(""))
path.append("\\"+request.getParameter("dir3"));
String filename=request.getParameter("filename");
String temp=request.getParameter("content");
String content=new String(temp.getBytes("ISO-8859-1"),"UTF-8");
writer.println("Path:"+path);
writer.println("savePath:"+Data.saveLog(path.toString(), filename, content));
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
doGet(request, response);
}
}
Global類,定義全域性變數,儲存在記憶體中。
package savelog.packagename.com;
public class Global {
/*寫日誌緩衝區*/
public static StringBuffer stringBuffer=new StringBuffer();
/*filename標誌*/
public static String filename=new String("");
/*根路徑*/
public static final String rootPath = "e:\\logroot";
}
Date類,業務邏輯類,實現了儲存的業務邏輯
package savelog.packagename.com;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
public class Data {
/**
* 訪問方法(同步)
* @param path
* @param filename
* @param content
* @return
*/
public static synchronized String saveLog(String path, String filename, String content){
if(Global.filename.equals("")){
//第一次訪問,建立檔案
Global.filename=filename;
String savePath=createFile(path,filename,content);
Global.stringBuffer.setLength(0);
return savePath;
}
if(Global.filename.equals(filename)){
//追加入已有檔案
Global.stringBuffer.append(getTime()+"\r\n"+content+"\r\n");
if (Global.stringBuffer.length()>10000) {
writelog(path, Global.filename, Global.stringBuffer.toString());
Global.stringBuffer.setLength(0);
}
return Global.stringBuffer.toString();
}else {
//更換檔名
if(Global.stringBuffer.length()>0){
writelog(path, Global.filename, Global.stringBuffer.toString());
Global.stringBuffer.setLength(0);
}
String savePath=createFile(path,filename,content);
Global.filename=filename;
return savePath;
}
}
/**
* 建立新的檔案路徑,並寫入當前 content
* @param path
* @throws Throwable
*/
private static String createFile(String path,String filename,String content){
String saveDirPath=Global.rootPath+"\\"+path+"\\"+getDate();
File Dirs = new File(saveDirPath);
Dirs.mkdirs();
String saveFilePath=saveDirPath+"\\"+filename+".log";
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(saveFilePath, true),"UTF-8"));
writer.write(getTime()+"\r\n"+content+"\r\n");
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
return saveFilePath;
}
/**
* 將StringBuffer中的內容寫入到file
* @param path
* @param content
*/
private static void writelog(String path,String filename,String content){
BufferedWriter writer = null;
String saveFilePath=Global.rootPath+"\\"+path+"\\"+getDate()+"\\"+filename+".log";
// 處理執行中檔案被刪除的情況
// if(!new File(saveFilePath).exists())
// new File(Global.rootPath+"\\"+path+"\\"+getDate()).mkdirs();
try {
writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(saveFilePath, true),"UTF-8"));
writer.write(content);
writer.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 獲得當前日期
* @return 例:2015-10-11
*/
private static String getDate(){
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DAY_OF_MONTH);
String dateStr = "" + year + "-" + month + "-" + day;
return dateStr;
}
/**
* 獲得當前時間 例:2015-10-11 15:00:01
* @return
*/
private static String getTime(){
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return simpleDateFormat.format(new Date().getTime());
}
}
併發的處理,簡單的處理了併發,使用synchronized關鍵字處理了saveLog方法,確保每次只有一個執行緒可以訪問該方法,這樣就保證了該方法的安全性,避免在多執行緒的狀態下出現不可預期的結果。
效能測試:
使用apache ab進行壓力測試,10000次訪問的時間是3.2s左右,完全可以滿足效能要求。
不足:每次只能處理一個url,如果併發多個url,分佈在多個檔案中,效能太低,不能滿足需求。
相關推薦
基於servlet併發的日誌儲存(上)
由於servlet本身就是併發處理的,因此我們只需要處理好對應的呼叫函式就可以了。 考慮到對效率有要求,因此使用一個StringBuffer做緩衝區,將資料儲存在記憶體中,然後定時將資料寫入檔案。基本思路是先將檔名儲存在記憶體中,將url的filename
執行緒基礎(二十一)-併發容器-ArrayBlockingQueue(上)
本文作者:王一飛,叩丁狼高階講師。原創文章,轉載請註明出處。 在正式講解ArrayBlockingQueue類前,先來科普一下執行緒中各類鎖,只有瞭解這些鎖之後,理解ArrayBlockingQueue那就更輕鬆了。 可重入鎖 一種遞迴無阻塞的同步機制,也叫做遞迴鎖。簡單講
【Java原始碼】基於陣列實現的ArrayList(上)
眾所周知,Java中ArrayList是基於陣列實現的 咱們先看其基本屬性: private static final int DEFAULT_CAPACITY = 10; private static final Object[
基於Servlet的會話跟蹤(一)
1、HTTP協議的無狀態 當客戶端向伺服器傳送一個請求後,伺服器為每一個客戶,建立一個唯一的識別符號-ID號,並在響應的時候,把這個ID號傳送給客戶端瀏覽器。當瀏覽器再次發生請求的時候,同時也把這個ID
eos原始碼賞析(十三):EOS智慧合約資料持久化儲存(上)
前面的文章(eos原始碼賞析(十):EOS智慧合約入門之區塊上鍊)中提到了fork_db,區塊生產之後會將區塊的狀態資訊等儲存在fork_db中,但是當這個動作完成之後,fork_db中的內容就會變化,用來儲存下一個區塊的狀態資訊,並不能實現對歷史區塊資訊的儲存。對於區塊鏈來
基於face++的人臉識別(上)
因為畢業設計需要做人臉識別的考勤,這裡採取已有的平臺上的sdk來做人臉識別,詳細說下如何使用face++平臺來進行人臉識別。 1.註冊為face++的開發者。在這裡註冊個賬號,https://console.faceplusplus.com.cn ,之後進入
Serilog 原始碼解析——資料的儲存(上)
在[上一篇](https://www.cnblogs.com/iskcal/p/parse-of-string-template.html)中,我們主要研究了Serilog是如何解析字串模板的,它只是單獨對字串模板的處理,對於日誌記錄時所附帶的資料沒有做任何的操作。在本篇中,我們著重研究日誌資料的儲存方式。(
【轉載】基於rasa的對話系統搭建(上)
生成模型 efi 實體類 total ted twisted -m serve feature 文章介紹使用rasa nlu和 rasa core 實現一個電信領域對話系統demo,實現簡單的業務查詢辦理功能,更完善的實現需要
python配置MYSQL基於pycharm+mysql+sqlyog(上)
** python配置MYSQL(上) ** 基於pycharm、mysql、sqlyog,進行資料庫操作。菜鳥在慕課慕課網學習python系列語法,及pycharm/mysql/python/sqlyog等的相關配置。基於瘋狂的螞蟻Crazyant的教程,完成mysql例項配置,並
網際網路架構多執行緒併發程式設計高階教程(上)
#基礎篇幅:執行緒基礎知識、併發安全性、JDK鎖相關知識、執行緒間的通訊機制、JDK提供的原子類、併發容器、執行緒池相關知識點 #高階篇幅:ReentrantLock原始碼分析、對比兩者原始碼,更加深入理解讀寫鎖,JAVA記憶體模型、先行發生原則、指令重排序 #環境說明:idea、ja
搭建ELK日誌分析平臺(上)—— ELK介紹及搭建 Elasticsearch 分散式叢集
轉:http://blog.51cto.com/zero01/2079879 筆記內容:搭建ELK日誌分析平臺(上)—— ELK介紹及搭建 Elasticsearch 分散式叢集筆記日期:2018-03-02 27.1 ELK介紹 27.2 ELK安裝準備工作 27.3 安
阿里雲PolarDB及其共享儲存PolarFS技術實現分析(上)
PolarDB是阿里雲基於MySQL推出的雲原生資料庫(Cloud Native Database)產品,通過將資料庫中計算和儲存分離,多個計算節點訪問同一份儲存資料的方式來解決目前MySQL資料庫存在的運維和擴充套件性問題;通過引入RDMA和SPDK等新硬體來改造傳統的網路和IO協議棧來極大提升資料庫效能。
珍藏 | 基於深度學習的目標檢測全面梳理總結(上)
關於作者:@李家丞 同濟大學數學系本科在讀,現為格靈深瞳演算法部實習生。 作者個人主頁:李家丞|個人主頁|關於我 導言:目標檢測的任務表述 如何從影象中解析出可供計算機理解的資訊,是機器視覺的中心問題。深度學習模型由於其強大的表示能力,加之資料量的積累和計算力的
計算機組成與設計(十一)—— 儲存層次結構(上)
儲存層次結構概況 這是我們非常熟悉的馮·諾依曼計算機結構, 那這其中哪些部件和儲存功能有關呢? 儲存器和外部記錄介質肯定具有儲存功能,另外還有一個自帶儲存功能的運算器,為了描述方便,我們把這些部件統稱為儲存器。那麼我們看一下計算機中對儲存器有哪些要求 ? 1、首先儲存器當
【鏈塊技術35期】區塊鏈技術語言——Go語言併發程式設計(上)
併發程式設計分為上、下兩節。這一節包括了併發程式設計的概述、goroutine和channel的部分內容。 一、概述 1.1 並行和併發 並行(parallel):在多個處理器上同時執行多條指令,如圖1所示。 併發(concurrency):同一時刻只有一條指令在
用Fluentd實現收集日誌到HDFS(上)
版權宣告:本文來自行者(http://blog.csdn.net/liuyuan185442111),轉載請註明出處。 https://blog.csdn.net/liuyuan185442111/article/details/47057571 Fluentd是一個實
大資料儲存---HBase介紹(上)
本次主要介紹三部分: HBase簡介 HBase整體架構 HBase安裝和啟動 Hbase基本操作 HBase簡介 hbase是bigtable的開源java版本,是建立在hdfs之上。 提供高可靠性、高效能、列儲存、可伸縮、實時讀寫nosql的資料庫系統
億級併發|day06-Nginx高階應用(上)
0 前期準備 1 服務代理 1.1 需求 1.2 編輯配置檔案 #後臺管理系統 server { listen 80; server_name manage.jt.com; location / { proxy_pass http:/
innodb儲存引擎筆記(上)
MySQL發展路線圖: MySQL體系結構 InnoDB體系架構圖 總體架構圖: 儲存結構: 表空間 所有的資料都需要儲存在表空間中 表空間分類 系
億級流量系統架構之如何在上萬併發場景下設計可擴充套件架構(上)?【石杉的架構筆記】
歡迎關注個人公眾號:石杉的架構筆記(ID:shishan100) 週一至週五早8點半!精品技術文章準時送上! 一、寫在前面 之前更新過一個“億級流量系統架構”系列,主要講述了一個大規模商家資料平臺的如下幾個方面: 如何承載百億級資料儲存 如何設計高容錯的分散式架構 如何設計承載百億流量的高效能架構