❶ 大规模,高并发网站开发经验都有哪些
这个问题问得比较笼统,不过可以简单回答一下。现在一般说的大规模、高并发网站指的是阿里巴巴,特别是淘宝、支付宝这种电商网站,或者网络这种搜索引擎网站。
这种网站的大规模、高并发支撑都是使用分布式系统来支持的,他们的网站系统由成千上万的机器组成,一个用户的请求会投递到一台或多台机器上来处理。这样你问的问题就转化成了分布式系统要做到大规模、高并发需要有哪些开发经验。这个时候就好回答了:
根据业务选择不同的软件栈,比如阿里巴巴是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之类的,要求低延迟的就需要结合具体具体业务场景来分解了。