对于Web系统:
要实现统一读取,可以使用ThreadContext+AOP来实现。
ThreadContext的使用方式有以下几种:
解决方法一 :提供ThreadContext包,在每次请求一开始时都复制系统里的所有配置缓存(复制过程要与配置更新Sync互斥),从而保证每次会话的数据的一致性。
解决方法二 :提供ThreadContext包,每次请求都绑定一个版本号,如果读取时版本号不一致则报错,需要重新请求。
解决方法三 :方法二的加强版,添加一个注解定义,标注它是需要强一制性的,每次会话读取时只复制这些强一制性配置(复制过程要与配置更新Sync互斥)。
解决方法四 :提供ThreadContext包,系统内保存有多个配置缓存层,读取时统一读取某个版本的缓存。每当配置更新时,缓存层增加。
第一种方法,代价太大。第二种方法,严重增加用户负担,第三种还是需要用户关心这个事情。我们将采用 第四种方法 。
对于非Web项目:
比较难解决非一致性读取的问题。因为它没有了会话这样一个概念。Apache的FileChangedReloadingStrategy Reload配置文件的方案也没有解决此问题。所以,我们打算放弃这方面的解决。但是,我们还是会提供一个简单却Ugly的解决方案: 提供函数来标识用户读取配置的边界 。用户可以放弃使用这个方案,但是我们不保证不会发生“不一致读’问题。
服务启动前,zk连接上了:
注意
ZK一般需要以集群的形式提供出来。假设有N台ZK,
** * disconf-client的ZK异常处理
disconf-client可以完全保证: 如果在启动程序时保证ZK集群是可用的 ,那么,就可以保证在任何情况下,与ZK集群的自动连接。
下面按情况进行分析:
程序启动前,zk连接不上
这时disconf-client无法在ZK上注册信息。这是必须禁止发生的情况。也是disconf-client无法支持的情况。
一旦发生这种情况,请先恢复ZK集群,再启动你的程序。
程序启动前,zk连接上了:
如果在程序启动过程中,ZK是正常的,那么,disconf-client可以保证与ZK连接的自动性。
注意
disconf-client必须保证在程序在启动时,ZK集群的可用性。
查看disconf日志,发现zk没有启动。实际情况是:zk已经启动,可以使用zkServer.sh status命令进行查看。
那么问题就明确了,disconf没有关联上zk。
经过排查,发现在disconf部署目录之下,有一个zk的jar,且版本号和实际使用的版本号不一致。因此,zk才没法连接到disconf,导致最终的zk部署情况为空。
解决办法比较简单:让这个zk的jar和实际使用的zk版本保持一致就OK了。
详细步骤如下:
①在POM.xml中重新改动zk依赖的版本号(改为实际使用的zk版本),重新编译。
②将disconf-web部署目录下的zoo.properties中的hosts改为要启动的zk的client端口号,本机为127.0.0.1:2181。【重要】
经过上述步骤,重新启动zk,发现disconf日志中显示zk已经能够正确连接。
通过学习《亿级流量网站架构核心技术》及《linux就该这么学》学习笔记及自己的感悟:架构设计之高可用高并发系统设计原则,架构设计包括墨菲定律、康威定律和二八定律三大定律,而系统设计包括高并发原则、高可用和业务设计原则等。架构设计三大定律
墨菲定律 – 任何事没有表面看起来那么简单 – 所有的事都会比预计的时间长 – 可能出错的事情总会出错 – 担心某种事情发生,那么它就更有可能发生
康威定律 – 系统架构师公司组织架构的反映 – 按照业务闭环进行系统拆分/组织架构划分,实现闭环、高内聚、低耦合,减少沟通成本 – 如果沟通出现问题,应该考虑进行系统和组织架构的调整 – 适合时机进行系统拆分,不要一开始就吧系统、服务拆分拆的非常细,虽然闭环,但是每个人维护的系统多,维护成本高 – 微服务架构的理论基础 – 康威定律https://yq.aliyun.com/articles/8611– 每个架构师都应该研究下康威定律http://36kr.com/p/5042735.html
二八定律 – 80%的结果取决于20%的原因
系统设计遵循的原则
1.高并发原则
无状态
无状态应用,便于水平扩展
有状态配置可通过配置中心实现无状态
实践: Disconf、Yaconf、Zookpeer、Consul、Confd、Diamond、Xdiamond等
拆分
系统维度:按照系统功能、业务拆分,如购物车,结算,订单等
功能维度:对系统功能在做细粒度拆分
读写维度:根据读写比例特征拆分;读多,可考虑多级缓存;写多,可考虑分库分表
AOP维度: 根据访问特征,按照AOP进行拆分,比如商品详情页可分为CDN、页面渲染系统,CDN就是一个AOP系统
模块维度:对整体代码结构划分Web、Service、DAO
服务化
服务化演进: 进程内服务-单机远程服务-集群手动注册服务-自动注册和发现服务-服务的分组、隔离、路由-服务治理
考虑服务分组、隔离、限流、黑白名单、超时、重试机制、路由、故障补偿等
实践:利用Nginx、HaProxy、LVS等实现负载均衡,ZooKeeper、Consul等实现自动注册和发现服
消息队列
目的: 服务解耦(一对多消费)、异步处理、流量削峰缓冲等
大流量缓冲: 牺牲强一致性,保证最终一致性(案例:库存扣减,现在Redis中做扣减,记录扣减日志,通过后台进程将扣减日志应用到DB)
数据校对: 解决异步消息机制下消息丢失问题
数据异构
数据异构: 通过消息队列机制接收数据变更,原子化存储
数据闭环: 屏蔽多从数据来源,将数据异构存储,形成闭环
缓存银d
用户层:
DNS缓存
浏览器DNS缓存
*** 作系统DNS缓存
本地DNS服务商缓存
DNS服务器缓存
客户端缓存
浏览器缓存(Expires、Cache-Control、Last-Modified、Etag)
App客户缓存(js/css/image…)
代理层:
CDN缓存(一般基于ATS、Varnish、Nginx、Squid等构建,边缘节点-二级节点-中心节点-源站)
接入层:
Opcache: 缓存PHP的Opcodes
Proxy_cache: 代理缓存,可以存储到/dev/shm或者SSD
FastCGI Cache
Nginx+Lua+Redis: 业务数据缓存
Nginx为例:
PHP为例:
应用层:
页面静态化
业务数据缓存(Redis/Memcached/本地文件等)
消息队列
数据层:
NoSQL: Redis、Memcache、SSDB等
MySQL: Innodb/MyISAM等Query Cache、Key Cache、Innodb Buffer Size等
系统层:
CPU : L1/L2/L3 Cache/NUMA
内存
磁盘:磁盘本身缓存、dirtyratio/dirtybackground_ratio、阵列卡本身缓存
并发化
2.高可用原则
降级
降级开关集中化管理:将开关配置信息推送到各个应用
可降级的多级读服务:如服务调用降级为只读本地缓存
开关前置化:如Nginx+lua(OpenResty)配置降级策略,引流流量;可基于此做灰度策略
业务降级:高并发下,保证核心功能,次要功能可由同步改为异步策略或屏蔽功能
限流
目的: 防止恶意请求攻击或超出系统峰值
实践:
恶意请求流量只访问到Cache
穿透后端应用的流量使用Nginx的limit处理
恶意IP使用Nginx Deny策略或者iptables拒绝
切流量
目的:屏蔽故障机器
实践:
DNS: 更改域名解析入口,如DNSPOD可以添加备用IP,正常IP故障时,会自主切换到备用地址生效实践较慢
HttpDNS: 为了绕过运营商LocalDNS实现的精准流量调度
LVS/HaProxy/Nginx: 摘除故障节点
可回滚
发布版本失败时可随时快速回退到上一个稳定版本
3.业务设计原则
防重设计
幂等设计
流程定义
状态与状态机
后台系统 *** 作可反馈
后台系统审批化
文档注释
备份
4.总结
先行规划和设计时有必要的,要对现有问题有方案,对未来有预案欠下的技术债,迟早都是要还的。
本文作者为网易高级运维工程师
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)