1. 程式人生 > >基於servlet併發的日誌儲存(上)

基於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點半!精品技術文章準時送上! 一、寫在前面 之前更新過一個“億級流量系統架構”系列,主要講述了一個大規模商家資料平臺的如下幾個方面: 如何承載百億級資料儲存 如何設計高容錯的分散式架構 如何設計承載百億流量的高效能架構