Java開發問題總結

最近在作開發時,遇到了如下四個問題,總結一下。前端


1.Nginx+Struts中上傳文件的大小限制。java

在上傳文件時,若文件太大會出現上傳失敗。咱們的Web應用前端代理使用了Nginx,MVC使用了Struts,經過檢查,發如今Nginx和Struts中對於上傳文件的大小都作了限制。web

在Nginx的http模塊配置中,client_max_body_size這個參數用於表示http請求body最大值,因爲文件也是以二進制形式存儲於body中,所以client_max_body_size也限制了上傳文件的大小,當上傳文件較大時,可適當調大該值。安全

http {
    ...
    client_max_body_size 20m;
    ...
}

在Struts中,對於上傳文件大小也有限制,默認大小爲2M,能夠在Struts配置文件中修改該默認配置。bash

<constant name="struts.multipart.maxSize" value="104857600"/>


2.Nginx代理對於請求響應超時時間的設置。服務器

外部應用調用咱們提供的http接口時,有時會返回504錯誤,但查看咱們的應用日誌,請求是被正確執行了,再查看Nginx配置,發如今Nginx代理配置中,proxy_read_timeout這個參數用於表示Nginx轉發請求至實際應用後等待響應的時間,若超過該時間,則向客戶端返回超時錯誤,經過適當調大該值解決問題。併發


3.同一個應用部署在不一樣服務器上致使的亂碼問題。app

爲了實現高可用,咱們將同一個應用部署在兩臺服務器上,前端經過Nginx實現負載均衡。啓動後,發現應用有一個功能存在亂碼問題,該功能是接收客戶端傳來的GBK編碼字符串,並調用另外一文件服務接口寫到另外一個服務器的磁盤中。咱們發現該亂碼問題只在客戶端請求轉發至這兩臺服務器上中的其中一臺時存在。負載均衡

經過檢查發現,應用在接收客戶端傳來的GBK編碼字符串時,會調用字符串的getByte()方法,進行解碼,而getByte()方法在不指定編碼格式時,會使用服務器的默認編碼,而這兩臺服務器中,一臺服務器的默認編碼是GBK,能正確解碼,另外一臺服務器的默認編碼是UTF-8,則不能正確解碼。webapp

後來的解決方法是:因爲應用是部署在resin容器中,所以修改resin的配置文件,在jvm參數配置中,指定服務器的默認編碼爲GBK。

<jvm-arg>-Dfile.encoding=GBK</jvm-arg>


4.Web應用負載太高

有一個Java Web應用部署在resin容器中,每隔一端時間,會致使服務器負載太高,但查看後臺並無報錯信息,於是之前每次只能經過重啓應用來解決該問題。

後來在網上找到一個解決該類問題的方法:

1)使用ps查看應用的進程id;

2)使用「top -H -p 進程id」查看進程中的線程列表,排在前面的線程佔CPU較高;

3)使用「jstack 進程id」dump Java進程使用狀況;

4)從Java進程dump中找到在2)中排在前面佔CPU較高的線程,須要注意的是2)中的線程號是十進制,而3)中的線程號是十六進制,須要作一下轉換,咱們找到的佔CPU較高的線程在dump中以下:

"http--8080-37$65442827" daemon prio=10 tid=0x00002aaabc0f3000 nid=0x2c53 runnable [0x000000004517b000]
java.lang.Thread.State: RUNNABLE
at java.util.HashMap.get(HashMap.java:303)
at com.sohu.cms.auth.impl.AuthenticationImpl.hasAction(AuthenticationImpl.java:170)
at com.sohu.cms.webapp.util.AuthenticationInterceptor.intercept(AuthenticationInterceptor.java:62)

發現問題發生在HashMap,這裏咱們定義了一個static HashMap對象,在多個客戶端發起請求時,會併發訪問該HashMap對象時,因爲HashMap並非線程安全的,於是可能會引發問題。咱們在網上找到一個問題現象和緣由和咱們相似的例子:http://shuaijie506.iteye.com/blog/1815213,其中提到問題根本緣由是HashMap在resize時會形成死循環。

後來的解決方案是咱們使用線程安全的ConcurrentHashMap來替代HashMap。

相關文章
相關標籤/搜索