单品页统一服务系统架构未公开细节
架构
单品页依赖服务众多,分布在各个部门。问题:
-
服务质量没有监控数据
-
出现问题不能及时降级
-
接口调用分散化
-
域名重复解析,没有长连接的优势
架构总体原则
-
设计上无状态
-
使用nginx+lua+tomcat7架构
-
充分利用localcache(proxycache or shared_dict orjava guava cache)
-
使用localtwemproxy做redis分片,且缓存分离(重要业务与其他业务分离)
-
分离线程池,核心业务与非核心业务分离,且有线程池监控和开关
-
异步化更新
-
Redis集群使用主从架构
-
使用unixdomain socket减少连接数
-
使用keepalive长连接
-
考虑好开关
-
缓存时间、是否调用后端服务、托底(托底恢复采用指数/随机数恢复机制)
Twemproxy+Redis
-
使用localtwemproxy做redis分片,且缓存分离(重要业务与其他业务分离)Redis集群使用集中式主从架构/ 考虑复制缓冲区大小
-
考虑使用unix domain socket/ 套接字放内存文件系统
-
考虑使用HashTag
-
Redis考虑缓存驱逐策略:maxmemory-policy allkeys-lru maxmemory-samples 10
Nginx keep alive
-
使用长连接,并限制长连接数量
Nginx timeout
-
设置超时
Nginx proxy cache
-
使用内存文件系统进行 Nginx Proxy Cache
-
注意响应头对cache时间的影响
Parameters of caching can also beset directly in the response header. This has higher priority than setting ofcaching time using the directive.
•The“X-Accel-Expires” header field sets caching time of a response in seconds. Thezero value disables caching for a response. If the value starts with the @ prefix,it sets an absolute time in seconds since Epoch, up to which the response maybe cached.•Ifthe header does not include the “X-Accel-Expires” field, parameters of cachingmay be set in the header fields “Expires” or “Cache-Control”.•Ifthe header includes the “Set-Cookie” field, such a response will not be cached.•Ifthe header includes the “Vary” field with the special value “*”,such a response will not be cached (1.7.7). If the header includes the “Vary”field with another value, such a response will be cached taking into accountthe corresponding request header fields (1.7.7).
-
数据有问题不要缓存
Nginx DNS
-
proxy_pass时使用Local DNS解析
-
可能解析到多个server(nslookup),会自动next upstream
-
Nginx plus支持upstream的动态解析
Nginx Gzip
-
根据自己需求设置gzip_comp_level、gzip_min_length、gzip_types
Nginx upstream
-
upstream检查
-
upstream策略 ip_hash
-
upstream策略 hash key [consistent]
consistent_key是根据流量负载动态计算的,如根据ip计算:
local newval, err = ip_log:incr(ip, 1)
local toDelay = false
-- 单IP恶意请求 分流到固定机组
if newval > 50 then
toDelay = true
ngx_var.consistent_key = ngx_var.consistent_key .. '_' .. newval
--要在set_uri前执行,否则执行不到
end
Nginx Real ip
Nginx client header
限定请求头和请求体大小,在proxy pass到后端服务时不传输请求头和请求体,减少网络交互。
Nginx limit
-
limit request
-
limit connection / limit rate
-
ip白名单/黑名单
-
user-agent白名单/黑名单
-
Token限流
-
漏桶算法令牌桶算法(JavaGuava rate limit)
-
Delay限速
参考 聊聊高并发系统之限流特技-1、 聊聊高并发系统之限流特技-2。
Nginx+Lua shared_dict
-
使用共享字典做local cache
Nginx+Lua 接口合并
-
请求时使用method参数表示请求哪个服务
-
数据过滤逻辑前置,不合法直接403(防止XSS)
-
封装调用逻辑,参数顺序等固定,提升缓存命中率
-
通过Nginx子请求(ngx.location.capture_multi)进行合并
-
只对原子接口进行Cache
-
通过一层代理重试或者记录UMP日志
Nginx+Lua 记录日志
-
记录日志还可以通过
Java 架构
-
异步非阻塞事件模型
从Servlet3开始支持异步模型,Tomcat7/Jetty8开始支持,相同的概念是Jetty6的Continuations。我们可以把处理过程分解为一个个的事件。
通过这种将请求划分为事件方式我们可以进行更多的控制。如,我们可以为不同的业务再建立不同的线程池进行控制:
即我们只依赖tomcat线程池进行请求的解析,对于请求的处理我们交给我们自己的线程池去完成;这样tomcat线程池就不是我们的瓶颈,造成现在无法优化的状况。
通过使用这种异步化事件模型,我们可以提高整体的吞吐量,不让慢速的A业务处理影响到其他业务处理。慢的还是慢,但是不影响其他的业务。
通过这种将请求划分为事件方式我们可以进行更多的控制。如,我们可以为不同的业务再建立不同的线程池进行控制:
Java Tomcat
-
start.sh
export JAVA_OPTS="-Djava.library.path=/usr/local/lib -server -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection -XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled -XX:SoftRefLRUPolicyMSPerMB=0 -XX:MaxDirectMemorySize=512m -Xss256k -XX:NewRatio=1 -XX:SurvivorRatio=6 -Xms16384m -Xms16384m -XX:MaxPermSize=256m -Djava.awt.headless=true -Dsun.net.client.defaultConnectTimeout=60000 -Dsun.net.client.defaultReadTimeout=60000 -Djmagick.systemclassloader=no -Dnetworkaddress.cache.ttl=300 -Dsun.net.inetaddr.ttl=300 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$CATALINA_BASE/logs -XX:ErrorFile=$CATALINA_BASE/logs/java_error_%p.log"
-XX:+UseConcMarkSweepGC 表示使用CMS
-XX:+CMSParallelRemarkEnabled 表示并行remark
-XX:+UseCMSCompactAtFullCollection 表示在FGC之后进行压缩,因为CMS默认不压缩空间的。
-XX:CMSInitiatingOccupancyFraction=80 设置阀值为80%,默认为68%。
-XX:SoftRefLRUPolicyMSPerMBsoftly reachable objects will remain alive for some amount of time after thelast time they were referenced. The default value is one second of lifetime perfree megabyte in the heap
-XX:NewRatio年轻代(包括Eden和两个Survivor区)与年老代的比值(不包括持久代)
-XX:SurvivorRatio Eden区与Survivor区的大小比值
-
server.xml
<Connector port="1601" asyncTimeout="10000" acceptCount="10240" maxConnections="10240" acceptorThreadCount="1" minSpareThreads="5" maxThreads="5" redirectPort="8443" processorCache="1024" URIEncoding="UTF-8" protocol="org.apache.coyote.http11.Http11NioProtocol" enableLookups="false"/>
以Tomcat 6为例,其Connector有几个关键配置:
BIO实现:
acceptCount:在超过最大连接数时,可接受的排队数量;超过这个值就直接拒绝连接;默认100;
maxThreads:tomcat可创建的最大线程数,没线程处理一个请求,它决定了tomcat最大线程阀值;默认200;
minSpareThreads:最小备用线程数,即tomcat一启动就创建的线程数;默认25;(使用Executor时配置)
maxQueueSize:最大备用线程数,一旦创建的线程超过这个值tomcat就会关闭不活动的线程;默认Integer.MAX_VALUE;(使用Executor时配置)
NIO实现(继承如上的配置):
acceptorThreadCount:接受连接的线程数;默认1,可以根据CPU核数调整;如果没有问题默认1个即可,基本不需要改;
pollerThreadCount:运行选择事件的线程个数;默认每核一个;
processorCache:协议处理器缓存Http11NioProcessor对象的个数,目的是提高性能,默认200,建议其值接近maxThreads;
对于tomcat7的相关配置可以参考官网http://tomcat.apache.org/tomcat-7.0-doc/config/http.html;核心差不多。
Java servlet3
Java thread pool
-
线程池并发执行任务获取数据
-
异步更新缓存
Java cache
-
local cache guava
-
批量接口时,对单个数据进行缓存;首先查询单个缓存,然后对miss数据进行批量获取,最后合并为结果
其他
-
域名分区:客户端同域连接限制,进行域名分区:c.3.cn c1.3.cn c2.3.cn
-
充分使用CPU,比如绑定CPU核数
-
考虑减少连接数
-
考虑使用内存文件系统
-
考虑大内存或企业级SSD
-
全部使用弹性云
完。PPT下载地址: https://pan.baidu.com/s/1K-Djkf6IFZ7qSEIlNqYPAw。
======广告======
亿级流量网站架构核心技术——跟开涛学搭建高可用高并发系统
作者:张开涛 著
京东基础架构建设之路
作者:京东商城基础架构部
京东数据中心构建实战
作者:吕科等