❶ 大規模,高並發網站開發經驗都有哪些
這個問題問得比較籠統,不過可以簡單回答一下。現在一般說的大規模、高並發網站指的是阿里巴巴,特別是淘寶、支付寶這種電商網站,或者網路這種搜索引擎網站。
這種網站的大規模、高並發支撐都是使用分布式系統來支持的,他們的網站系統由成千上萬的機器組成,一個用戶的請求會投遞到一台或多台機器上來處理。這樣你問的問題就轉化成了分布式系統要做到大規模、高並發需要有哪些開發經驗。這個時候就好回答了:
根據業務選擇不同的軟體棧,比如阿里巴巴是Java,網路搜索引擎是C++。然後在這些軟體棧上開發自己的分布式方案,比如淘寶的HSF,阿里巴巴的bbo等等。
解決機器規模上去後的高可用問題,不能因為一台出現故障,導致整體服務都不可用,要有一定的故障保障機制。
河南商之源網路科技有很多經驗,可以去看一下
❷ 高並發的伺服器有什麼模式
服務程序最為關鍵的設計是並發服務模型,當前有以下幾種典型的模型:
- 單進程服務,使用非阻塞IO
使用一個進程服務多個客戶,通常與客戶通信的套接字設置為非阻塞的,阻塞只發生在select()、poll()、epoll_wait()等系統調用上面。這是一種行之有效的單進程狀態機式服務方式,已被廣泛採用。
缺點是它無法利用SMP(對稱多處理器)的優勢,除非啟動多個進程。此外,它嘗試就緒的IO文件描述符後,立即從系統調用返回,這會導致大量的系統調用發生,尤其是在較慢的位元組傳輸時。
select()本身的實現也是有局限的:能打開的文件描述符最多不能超過FD_SETSIZE,很容易耗盡;每次從select()返回的描述符組中掃描就緒的描述符需要時間,如果就緒的描述符在末尾時更是如此(epoll特別徹底修復了這個問題)。
- 多進程服務,使用阻塞IO
也稱作 accept/fork 模型,每當有客戶連線時產生一個新的進程為之服務。這種方式有時是必要的,比如可以通過操作系統獲得良好的內存保護,可以以不同的用戶身份運行程序,可以讓服務運行在不同的目錄下面。但是它的缺點也很明顯:進程比較占資源,進程切換開銷太大,共享某些信息比較麻煩。Apache 1.3就使用了這種模型,MaxClients數很容易就可以達到。
- 多線程服務,使用阻塞IO
也稱之 accept/pthread_create模型,有新客戶來時創建一個服務線程而不是服務進程。這解決了多進程服務的一些問題,比如它佔用資源少,信息共享方便。但是麻煩在於線程仍有可能消耗光,線程切換也需要開銷。
- 混合服務方式
所謂的混合服務方式,以打破服務方和客戶方之間嚴格的1:1關系。基本做法是:
新客戶到來時創建新的工作線程,當該工作線程檢測到網路IO會有延遲時停止處理過程,返回給Server一個延遲處理狀態,同時告訴 Server被延遲的文件描述符,延遲超時時間。Server會在合適的時候返回工作線程繼續處理。注意這里的工作線程不是通過 pthread_create()創建的,而是被包裝在專門用於處理延遲工作的函數里。
這里還有一個問題,工作線程如何檢測網路IO會有延遲?方法有很多,比如設置較短的超時時間調用poll(),或者甚至使用非阻塞IO。如果是套接字,可以設置SO_RCVTIMEO和SO_SNDTIMEO選項,這樣更有效率。
除了延遲線程,Server還應提供了未完成線程的支持。
如有有特別耗費時間的操作,你可以在完成部分工作後停止處理,返回給Server一個未完成狀態。這樣Server會檢查工作隊列是否有別的線程,如果有則讓它們運行,否則讓該工作線程繼續處理,這可以防止某些線程挨餓。
典型的一個混合服務模型開源實現ServerKit
Serverkit的這些線程支持功能可簡化我們的服務程序設計,效率上應該也是有保證的。
2. 隊列(queue)
ServerKit提供的隊列是一個單向鏈表,隊列的存取是原子操作,如果只有一個執行單元建議不要用,因為原子操作的開銷較大。
3. 堆(heap)
malloc()分配內存有一定的局限,比如在多線程的環境里,需要序列化內存分配操作。ServerKit提供的堆管理函數,可快速分配內存,可有效減少分配內存的序列化操作,堆的大小可動態增長,堆有引用計數,這些特徵比較適合多線程環境。目前ServerKit堆的最大局限是分配單元必須是固定大小。
4. 日誌記錄
日誌被保存在隊列,有一個專門的線程處理隊列中的日誌記錄:它或者調用syslog()寫進系統日誌,或者通過UDP直接寫到遠程機器。後者更有效。
5. 讀寫鎖
GNU libc也在pthreads庫里實現了讀寫鎖,如果定義了__USE_UNIX98就可以使用。不過ServerKit還提供了讀寫鎖互相轉換的函數,這使得鎖的應用更為彈性。比如擁有讀鎖的若干個線程對同一個hash表進行檢索,其中一個線程檢索到了數據,此時需要修改它,一種辦法是獲取寫鎖,但這會導致釋放讀鎖和獲取寫鎖之間存在時間窗,另一種辦法是使用ServerKit提供的函數把讀鎖轉換成寫鎖,無疑這種方式更有效率。
除了以上這些功能,ServerKit還提供了資料庫連接池的管理(當前只支持MySQL)和序列化(Sequences),如感興趣可參見相關的API文檔。
二、ServerKit服務模塊編寫
ServerKit由3部分組成:server程序,負責載入服務模塊、解析配置文件、建立資料庫連接池;libserver,動態鏈接庫,提供所有功能的庫支持,包括server本身也是調用這個庫寫的;API,編程介面,你編寫的服務模塊和ServerKit框架進行對話的介面。
ServerKit需要libConfuse解析配置文件,所以出了安裝ServerKit,還需要安裝libConfuse。關於libConfuse可參考 http://www.nongnu.org/confuse/ 。
下面我們看一個簡單的服務模塊FOO:
#include <confuse.h>
#include <server.h>
static long int sleep_ration;
static int FOO_construct()
{
fprintf(stderr, "FOO_construct\n");
return 1;
}
static int FOO_prestart(cfg_t *configuration)
{
fprintf(stderr, "FOO_prestart\n");
return 1;
}
static void * FOO_operator(void *foobar)
{
fprintf(stderr, "FOO_operator\n");
for(;;) sleep(sleep_ration);
return NULL;
}
static void FOO_report(void)
{
fprintf(stderr, "FOO_report\n");
}
static cfg_opt_t FOO_config[] = {
CFG_SIMPLE_INT("sleep_ration", &sleep_ration),
CFG_END()
};
static char *FOO_authors[] = {"Vito Caputo <[email protected]>", NULL};
SERVER_MODULE(FOO,0,0,1,"Example mole that does nothing but sleep")按以下方法編譯:
$ gcc -c -fPIC -pthread -D_REENTRANT -g FOO.c
$ gcc -shared -lserver -lconfuse -lpthread -g -e __server_mole_main -o FOO.so FOO.o
-e選項指定程序運行入口,這使得你可以直接在命令行敲 ./FOO.so 運行模塊。
server程序根據環境變數SERVER_PERSONALITY_PATH定位主目錄,並查找主目錄下的c11n作為配置文件,動態載入的模塊需放在主目錄下的moles目錄。
$ export SERVER_PERSONALITY_PATH=`pwd`
$ mkdir moles
$ cp FOO.so moles
$ vi c11n
c11n的內容:
identity = "any_id"
FOO {
sleep_ration = 1;
}
identity標識server實例,用ps可看到程序名稱形如server.identity,本例為server.any_id。
執行server啟動服務程序。
三、ServerKit其他功能缺陷
缺乏daemon模式;
只能運行在Linux box;
DB pool只支持MySQL;
Heap管理內存的功力有限
❸ 用java做互聯網開發,高並發,大數據量,應具備哪些技術系統架構,資料庫方面的,還有那些常用的技術。
memcache緩存系統
proxool資料庫連接池
這兩個用好已經基本解決問題了
❹ 什麼是多線程和高並發
「高並發和多線程」總是被一起提起,給人感覺兩者好像相等,實則 高並發 ≠ 多線程
多線程是完成任務的一種方法,高並發是系統運行的一種狀態,通過多線程有助於系統承受高並發狀態的實現。
高並發是一種系統運行過程中遇到的一種「短時間內遇到大量操作請求」的情況,主要發生在web系統集中大量訪問或者socket埠集中性收到大量請求(例如:12306的搶票情況;天貓雙十一活動)。該情況的發生會導致系統在這段時間內執行大量操作,例如對資源的請求,資料庫的操作等。如果高並發處理不好,不僅僅降低了用戶的體驗度(請求響應時間過長),同時可能導致系統宕機,嚴重的甚至導致OOM異常,系統停止工作等。如果要想系統能夠適應高並發狀態,則需要從各個方面進行系統優化,包括,硬體、網路、系統架構、開發語言的選取、數據結構的運用、演算法優化、資料庫優化……而多線程只是其中解決方法之一。
❺ java 高並發 都有哪些技術
我用的JAVA NIO,一般常用的高並發IO框架,也是用的這個做擴展。
Java NIO是在jdk1.4開始使用的,它既可以說成「新I/O」,也可以說成非阻塞式I/O。下面是java NIO的工作原理:
1. 由一個專門的線程來處理所有的 IO 事件,並負責分發。
2. 事件驅動機制:事件到的時候觸發,而不是同步的去監視事件。
3. 線程通訊:線程之間通過 wait,notify 等方式通訊。保證每次上下文切換都是有意義的。減少無謂的線程切換。
Java NIO的服務端只需啟動一個專門的線程來處理所有的 IO 事件,這種通信模型是怎麼實現的呢?呵呵,我們一起來探究它的奧秘吧。java NIO採用了雙向通道(channel)進行數據傳輸,而不是單向的流(stream),在通道上可以注冊我們感興趣的事件。一共有以下四種事件:
事件名 對應值
服務端接收客戶端連接事件 SelectionKey.OP_ACCEPT(16)
客戶端連接服務端事件 SelectionKey.OP_CONNECT(8)
讀事件 SelectionKey.OP_READ(1)
寫事件 SelectionKey.OP_WRITE(4)
服務端和客戶端各自維護一個管理通道的對象,我們稱之為selector,該對象能檢測一個或多個通道 (channel) 上的事件。我們以服務端為例,如果服務端的selector上注冊了讀事件,某時刻客戶端給服務端發送了一些數據,阻塞I/O這時會調用read()方法阻塞地讀取數據,而NIO的服務端會在selector中添加一個讀事件。服務端的處理線程會輪詢地訪問selector,如果訪問selector時發現有感興趣的事件到達,則處理這些事件,如果沒有感興趣的事件到達,則處理線程會一直阻塞直到感興趣的事件到達為止。下面是我理解的java NIO的通信模型示意圖:
❻ socket高並發網路編程服務端有什麼框架
netty;
PayServer.java
package com.miri.pay.scoket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PayServer implements Runnable
{
private static final Logger DLOG = LoggerFactory.getLogger(PayServer.class);
private final int port;
public PayServer(int port)
{
this.port = port;
}
/**
* 為ServerBootstrap綁定指定埠
*/
public void run()
{
// 用於接收發來的連接請求
final EventLoopGroup bossGroup = new NioEventLoopGroup();
// 用於處理boss接受並且注冊給worker的連接中的信息
final EventLoopGroup workerGroup = new NioEventLoopGroup();
try
{
// 配置伺服器
final ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup);
bootstrap.channel(NioServerSocketChannel.class);
bootstrap.option(ChannelOption.SO_BACKLOG, 128);
// 通過NoDelay禁用Nagle,使消息立即發出去,不用等待到一定的數據量才發出去
bootstrap.option(ChannelOption.TCP_NODELAY, true);
// 保持長連接狀態
bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
// CustomChannelInitializer是一個特殊的handler,用於方便的配置用戶自定義的handler實現
bootstrap.childHandler(new CustomChannelInitializer());
// 綁定並開始接受傳入的連接
final ChannelFuture future = bootstrap.bind(this.port).sync();
if (future.isSuccess())
{
PayServer.DLOG.info("Start the socket server {} success", this.port);
}
else
{
PayServer.DLOG.info("Start the socket server {} failure,System exit!", this.port);
throw new RuntimeException("Socket服務端啟動失敗");
}
// 等待伺服器套接字關閉
// 關閉伺服器
future.channel().closeFuture().sync();
}
catch (final InterruptedException e)
{
PayServer.DLOG.error("Close the socket server exception occurs,System exit!", e);
throw new RuntimeException("關閉Socket服務端失敗");
}
finally
{
// 關閉所有事件循環終止線程
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
/**
* 特殊的內部類
* <p>
* 是一個特殊的handler,用於方便的配置用戶自定義的handler實現
* @author xulonghui
*/
static class CustomChannelInitializer extends ChannelInitializer<SocketChannel>
{
@Override
protected void initChannel(SocketChannel ch) throws Exception
{
final ChannelPipeline p = ch.pipeline();
p.addLast(new PayMessageEncoder());
p.addLast(new PayMessageDecoder());
p.addLast(new PayServerHandler());
}
}
}
PayMessageEncoder.java
package com.miri.pay.scoket;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.CharsetUtil;
import com.miri.pay.model.CommonResponse;
import com.miri.pay.utils.JsonUtil;
/**
*消息編碼器
* <p>
* 編碼從服務端發送出的消息
*/
public class PayMessageEncoder extends MessageToByteEncoder<CommonResponse>
{
@Override
protected void encode(ChannelHandlerContext ctx, CommonResponse rsp, ByteBuf out) throws Exception
{
if (rsp != null)
{
final Object msgContent = rsp.getMsgContent();
// 消息ID,sequenceId和entityId三個加起來是12個長度
int msgLen = 12;
byte[] contentbs = new byte[] {};
if (msgContent != null)
{
final String content = JsonUtil.bean2json(msgContent);
contentbs = content.getBytes(CharsetUtil.UTF_8);
final int cl = contentbs.length;
msgLen += cl;
}
out.writeInt(msgLen);// 寫入當前消息的總長度
out.writeInt(rsp.getMsgId());// 寫入當前消息的消息ID
out.writeInt(rsp.getSequenceId());// 寫入當前消息的SequenceId
out.writeInt(rsp.getEntityId());// 寫入當前消息的EntityId
// 寫入消息主體內容
if (contentbs.length > 0)
{
out.writeBytes(contentbs);
}
}
}
}
PayMessageDecoder.java
package com.miri.pay.scoket;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.util.CharsetUtil;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.miri.pay.constants.Constants;
import com.miri.pay.model.CommonRequest;
import com.miri.pay.utils.ByteUtil;
/**
* 消息解碼器
* <p>
* 解碼從客戶端請求的消息
*/
public class PayMessageDecoder extends ByteToMessageDecoder
{
private static final Logger DLOG = LoggerFactory.getLogger(PayMessageDecoder.class);
/**
* 表示頭長度的位元組數
*/
private static final int HEAD_LENGTH = 4;
/**
* 所有ID串所屬的位元組數
*/
private static final int ID_STR_LENGTH = 12;
/**
* 單個ID所屬的位元組數
*/
private static final int SINGLE_ID_LENGTH = 4;
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception
{
int readable = in.readableBytes();
if (readable < PayMessageDecoder.HEAD_LENGTH)
{
return;
}
in.markReaderIndex(); // 我們標記一下當前的readIndex的位置
final int dataLength = in.readInt(); // 讀取傳送過來的消息的長度。ByteBuf 的readInt()方法會讓他的readIndex增加4
if (dataLength < 0)
{
// 我們讀到的消息體長度為0,這是不應該出現的情況,這里出現這情況,關閉連接。
ctx.close();
}
readable = in.readableBytes();
if (readable < dataLength)
{
// 讀到的消息體長度如果小於我們傳送過來的消息長度,則resetReaderIndex. 這個配合markReaderIndex使用的。把readIndex重置到mark的地方
in.resetReaderIndex();
return;
}
final byte[] body = new byte[dataLength];
in.readBytes(body);
// 判斷是否讀取到內容
final int length = body.length;
if (length == 0)
{
return;// 若未讀出任何內容,則忽略
}
out.add(this.byte2req(body));
}
/**
* 將讀取到的byte數據轉換為請求對象
* @param body
* @return
* @throws Exception
*/
private CommonRequest byte2req(byte[] body) throws Exception
{
final CommonRequest req = new CommonRequest(Constants.INVALID_MSGID);
final int length = body.length;
// 若內容數組的長度小於或等於12,則表示消息主體內容為空,直接返回一個無效的消息出去
if (length < PayMessageDecoder.ID_STR_LENGTH)
{
PayMessageDecoder.DLOG
.info("The client sends the message length is: {}, is invalid message, directly returns a msgId = {} request entity",
length, Constants.INVALID_MSGID);
return req;
}
// 獲取消息ID
final byte[] mbs = new byte[PayMessageDecoder.SINGLE_ID_LENGTH];
System.array(body, 0, mbs, 0, PayMessageDecoder.SINGLE_ID_LENGTH);
final int msgId = ByteUtil.byte4toint(mbs);
req.setMsgId(msgId);
// 獲取sequenceId
final byte[] sbs = new byte[PayMessageDecoder.SINGLE_ID_LENGTH];
System.array(body, 4, sbs, 0, PayMessageDecoder.SINGLE_ID_LENGTH);
final int sequenceId = ByteUtil.byte4toint(sbs);
req.setSequenceId(sequenceId);
// 獲取entityId
final byte[] ebs = new byte[PayMessageDecoder.SINGLE_ID_LENGTH];
System.array(body, 8, ebs, 0, PayMessageDecoder.SINGLE_ID_LENGTH);
final int entityId = ByteUtil.byte4toint(ebs);
req.setEntityId(entityId);
// 獲取消息主體內容
if (length > PayMessageDecoder.ID_STR_LENGTH)
{
final int contentLen = length - PayMessageDecoder.ID_STR_LENGTH;
final byte[] contentbs = new byte[contentLen];
System.array(body, 12, contentbs, 0, contentLen);
final String content = new String(contentbs, CharsetUtil.UTF_8);
req.setMsgContent(content);
}
return req;
}
}
PayServerHandler.java
package com.miri.pay.scoket;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.miri.pay.MessageQueue;
import com.miri.pay.model.CommonRequest;
import com.miri.pay.model.PendingBean;
/**
* Socket服務端處理器
*/
public class PayServerHandler extends ChannelInboundHandlerAdapter
{
private static final Logger DLOG = LoggerFactory.getLogger(PayServerHandler.class);
/**
* 外部訂單號-頻道
*/
public static final Map<String, Channel> CHANNELS = new HashMap<String, Channel>();
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception
{
try
{
PayServerHandler.DLOG.info("Client send to msg is: {}", msg);
final CommonRequest request = (CommonRequest) msg;
final PendingBean bean = new PendingBean(ctx.channel(), request);
MessageQueue.offer(bean);
}
finally
{
ReferenceCountUtil.release(msg);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception
{
ctx.flush();
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
super.channelActive(ctx);
final Channel channel = ctx.channel();
PayServerHandler.DLOG.info("Client active form {}", channel.remoteAddress());
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception
{
super.channelInactive(ctx);
final Channel channel = ctx.channel();
PayServerHandler.DLOG.info("Client inactive form {}", channel.remoteAddress());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception
{
PayServerHandler.DLOG.error("System exception", cause);
ctx.close();
}
}
❼ 會出現高並發架構,主要運用了哪些技術
高並發主要是由於網站PV訪問量大,單台伺服器涌承載大量訪問所帶來的壓力,所以會採用多台伺服器進行分流,採用伺服器集群技術,對於每個訪問會被發送到哪台伺服器,我們採取負載均衡策略,常見的技術有LVS,由於網站中有大量的靜態頁面,所以採用緩存伺服器和反向代理技術,包括HAPROXY,REDIS,資料庫可以採用資料庫集群,進行讀寫分離,緩解資料庫壓力。等等。
❽ 電子商務網站中高負載,高並發指的到底是什麼解決思路有哪些
電子商務網站高負載,簡單可以分為前端和後台:
前端主要是圖片(應該沒有文件下載吧),因為是電子商務網站,少不了大量的圖片,用戶集中的情況下,網頁載入就會變的極其緩慢。
解決思路:1、壓縮圖片,使產品圖不失真的情況下盡可能的減少體積,節省寬頻。2、增大伺服器帶寬。3、優化網頁代碼,盡量採用非同步載入方式。4、CDN
後台則是數據處理和資料庫負載,電子商務網站後台除了龐大的用戶數據要處理意外,還有大量訂單,和結算數據。
解決思路:增大資料庫伺服器配置。
高並發,是所有訪問量大的網站都會遇到的問題,並發數是指同一時刻,伺服器能接受多少次同時訪問,比如伺服器配置並發數為200,則這一刻只能允許200個用戶同時訪問,超過並發數,輕則用戶打不開網站,嚴重的則是伺服器宕機。
解決思路:1、CDN。2、增加伺服器配置
註:CDN是現在網站普遍使用的加速方案,對減輕伺服器負載,避免高並發,緩解惡意攻擊都有很好的效果,其主要原理就是將伺服器上的數據分發給多個伺服器,用戶訪問的是CDN伺服器,從而減輕和保護了網站伺服器,也就是常說的雲伺服器。
❾ 哪個技術具有高寬頻高並發低時延低耗電的優勢
摘要 親 你好 您的問題我已經看到了 麻煩您等待三分鍾 我需要整理一下答案。
❿ Java互聯網開發涉及的高並發和大數據業務都有什麼技術
高並發很好解決,用負載均衡器分流到各個集群節點即可,遇到相應的業務,對一致性要求很強的,使用zookeeper之類的工具處理一下即可。最新的技術比如:playframework2、actor模型(akka)、netty的非阻塞應用,就是Java Web分布式高並發治理的良葯,負載均衡器的節點映射和拆分需要用到一致性哈希演算法(環形哈希)。大數據有些就比較復雜了,延遲要求不高的用hadoop或spark之類的,要求低延遲的就需要結合具體具體業務場景來分解了。