elastic-job与xxl-job的实践数据对比。从多个维度,数据进行更适合的选择。
技术文档都比较完善,学习成本低。
官网地址:https://shardingsphere.apache.org/elasticjob/current/cn/overview/
E-Job 关注的是数据,增长了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。可是学习成本相对高些,推荐在“数据量庞大,且部署服务器数量较多”时使用算法
X-Job 侧重的业务实现的简单和管理的方便,学习成本简单,失败策略和路由策略丰富。推荐使用在“用户基数相对少,服务器数量在必定范围内”的情景下使用
前提条件均运行在K8S中,并且程序运行内存512M,正常运行12小时。
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT |
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT |
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS |
E-job稍微逊色一点,但是相差不多,对于上述比较的GC来看,个人觉得GC的可比性更重要。
集群部署唯一要求为:保证每个集群节点配置(db和登陆账号等)保持一致。调度中心通过db配置区分不同集群。
执行器支持集群部署,提升调度系统可用性,同时提升任务处理能力。集群部署唯一要求为:保证集群中每个执行器的配置项 “xxl.job.admin.addresses/调度中心地址” 保持一致,执行器根据该配置进行执行器自动注册等操作。
重写Quartz基于数据库的分布式功能,改用Zookeeper实现注册中心
作业注册中心: 基于Zookeeper和其客户端Curator实现的全局作业注册控制中心。用于注册,控制和协调分布式作业执行。
提供了调度器,支持日志查询,动态控制任务触发条件,支持配置邮箱地址进行异常告警。
需监听任务的处理是否成功,作业服务器是否存活,数据是否处理成功,自行编写告警程序。
支持并行调度,采用任务分片实现,可自定义分片策略,并且通过zk实现服务注册,控制,协调,对服务器压力更少
支持任务分片,更加执行起集群实现动态分片。因为是通过数据来实现弹性扩容,如果任务服务器多了,会对服务器造成一定的压力
综合来说,如果侧重于数据则使用E-job,侧重业务请使用XXL-job
]]>https://kubernetes.io/zh/docs/home/
自己动手安装部署,先通过命令简单熟悉下,尽量自己建立虚拟机进行安装部署。
https://kubernetes.io/zh/docs/tasks/tools/
Kubernetes用于容器化应用程序的部署,扩展和管理,目标是让部署容器化应用简单高效。
kube-apiserver
Kubernetes API,集群的统一入口,各组件协调者,以RESTful API提供接口服务,所有对象资源的增删改查和监听操作都交给 APIServer处理后再提交给Etcd存储。
处理集群中常规后台任务,一个资源对应一个控制器,而 ControllerManager就是负责管理这些控制器的。
根据调度算法为新创建的Pod选择一个Node节点,可以任意部署, 可以部署在同一个节点上,也可以部署在不同的节点上。
分布式键值存储系统。用于保存集群状态数据,比如Pod、Service 等对象信息。
kubelet是Master在Node节点上的Agent,管理本机运行容器的生命周 期,比如创建容器、Pod挂载数据卷、下载secret、获取容器和节点状态 等工作。kubelet将每个Pod转换成一组容器。
在Node节点上实现Pod网络代理,维护网络规则和四层负载均衡工作。
容器引擎,运行容器。
https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kubelet/
https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-apiserver/
https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-controller-manager/
https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-proxy/
https://kubernetes.io/zh/docs/reference/command-line-tools-reference/kube-scheduler/
Kubernetes 计划弃用就是kubelet中dockershim。
即 Kubernetes kubelet 实现中的组件之一,它通过CRI(gRPC server服务)与 Docker Engine 进行通信。
说白了就是docker与kubernetes两家没有谈好合作
利用containerd替换docker。
docker由 docker-client ,dockerd,containerd,docker-shim,runc组成,所以containerd是docker的基础组件之一。
下面是从containerd引过来的一张图
从k8s的角度看,可以选择 containerd 或 docker 作为运行时组件:Containerd 调用链更短,组件更少,更稳定,占用节点资源更少,调用链:
Docker 作为 k8s 容器运行时,调用关系如下:
kubelet –> docker shim (在 kubelet 进程中) –> dockerd –> containerd
Containerd 作为 k8s 容器运行时,调用关系如下:
kubelet –> cri plugin(在 containerd 进程中) –> containerd
K8s是一个扁平化网络。
即所有部署的网络组件都必须满足如下要求:
一个Pod一个IP
apiVersion: apps/v1 |
Pod:K8s最小部署单元,一组容器的集合
Deployment:最常见的控制器,用于更高级别部署和管理Pod
Service:为一组Pod提供负载均衡,对外提供统一访问入口
Label :标签,附加到某个资源上,用于关联对象、查询和筛选
Namespaces :命名空间,将对象逻辑上隔离,也利于权限控制
以太坊是一个为去中心化应用(DApp)而生的全球开源平台。
官方地址: https://ethereum.org/zh
以太坊主网于 2015 年上线,是世界领先的可编程区块链。和其它区块链一样,以太坊也拥有原生加密货币,叫作 Ether (ETH)。 ETH 是一种数字货币, 和比特币有许多相同的功能。
年份 | 历史名 | 区块高度 | 价格 | 概述 | 改进提议EIP |
---|---|---|---|---|---|
2013年11月27日 | 白皮书发布 | 0 | $0 | 该项目在 2015 年启动。但早在 2013 年,以太坊的创始人 VitalikButerin维塔利克·巴特林(V神) 就发表了介绍性[文章]。 | |
2014年4月1日 | 黄皮书发布 | 0 | $0 | 以太坊白皮书概要性地介绍了以太坊,以太坊黄皮书通过大量的定义和公式详细地描述了以太坊的技术实现的[文章]。 | |
2014年7月22日 - 9月2日 | 公开招募 | 0 | $0 | 以太币预售为期 42 天。 你可以使用比特币进行购买。[请阅读以太坊基金会公告] | |
2015-7月-30日 | Frontier | 0 | $0 | 边境是以太坊的最初版本,但在上面能做的事情很少。 它是在 Olympic 测试阶段之后进行的。 它面向技术用户,特别是开发者。 每个区块有一个 gas 限制为 5,000。 这个“缓冲”期使矿工能够开始工作,并使早期采用者能够安装他们的客户端而不必“匆忙”。 | |
2015-9月-7日 | Frontier thawing | 200000 | $1.24 USD | Frontier thawing 分叉取消了每个区块 5,000 gas 的限制,并将默认的 gas 价格设置为 51 gwei。 这开启了交易功能——交易需要 21,000 gas。 | |
2016-3月-14日 | Homestead | 1150000 | $12.50 USD | 展望未来的 Homestead 分叉。 其中包括若干协议修改和网络变更,使以太坊能够进一步进行网络升级。 | EIP-2\EIP-7\EIP-8 [EIP详情] |
2016-7月-20日 | DAO 分叉 | 1920000 | $12.54 USD | DAO 分叉是为了解决 2016 DAO 攻击 ,当时一个不安全 DAO 合约被黑客盗走了超过 3 百万个 ETH。 这个分叉将资金从错误的合约转移到 这个只有 withDraw 方法的新合约。 任何损失资金的人都可以在他们的钱包中为每 100 个 DAO 代币提取 1 个 ETH。 | |
2016-10月-18日 | Tangerine Whistle | 2463000 | $12.50 USD | 处理与价格低廉的操作代码有关的紧急网络健康问题 | EIP-150\EIP-158 |
2016-11月-22日 | Spurious Dragon | 2675000 | $9.84 USD | 1、调整操作码的价格以防止今后对网络的攻击。 2、启用区块链状态的“区块链减重”。 3、添加重放攻击保护。 | EIP-155\EIP-160\EIP-161\EIP-170 |
2017-10月-16日 | Byzantium | 4370000 | $334.23 USD | 拜占庭分叉: 1、将区块挖矿奖励从 5 ETH 减少到 3 ETH 2、将[难度炸弹]升级延迟一年 3、增加了调用其他合约的能力 4、添加加密算法以允许[第二层扩容] | EIP-140\EIP-658\EIP-196\EIP-197\EIP-198\EIP-211\EIP-214\EIP-100\EIP-649 |
2018-2月-28日 | 君士坦丁堡升级 | 7280000 | $136.29 USD | 君士坦丁堡分叉: 1、保证在 POS 实现前区块不会被冻结 2、优化 EVM 数据存储操作的 Gas 耗用量计量方式 3、添加了与尚未创建的地址进行交互的能力 | EIP-145\EIP-1014\EIP-1052\EIP-1234 |
2019-9月-8日 | 伊斯坦布尔升级 | 9069000 | $151.06 USD | 伊斯坦布尔分叉: 1、优化 EVM 数据存储操作的 gas 耗用量计量方式。 2、提高拒绝服务(DoS)攻击的弹性 3、使基于 SNARK 和 STARK 的 二层扩容第二层方案性能更佳 4、使以太坊和 Zcash 能够互操作 5、让合约能够引入更有创造性的功能 | EIP-152\EIP-1108\EIP-1344\EIP-1884\EIP-2028\EIP-2200 |
2020-1月-2日 | 缪尔冰川升级 | 9200000 | $127.18 USD | 缪尔冰川分叉将 难度炸弹 的启动延迟。 增加Pow 的区块难度可能会增加发送交易和使用数据库的等待时间,从而降低以太坊的可用性。 | EIP-2384 |
2020-10月-14日 | 质押合约部署 | 11052984 | $379.04 USD | [质押合约]将质押引入以太坊生态系统。 虽然这只是一个 ETH1.0 主网 合约,但它直接影响了启动 信标链重要的 Eth2 升级。 | |
2020-12月-1日 | 信标链的起源 | 1 (信标链区块高度) | $586.23 USD | [信标链]需要 16384 个 ETH 并且每个节点拥有 32 个 ETH 来保证网络的安全。 2020 年 11 月 27 日确定规则,并且在 2020 年 12 月 1 日开始生产区块。 这是实现 Eth2.0 愿景的重要一步。 | |
2021-8月-5日 | 伦敦升级 | 1296500 | $3292.71 USD | 「伦敦」升级顺利完成,作为以太坊2.0全面部署前的最后一次全网升级,「伦敦」重要性不言而喻,尤其是以太坊改进提案EIP-1559的激活,不仅消除了用户通过投标系统竞争区块包含的方法,更会从根本上改变以太坊交易机制和ETH供应量。 |
总结:2014年实行预售,可以从2016年到2017年价格上涨,然后2020年到2021年价格上涨。每次升级都会影响价格的波动。2020年12月上线的信标链,只是以太坊2.0“阶段 0”迈出的第一步,「伦敦」升级之后将会进入到「阶段 1」(最初预计是2021年完成,但目前几乎可以肯定会延迟到2022年),而 ETH 1.0ETH 2.0 的完整升级则可能需要5-10年。个人觉得可以买币,放个几年。
以太坊的智能合约并非现实中常见的合同,而是存在区块链上,可以被触发执行的一段程序代码,这些代码实现了某种预定的规则,是存在于以太坊执行环境中的“自治代理”
以太坊的智能合约设计很简明。
在以太坊,智能合约是可以处理资金的脚本,就是这么简单。
这些合约由我们称为“矿工”的参与方强制执行和证明。我们给这些矿工支付一种叫作 “Gas” 的东西,它是运行一份合约的成本。当你发布一份智能合约,或者执行一份智能合约,或者把钱转到另一个账户,你就要支付一些被转换成Gas的以太币。
图2 是一个简明的图示,图示是一个典型的 ERC20 通证发行过程:一个项目通过智能合约创建通证,这个通证是实体资产或线上资产的价值表示物。投资者(用户)发起交易,向智能合约转入以太币(ETH),智能合约自动运转,在满足一定规则后,它向投资者账户转入相应数量的通证。
在一个没有合约或货币的世界里,我们只能局限于同步的易货交易——你有一个苹果,我有一条面包,我可以当场用面包换你的苹果。 然而,我们交易的越多,就越有可能陷入经济学家所谓的需求的双重偶合(double coincidence of wants)问题:我们之间达成交易的前提必须是我们同时想要对方手里的东西,而这种情况不常出现。
货币是解决这个问题的一种方法。 我可以卖了面包换到钱,然后用钱换苹果或其他物品。通过钱,我们可以把双重需求减少成单一需求:我无需持有你想交易的东西;我可以通过后续交易获得苹果。这样时间限制就被削弱了。
合约的工作原理与货币类似,但它们能促进更多潜在的交易。 合约不要求同步交换价值,甚至不需要以货币作为中介。 我现在可以把一条面包卖出去,买方可以答应下个月付款给我。 这种能力从根本上扩展了我们可以进行的交易类型。
但仍有一个问题。 你怎么确定我会履行承诺付款给你? 我们如何建立可信的约定?
在点对点交易过程中,无论谁先履行合约都要承担对方违背合约的风险。 如果卖方先发货,买方可能不会付款;如果买方先付款,卖方可能不会发货。
怎么来解决这个问题?
解决方案是使用多重签名的智能合约,在针对在线交易的多重签名合约中,可以要求至少获得三方(买方,卖方和中立的第三方)中任意两方的签名。 第三方可以是任何人(或任何事物!),只要能让我们相信 ta 能公正地解决争议即可。 特别要注意的是,第三方仲裁员的权力非常有限,ta 们只能在买卖双方出现争议的情况下,决定将钱汇给其中一方。 仲裁员不能私吞这笔钱或是将它汇给买卖双方以外的其他人。
在2016年6月,一名黑客企图转移一大笔众筹资金 (350 万个 ETH, 占当时ETH总数的15%)至他自己的子合约,这笔资金被锁定在该子合约中 28 天。
众多创业公司使用的多重签名钱包的逻辑大多通过库合约实现。每个钱包都包含一个轻量级的客户端合约,连接到这个单点故障。漏洞是一种叫做wallet.sol的多重签名合约出现bug导致的,问题在于其中一个初始化函数只能被调用一次。
1、生成256位随机数作为私钥
2、将私钥转化为 secp256k1 非压缩格式的公钥,即 512 位的公钥。
3、使用散列算法 Keccak256 计算公钥的哈希值,转化为十六进制字符串。
4、取十六进制字符串的后 40 个字母,开头加上 0x 作为地址。
利用发送代币生成合约地址
利用Remix - Solidity IDE 网站来发布智能合约 [地址]
MetaMask是钱包的一种,在chrome浏览器中,安装MetaMask插件即可,安装完成后,右上角会出现一个“狐狸头”的标志,点击该标志,打开钱包,第一步,创建账户,(创建账户只需要输入面密码即可,名称创建后可以随便改,该账户就是一个hash值,如何给自己创建的账户冲以太币呢,你可以通过在交易所买入一些ETH,然后转入即可)创建成功后,记住密码还有产生的几个随机单词(一定要记录下来)。
注意事项:
合约代码引用版本需要与编辑器所选版本匹配
pragma solidity ^0.4.16; |
精度默认值decimals=18,就是小数点后18位。
BTC是8位,0.00000001 (Gwei) = 1(sat)
ERC20是18位,0.000000002578400219 (Ether) = 2.578400219 (Gwei)
注意事项:
MetaMask交易结果
链上交易详情[链上地址]
注意:对于EIP-1559升级后,文章后面会详细讲解矿工费机制。
指的是随着挖矿难度增加.[以太坊浏览器]
如图可以看出从20年中旬开始,难度指数上涨明显,这是因为ETH升级2.0造成的。
因为他们最终将希望矿工停止挖矿并开始验证工作。
以太坊(ETH)正试图通过将现有的工作量证明(PoW)共识算法切换为权益证明(PoS)共识算法来解决这个问题。挖矿的奖励将由参与者质押资金的大小决定,而非由现在的电力和资源密集型计算机算力决定。如果出现算法转变的情况,以太坊社区可能会选择通过硬分叉来完全移除或者延迟难度炸弹。
POW模式(接下来会讲)下ETH的出块速度
如图蓝色线是出块耗时时间,红色线是币价,黄色线是平均线(可以看出平均耗时在13.45秒)
如图中蓝色线,以太坊的发行每年产量被限制在7200万以太币的25%(每年以太币的矿产量,不高于1800万。7200万为一次性crowdsale而发行的以太坊)
按照这个总量来计算
区块奖励: 每挖一个区块奖励5个以太坊
叔块奖励: 有些区块被挖得稍晚一些,因此不能称为主区块链的组成部分。比特币称这类区块为“孤块”,并且完全舍弃它们。但是,以太币称它们为“ uncles”,并且在之后的区块中,可以引用它们。如果uncles在之后的区块链中作为叔块被引用,每个叔块会为挖矿者产出大约4.375个以太坊。目前每天有大约500个叔块被创建,每年产量为70万以太坊
叔块引用奖励: 矿工每引用一个叔块,就得到了大约0.15个以太币(最多引用两个叔块)
出块速度计算
一年3150万秒(365x24x60x60),每产生一个新区快就会奖励5个以太坊
出块速度 : 3150万 / ( (1800万-70万) / 5) ≈ 9 s
注: 这里的计算,忽略了叔块引用奖励,真实出块速度可能大于9s,目前真实平均在13.45秒。
以最高的日期算: 2021年5月9日星期日的最高交易数的tps是1716600/24/60/60 ≈ 19.868055笔
目前平均: 1250000/24/60/60 ≈ 14.4675笔
TPS困扰区块链久矣
很多区块链项目都面临着TPS性能不足的难题,区块链技术的鼻祖自然也不避免。一直以来比特币每个区块容量设置为1MB,平均每10分钟出一次块,在理想情况下TPS可以达到每秒7笔,但实际情况下只能达到每秒3到4笔。而且随着全网交易量走高,已经出现了拥堵的情况,很多交易无法上链,用户体验不好。如今比特币网络中未确认的交易数已经达到22000笔,将近60MB大小,也就是说平均要等待一小时的时间才可以确认。
伦敦升级(EIP-1559)升级后矿工费机制变更。
GasPrice越多速度越快,web3j默认取得Average值
思考? 这里为什么叫交易费用,而非矿工费?
对比升级前后的公式,可以看出 EIP-1559 是将 GasPrice 拆分成了两个费率的组合:baseFee 和 PriorityFee。
baseFee(基础费用)
baseFee 会根据上一区块的空间利用率自动调整,如果利用率超过 50%,则提升当前区块的 baseFee;反之降低。
按照 baseFee 计算公式,相邻区块间的 baseFee 变化幅度在 ±12.5% 之间:
不同于原来的矿工费机制,EIP-1559 升级后,交易费用不完全由矿工收取,其中 baseFee 将被完全销毁。
PriorityFee(小费)
PriorityFee 表示给矿工的小费,延续了竞价设计。如果希望自己的交易在区块中被尽快打包,可通过设置 PriorityFee 激励矿工,矿工将优先处理 PriorityFee 高的交易。
同时,用户还可以自行设置 PriorityFee 的最高值,即付给矿工小费的上限,也叫 maxPriorityFee。
maxFee(最高费用)
maxFee 表示用户愿意对某笔交易可支付的最高交易费用。对应到公式中,maxFee = baseFee + maxPriorityFee,其中 maxFee 和 maxPriorityFee 都支持用户自行设置,baseFee 则由算法自动给出。
注:升级后「矿工费」的说法已经不合适了,因为费用中的 baseFee 是要销毁的,只有 PriorityFee 由矿工收取。或许 EIP-1559 升级后,我们应该在以太坊生态中弃用「矿工费」的说法了。
maxFee | maxPriorityFee | baseFee | 销毁 | PriorityFee(矿工小费) |
---|---|---|---|---|
50 | 10 | 1 | 1 | 10 |
50 | 10 | 40 | 40 | 10 |
50 | 10 | 45 | 45 | 50-45=5 |
50 | 10 | 50 | 50 | 50-50=0 |
50 | 10 | 60 | 由于 maxFee 小于 baseFee,这笔交易无法进入当前区块,将继续排队 |
注:如果交易失败,交易费用会退款给源地址,但是其中的PriorityFee矿工小费不会退还。
Nonce决定了交易顺序,以上述链上交易详情[链上地址]为例。
排除非本账号发送方交易
可以看出同交易地址每交易一笔nonce则增加1,第一笔从O开始
共识机制(也称为共识协议或共识算法)允许分布式系统(计算机网络)协同工作并保持安全。
以太坊目前采用工作量证明 (PoW) 共识协议。这种机制允许以太坊网络的节点就以太坊区块链上记录的所有信息的状态达成共识,并防止某些产生经济影响的攻击。
工作量证明是一种允许去中心化的以太坊网络达成共识或者一致认可账号余额和交易顺序的机制,这个机制防止用户“双花”他们的货币。
名词解析:“双花”问题是指一笔数字现金在交易中被反复使用的现象。
以太坊的交易被处理为区块。 每个区块有一个:
区块的数据直接和 Pow 关联。
要求矿工经过激烈的试错竞赛,找到一个区块的 nonce。 只有具备有效 nonce 的区块才能被加入区块链中。
当通过比赛创建一个区块时,矿工将反复放置一个数据集,只能通过数学函数从下载和运行完整链(像矿工那样)中获得数据集。 这是为了根据区块所声明的难度,生成一个低于目标 nonce 的混合哈希(mixHash)。 做到这些最好的方式是试错。
难度决定了这个哈希(mixHash)的指标。 目标越小,有效的哈希值的集合就越小。 一旦哈希值生成,对于其他矿工和客户来说,是很容易校验哈希值是否有效的。
由于矿工是分散的,两个有效的区块是可以同时开采的。 这就造成一个临时的分叉。 最后只要两条中一条支链通过先挖出下一个区块成为最长的支链,这条支链就会被添加到主链上。
但为了使情况更复杂, 临时分叉上被拒绝的交易将会被记录在公认的主链上。 这意味着区块是可逆的。 因此,终局性是需要你等待一段时间至交易不可逆。 以太坊推荐的时间是等待 6 个区块或者超过 1 分钟。 这样你才能确定这笔交易已经成功。
简单来说,pow就是“按劳分配“一个矿工付出多少,提供多少工作证明就是能拿到多少报酬,这也是千百年来社会分配最公平的方式,自己购买显卡显然是有收益的,按照自己工作量获取报酬,多少矿机工作记录可以提供证明,就可以获取相应的报酬。
Eth升级到2.0,正在将其共识机制从工作量证明(POW)转变为权益证明(POS)
这将要求用户抵押他们的以太币从而成为网络中合法的验证者。 验证者有着与矿工在 工作量证明(pow)中相同的职责:将交易排序和创建新的区块,以便让所有的节点就网路状态达成一致。
权益证明相较于工作量证明系统有许多改进:
权益证明是一种用于激励验证者接受更多质押的基本机制。 就以太币而言,用户需要质押 32ETH 来获得作为验证者的资格。 验证者被随机选择去创建区块,并且负责检查和确认那些不是由他们创造的区块。 一个用户的权益也被用于激励良好的验证者行为的一种方式。 例如,用户可能会因为离线(验证失败)而损失一部分权益, 或因故意勾结而损失他们的全部权益。
与工作量证明不同的是,验证者不需要使用大量的计算能力,因为它们是随机选择的,相互间没有竞争。 他们不需要开采区块,他们只需要在被选中的时候创建区块并且在没有被选中的时候验证他人提交的区块。 此验证被称为证明。 你可以认为证明是说“这个块在我看来没问题”。 验证者因提出新区块和证明他们已经看到的区块而获得奖励。
如果你为恶意区块提供证明,你就会失去你的股权。
当以太坊用权益证明取代工作量证明时, [分片链] 的复杂性会增加。这是需要验证者来处理交易和创建新区块的独立区块链。 计划中将有 64 个分片链,并且它们都需要对网络的当下状态有一个共同的理解。 所以这需要额外的协调工作,这将由信标链来完成。
可以让验证者在某些检查点就一个区块的状态达成协议。 只要 2/3 的验证者同意,该区块就会被最终确定。 验证者如果试图稍后通过 51% 的攻击恢复,就会失去他们的全部权益。
现目前仍然是POW,还没有升级完,预计明年初,或者年末,应该有兼容版本行为。
BTC只有一个测试网络,为什么ETH会有多个,让我们一起来探究吧!
以太坊可以搭建私有的测试网络,不过由于以太坊是一个去中心化的平台,需要较多节点共同运作才能得到 理想的测试效果,因此并不推荐自行搭建测试网络。
测试网 | 共识机制 | 出块间隔(s) | 提供方 | 上线时间 | 备注 | 状态 |
---|---|---|---|---|---|---|
Morden | PoW | 以太坊官方 | 2015.7 | 因难度炸弹退出 | stopped | |
Ropsten | PoW | 30 | 以太坊官方 | 2016.11 | 接替Morden | running |
Kovan | PoA | 4 | 以太坊钱包Parity开发团队 | 2017.3 | 不支持geth | running |
Rinkeby | PoA | 15 | 以太坊官方 | 2017.4 | 最常用,只支持geth | running |
Goerli | PoA | 15 | 以太坊柏林社区 | 2018.9 | 首个以太坊2.0实验场 | running |
上图可以看出以太坊有一个主网络,四个测试网络。
Morden是以太坊官方提供的测试网络,自2015年7月开始运行。到2016年11月时,由于难度炸弹已经严重影响出块速度,不得不退役,重新开启一条新的区块链。Morden的共识机制为PoW。
现目前项目采用的web3j-api,采用的Ropsten网络,也是最接近主网络的。
Ropsten也是以太坊官方提供的测试网络,是为了解决Morden难度炸弹问题而重新启动的一条区块链,目前仍在运行,共识机制为PoW。测试网络上的以太币并无实际价值,因此Ropsten的挖矿难度很低,目前在755M左右,仅仅只有主网络的0.07%。这样低的难度一方面使一台普通笔记本电脑的CPU也可以挖出区块,获得测试网络上的以太币,方便开发人员测试软件,但是却不能阻止攻击。
PoW共识机制要求有足够强大的算力保证没有人可以随意生成区块,这种共识机制只有在具有实际价值的主网络中才会有效。测试网络上的以太币没有价值,也就不会有强大的算力投入来维护测试网络的安全,这就导致了测试网络的挖矿难度很低,即使几块普通的显卡,也足以进行一次51%攻击,或者用垃圾交易阻塞区块链,攻击的成本及其低廉。
2017年2月,Ropsten便遭到了一次利用测试网络的低难度进行的攻击,攻击者发送了千万级的垃圾交易,并逐渐把区块Gas上限从正常的4,700,000提高到了90,000,000,000,在一段时间内,影响了测试网络的运行。攻击者发动这些攻击,并不能获得利益,仅仅是为了测试、炫耀、或者单纯觉得好玩儿。
为了解决测试网络中PoW共识机制的问题,以太坊钱包Parity的开发团队发起了一个新的测试网络Kovan。Kovan使用了权威证明(Proof-of-Authority)的共识机制,简称PoA。
PoW是用工作量来获得生成区块的权利,必须完成一定次数的计算后,发现一个满足条件的谜题答案,才能够生成有效的区块。
PoA是由若干个权威节点来生成区块,其他节点无权生成,这样也就不再需要挖矿。 由于测试网络上的以太币无价值,权威节点仅仅是用来防止区块被随意生成,造成测试网络拥堵,完全是义务劳动,不存在作恶的动机,因此这种机制在测试网络上是可行的。
Kovan与主网络使用不同的共识机制,影响的仅仅是谁有权来生成区块,以及验证区块是否有效的方式,权威节点可以根据开发人员的申请生成以太币,并不影响开发者测试智能合约和其他功能。
https://app.mycrypto.com/faucet 使用时,注意体检切换你的metamask钱包网络。 它支持多个网络水龙头领币。
Rinkeby也是以太坊官方提供的测试网络,使用PoA共识机制。与Kovan不同,以太坊团队提供了Rinkeby的PoA共识机制说明文档,理论上任何以太坊钱包都可以根据这个说明文档,支持Rinkeby测试网络,目前Rinkeby已经开始运行。
目前开发人员最常用的测试网络是Rinkeby
以太坊 2.0 是一个 PoS 网络,由质押代币的验证节点来生产区块并维持网络运行。因此,首先要解决的问题是如何将代币分配给验证节点以运行网络。
水龙头(需翻墙,亲测可用 5ETH):https://faucet.dimensions.network/
水龙头(需翻墙,亲测可用 1ETH):https://app.mycrypto.com/faucet
水龙头:https://faucet.ropsten.be/
水龙头(需翻墙,亲测可用 1ETH):https://app.mycrypto.com/faucet
水龙头: https://faucet.rinkeby.io/
名称 | 地址 | 语言 | 支持系统 | 磁盘容量(快速同步) | 磁盘容量(完整归档) | 备注 |
---|---|---|---|---|---|---|
geth | https://github.com/ethereum/go-ethereum | Go | windows、linux和OSX | 400GB+ | 4.7TB+ | 最广泛的以太坊客户端 |
Open Ethereum | https://github.com/openethereum/openethereum/ | Rust | windows、linux和OSX | 280GB | 4.6TB+ | 最小内存和存储空间占用 |
nethermind | https://github.com/NethermindEth/nethermind | C#、.NET | Linux 、Mac 、 Windows | 200GB+ | 3TB+ | 性能强劲的虚拟机 |
Parity | https://github.com/paritytech/parity | C++ | Windows 、Linux、Mac | 前面出问题的客户端 |
世界分布
中国分布
以太坊官网开放了前段、后端相关的技术API文档。每个以太坊客户端都将履行 JSON-RPC 规范,因此我们有一个统一的端点组可供应用程序们依赖。
以whateverPay使用api举例,采用了web3j库。[参考文章]
在区块链上,数字加密货币分为原生币和代币两大类。代币之中又可分为同质化和非同质化两种
正如大家熟悉的比特币(BTC)、以太坊(ETH)等,拥有自己的主链,使用链上的交易来维护账本数据,交易手续费也是以原生币结算的。
则是依附于现有的区块链,使用智能合约来进行账本的记录,如项目方依附于以太坊发布的token。最多的是以太坊(Ethereum)上的ERC20代币,部署一个ERC20的智能合约就可以发布一个token。
即FT(Fungible Token),互相可以替代、可接近无限拆分的token。例如,你手里有一个ETH与我手里的一个ETH,可以拆分,1 ETH = 1 * 10^18 Wei,本质上没有任何区别,这就是同质化代币。
正如最近比较火:科比花55个以太坊(约18万美元,合人民币116万元)买下了一个猿猴头像。 孙宇晨韭菜王以1.2亿枚TRX购买NFT,价值约合1050万美元。有钱人的世界想象不到!
同质化代币,即NFT(Non-Fungible Token)属于ERC721协议,则是唯一的、不可拆分的token,如加密猫、艺术家的油画等。NFT都是独一无二、不可分割的。这意味着当一件作品被铸成NFT之后,这个作品就成为了区块链上独一无二的数字资产。
交易所的杠杆代币为ERC20代币,可直接在交易所的现货市场用USD进行交易。如果你有USDT的话,需要先在现货市场中使用USDT买入USD,然后再进行杠杆代币交易。需要注意的是,不管你在哪个交易所上交易他的杠杆代币,都会每天收取万三的持仓管理费,相较于其他交易所,管理费是最低的了。
下载DAPP进行交易吧,实际操作,真实体验。输赢则在那一刹间,先给自己定一个小目标,先来一个亿。
]]>使用Deployment控制器部署镜像
kubectl create deployment web --image=镜像地址 |
使用Service发布Pod
kubectl expose deployment web --port80 --type=NodePort --target-port=8080 --name=web |
K8s是一个容器编排引擎,使用YAML文件编排要部署应用,因此在学习之前,应先了解YAML语法格式:
- 缩进表示层级关系
- 不支持制表符”tab”缩进,需使用空格缩进
- 通常开头缩进2个空格
- 字符后缩进1个空格,如冒号、逗号等
- “—“ 表示YAML格式,一个文件的开始
- “#” 注释
apiVersion: apps/v1 |
等同于:kubectl create deployment web –image=镜像地址 –replicas=3 -n default
标签key | 含义 |
---|---|
apiVersion | API版本 |
kind | 资源类型 |
metadata | 资源元数据 |
spec | 资源规格 |
replicas | 副本数 |
selector | 标签选择器,下面metadata.labels保持一致 |
template | Pod模板 |
metadata | Pod元数据 |
spec | pod规格 |
containers | 容器配置 |
部署: kubectl apply -f xxx.yaml |
用get命令导出
kubectl get deployment nginx -o yaml > my-deploy.yaml |
Pod容器的字段拼写忘记了
kubectl explain pods.spec.containers |
Deployment是最常用的K8s工作负载控制器(Workload Controllers),是K8s的一个抽象概念,用于更高级层次对象,部署和管理Pod。其他控制器还有DaemonSet、StatefulSet等。
网站、API、微服务
多少钱
利用创建nginx为模板,创建nginx.yaml文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.16
执行创建yaml命令kubectl apply -f nginx.yaml
不使用yaml文件创建kubectl create deployment web --image=nginx:1.16 --replicas=3
在开始之前,部署Kubernetes集群机器需要满足以下几个条件:
角色 | IP |
---|---|
k8s-master | 192.168.31.61 |
k8s-node1 | 192.168.31.62 |
k8s-node2 | 192.168.31.63 |
关闭防火墙: |
Kubernetes默认CRI(容器运行时)为Docker,因此先安装Docker。
$ wget https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo -O /etc/yum.repos.d/docker-ce.repo |
配置镜像下载加速器:
$ cat > /etc/docker/daemon.json << EOF |
$ cat > /etc/yum.repos.d/kubernetes.repo << EOF |
由于版本更新频繁,这里指定版本号部署:
$ yum install -y kubelet-1.20.0 kubeadm-1.20.0 kubectl-1.20.0 |
https://kubernetes.io/zh/docs/reference/setup-tools/kubeadm/kubeadm-init/#config-file
在192.168.31.61(Master)执行。
$ kubeadm init \ |
或者使用配置文件引导:
$ vi kubeadm.conf |
拷贝kubectl使用的连接k8s认证文件到默认路径:
mkdir -p $HOME/.kube |
$ kubectl get nodes |
在192.168.31.62/63(Node)执行。
向集群添加新节点,执行在kubeadm init输出的kubeadm join命令:
$ kubeadm join 192.168.31.61:6443 --token 7gqt13.kncw9hg5085iwclx \ |
默认token有效期为24小时,当过期之后,该token就不可用了。这时就需要重新创建token,可以直接使用命令快捷生成:
kubeadm token create --print-join-command |
https://kubernetes.io/docs/reference/setup-tools/kubeadm/kubeadm-join/
注意:只需要部署下面其中一个,推荐Calico。
Calico是一个纯三层的数据中心网络方案,Calico支持广泛的平台,包括Kubernetes、OpenStack等。
Calico 在每一个计算节点利用 Linux Kernel 实现了一个高效的虚拟路由器( vRouter) 来负责数据转发,而每个 vRouter 通过 BGP 协议负责把自己上运行的 workload 的路由信息向整个 Calico 网络内传播。
此外,Calico 项目还实现了 Kubernetes 网络策略,提供ACL功能。
https://docs.projectcalico.org/getting-started/kubernetes/quickstart
$ wget https://docs.projectcalico.org/manifests/calico.yaml |
下载完后还需要修改里面定义Pod网络(CALICO_IPV4POOL_CIDR),与前面kubeadm init指定的一样
修改完后应用清单:
$ kubectl apply -f calico.yaml |
在Kubernetes集群中创建一个pod,验证是否正常运行:
$ kubectl create deployment nginx --image=nginx |
访问地址:http://NodeIP:Port
$ wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.3/aio/deploy/recommended.yaml |
默认Dashboard只能集群内部访问,修改Service为NodePort类型,暴露到外部:
$ vi recommended.yaml |
访问地址:https://NodeIP:30001
创建service account并绑定默认cluster-admin管理员集群角色:
# 创建用户 |
使用输出的token登录Dashboard。
https://kubernetes.io/zh/docs/setup/production-environment/container-runtimes/#containerd
1、配置先决条件
cat <<EOF | sudo tee /etc/modules-load.d/containerd.conf |
2、安装containerd
yum install -y yum-utils device-mapper-persistent-data lvm2 |
3、修改配置文件
vi /etc/containerd/config.toml |
4、配置kubelet使用containerd
vi /etc/sysconfig/kubelet |
5、验证
kubectl get node -o wide |
怎么查看容器日志? |
4核16G的设备,正常load average不大于4,表示系统一直处在负载状态,程序有异常。
4核16G的服务器,load率达到了 6.97, 6.70, 4.87.信息总览:
CPU 内核:4核
CPU load率: 6.97, 6.70, 4.87
总内存:15.3 GiB 使用内存:4.7 GiB 剩余内存:10.600000000000001GiB
TOP前5:
PID %CPU %MEM VSZ RSS Name
2805176 59.9 6.3 7.6 GiB 986.2 MiB java
2901828 13.1 5.4 4.1 GiB 847.4 MiB java
3532650 4.5 4.7 3.9 GiB 740.9 MiB java
3769112 3.0 4.2 5.5 GiB 657.7 MiB java
1619371 0.7 1.3 6.6 GiB 204.8 MiB java
注意:CPU load率: 6.97, 6.70, 4.87。load的平均值通过3个时间间隔来展示,就是我们看到的1分钟、5分钟、15分钟,load值和cpu核数有关,单核cpu的load=1表示系统一直处在负载状态,但是4核cpu的load=1表示系统有75%的空闲。
系统load高通常都是由于某段发布的代码有bug或者引入某些第三方jar而又使用不合理导致的,因此注意首先区分load高,是由于cpu高导致的还是io高导致的,根据不同的场景采取不同定位问题的方式。
- 死循环或者不合理的大量循环操作,如果不是循环操作,按照现代cpu的处理速度来说处理一大段代码也就一会会儿的事,基本对能力无消耗
- 频繁的YoungGC
- 频繁的FullGC
- 高磁盘IO
- 高网络IO
当束手无策时,jmap打印堆栈文件多分析分析吧,或许能灵光一现能找到错误原因。
jstat -gcutil pid 100 |
可以看出行O也一直在增加,几乎99,速度很快,老年代一下就满了,立马执行了YongGC,然后进入FGC的速度也快,2天就525了。
通过命令抓取dump文件,进行分析。jmap -dump:format=b,file=1.hprof pid
通过JProfiler分析1.hprof文件
上述分析结果可以直观的看出,创建的对象线程非常多,并且一直在加,释放很慢。
发现程序确实有类似代码
/**
* Provide a new ScheduledExecutorService instance.
*
* <p>A shutdown hook is created to terminate the thread pool on application termination.
*
* @return new ScheduledExecutorService
*/
public static ScheduledExecutorService defaultExecutorService() {
ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(getCpuCount());
Runtime.getRuntime().addShutdownHook(new Thread(() -> shutdown(scheduledExecutorService)));
return scheduledExecutorService;
}
因为此方法是通过一个业务定时器在轮序,2秒一次,每次都去执行了一次,所以造成了内存不足,load值增加,系统负载增加。
程序改用单例模式,静态方法,执行一次就行。
-XX:MaxTenuringThreshold=0 -XX:+UseConcMarkSweepGC -XX:CMSFullGCsBeforeCompaction=0 |
Map接口的基于哈希表的实现。
(ElementType.TYPE) |
其中比较重要的注解有@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解非常重要
(ElementType.TYPE) |
@Configuration注解是用来读取spring.factories文件
@EnableAutoConfiguration注解具有配置的功能,两则有什么区别?
(ElementType.TYPE) |
@EnableAutoConfiguration注解使用的是自动配置机制,是自动导入。
例如:在pom引入maven包,class自动import。<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.3.5</version>
</dependency>
class中自动import.import cn.hutool.json.JSONUtil;
(RetentionPolicy.RUNTIME) |
@ComponentScan的作用是告诉spring那个包下面的类用这个@Component注解,则会被spring自动扫描并且注入到bean容器。
]]>想必大家都比较熟悉RocketMQ,阿里开源消息队列项目。对于队列来说可以直接强势得理解成,处理并非、分布式事务得敌虫。
//实现监听 |
public TransactionSendResult sendMessageInTransaction(final Message msg, |
|
|
]]>业务场景源码正在创作..
定时服务无缘无故宕机了,服务相关日志没有任何错误日志。
首先报告领导
恢复业务
排查问题
监控服务
因服务没有监控,导致服务宕机没有发现,还是通过统计数据异常发现问题,立马去查看log日志。。。
# |
--------------- P R O C E S S --------------- |
ConcurrentHashMap相比于HashMap来讲,是线程安全的。底层的数据结构相同,都是数组+链表+红黑树。
因Segment继承ReentrantLock加锁,所以ConcurrentHashMap支持并发操作。static class Segment<K,V> extends ReentrantLock implements Serializable {
private static final long serialVersionUID = 2249069246763182397L;
final float loadFactor;
Segment(float lf) { this.loadFactor = lf; }
}
简单理解就是,ConcurrentHashMap 是一个 Segment 数组,Segment 通过继承ReentrantLock 来进行加锁,所以每次需要加锁的操作锁住的是一个 segment,这样只要保证每个 Segment 是线程安全的,也就实现了全局的线程安全。
concurrencyLevel:并行级别、并发数、Segment 数,怎么翻译不重要,理解它。默认是 16, 也就是说 ConcurrentHashMap 有 16 个 Segments,所以理论上,这个时候,最多可以同时支持 16 个线程并发写,只要它们的操作分别分布在不同的 Segment 上。这个值可以在初始化的时候设置为其他值,但是一旦初始化以后,它是不可以扩容的。再具体到每个 Segment 内部,其实每个 Segment 很像之前介绍的 HashMap,不过它要保证线程安全,所以处理起来要麻烦些。
Java8 对 ConcurrentHashMap 进行了比较大的改动,Java8 也引入了红黑树。
减小锁粒度是指缩小锁定对象的范围,从而减小锁冲突的可能性,从而提高系统的并发能力。减小锁粒度是一种削弱多线程锁竞争的有效手段,这种技术典型的应用是 ConcurrentHashMap(高性能的 HashMap)类的实现。对于 HashMap 而言,最重要的两个方法是get 与set 方法,如果我们对整个 HashMap 加锁,可以得到线程安全的对象,但是加锁粒度太大。Segment 的大小也被称为ConcurrentHashMap 的并发度。
ConcurrentHashMap,它内部细分了若干个小的 HashMap,称之为段(Segment)。默认情况下一个ConcurrentHashMap 被进一步细分为 16 个段,既就是锁的并发度。
如果需要在 ConcurrentHashMap 中添加一个新的表项,并不是将整个 HashMap 加锁,而是首先根据hashcode 得到该表项应该存放在哪个段中,然后对该段加锁,并完成put 操作。在多线程环境中,如果多个线程同时进行put 操作,只要被加入的表项不存放在同一个段中,则线程间可以做到真正的并行。
Map接口的基于哈希表的实现。
默认初始容量 (16) 和默认负载因子 (0.75) 的空HashMap,最大容量,在两个带参数的构造函数中的任何一个隐式指定更高的值时使用。 必须是 2 的幂 <= 1<<30 (1073741824)。
/** |
/** |
/** |
链表过长则使用红黑树,提高查找效率。
对此源码也做了解释。* Because TreeNodes are about twice the size of regular nodes, we
* use them only when bins contain enough nodes to warrant use
* (see TREEIFY_THRESHOLD). And when they become too small (due to
* removal or resizing) they are converted back to plain bins. In
* usages with well-distributed user hashCodes, tree bins are
* rarely used. Ideally, under random hashCodes, the frequency of
* nodes in bins follows a Poisson distribution
* (http://en.wikipedia.org/wiki/Poisson_distribution) with a
* parameter of about 0.5 on average for the default resizing
* threshold of 0.75, although with a large variance because of
* resizing granularity. Ignoring variance, the expected
* occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
* factorial(k)). The first values are:
*
* 0: 0.60653066
* 1: 0.30326533
* 2: 0.07581633
* 3: 0.01263606
* 4: 0.00157952
* 5: 0.00015795
* 6: 0.00001316
* 7: 0.00000094
* 8: 0.00000006
* more: less than 1 in ten million
上面这段话的意思是,如果 hashCode 分布良好,也就是 hash 计算的结果离散好的话,那么红黑树这种形式是很少会被用到的,因为各个值都均匀分布,很少出现链表很长的情况。在理想情况下,链表长度符合泊松分布,各个长度的命中概率依次递减,当长度为 8 的时候,概率仅为 0.00000006。这是一个小于千万分之一的概率,通常我们的 Map 里面是不会存储这么多的数据的,所以通常情况下,并不会发生从链表向红黑树的转换。
此问题参考连接
|
hashMap中元素个数超过【数组长度(容量)*localFactor(负载因子)】时,就会进行数组扩容。
现场安全标识
乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数 据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新), 如果失败则要重复读-比较-写的操作。
java 中的乐观锁基本都是通过 CAS 操作实现的,CAS 是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。
悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会block 直到拿到锁。java 中的悲观锁就是Synchronized,AQS 框架下的锁则是先尝试cas 乐观锁去获取锁,获取不到, 才会转换为悲观锁,如RetreenLock。
自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋), 等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
线程自旋是需要消耗 cup 的,说白了就是让 cup 在做无用功,如果一直获取不到锁,那线程也不能一直占用 cup 自旋做无用功,所以需要设定一个自旋等待的最大时间。
如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。
自旋锁尽可能的减少线程的阻塞,这对于锁的竞争不激烈,且占用锁时间非常短的代码块来说性能能大幅度的提升,因为自旋的消耗会小于线程阻塞挂起再唤醒的操作的消耗,这些操作会导致线程发生两次上下文切换!
但是如果锁的竞争激烈,或者持有锁的线程需要长时间占用锁执行同步块,这时候就不适合使用自旋锁了,因为自旋锁在获取锁前一直都是占用 cpu 做无用功,占着 XX 不 XX,同时有大量线程在竞争一个锁,会导致获取锁的时间很长,线程自旋的消耗大于线程阻塞挂起操作的消耗, 其它需要 cup 的线程又不能获取到 cpu,造成 cpu 的浪费。所以这种情况下我们要关闭自旋锁;
加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得
加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待
为了提高性能,Java 提供了读写锁,在读的地方使用读锁,在写的地方使用写锁,灵活控制,如果没有写锁的情况下,读是无阻塞的,在一定程度上提高了程序的执行效率。读写锁分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm 自己控制的,你只要上好相应的锁即可。
如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁
如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!
Java 中 读 写 锁 有 个 接 口 java.util.concurrent.locks.ReadWriteLock , 也 有 具 体 的 实 现ReentrantReadWriteLock。
独占锁模式下,每次只能有一个线程能持有锁,ReentrantLock 就是以独占方式实现的互斥锁。独占锁是一种悲观保守的加锁策略,它避免了读/读冲突,如果某个只读线程获取锁,则其他读线程都只能等待,这种情况下就限制了不必要的并发性,因为读操作并不会影响数据的一致性。
共享锁则允许多个线程同时获取锁,并发访问 共享资源,如:ReadWriteLock。共享锁则是一种乐观锁,它放宽了加锁策略,允许多个执行读操作的线程同时访问共享资源。
分段锁也并非一种实际的锁,而是一种思想ConcurrentHashMap中Segment分段锁。
只用在有线程安全要求的程序上加锁
将大对象(这个对象可能会被很多线程访问),拆成小对象,大大增加并行度,降低锁竞争。降低了锁的竞争,偏向锁,轻量级锁成功率才会提高。最最典型的减小锁粒度的案例就是ConcurrentHashMap。
最常见的锁分离就是读写锁 ReadWriteLock,根据功能进行分离成读锁和写锁,这样读读不互斥,读写互斥,写写互斥,即保证了线程安全,又提高了性能,具体也请查看[高并发 Java 五] JDK 并发包 1。读写分离思想可以延伸,只要操作互不影响,锁就可以分离。比如LinkedBlockingQueue 从头部取出,从尾部放数据
通常情况下,为了保证多线程间的有效并发,会要求每个线程持有锁的时间尽量短,即在使用完公共资源后,应该立即释放锁。但是,凡事都有一个度,如果对同一个锁不停的进行请求、同步和释放,其本身也会消耗系统宝贵的资源,反而不利于性能的优化 。
锁消除是在编译器级别的事情。在即时编译器时,如果发现不可能被共享的对象,则可以消除这些对象的锁操作,多数是因为程序员编码不规范引起。
]]>检验真理得决定性是实践。
[root@VM_0_12_centos 388]# free -m |
Linux在启动一个进程时,系统会在/proc下创建一个以PID命名的文件夹,在该文件夹下会有我们的进程的信息,
其中包括一个名为exe的文件即记录了绝对路径,通过ll或ls –l命令即可查看。
列入查看cpu高得服务情况PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 388 root 16 -4 114564 1264 1032 S 0.3 0.1 4:50.63 auditd 5646 root 20 0 573864 20200 2772 S 0.3 1.1 258:37.17 YDService 5990 root 20 0 576604 41248 12820 S 0.3 2.2 0:03.58 node /data/blog
查询PID等于388[root@VM_0_12_centos data]# cd /proc/388
[root@VM_0_12_centos 388]# ll
total 0
dr-xr-xr-x 2 root root 0 Mar 7 15:03 attr
-rw-r--r-- 1 root root 0 May 30 16:54 autogroup
-r-------- 1 root root 0 May 30 16:54 auxv
-r--r--r-- 1 root root 0 Mar 7 15:03 cgroup
--w------- 1 root root 0 May 30 16:54 clear_refs
-r--r--r-- 1 root root 0 Mar 7 15:03 cmdline
-rw-r--r-- 1 root root 0 Mar 7 15:03 comm
-rw-r--r-- 1 root root 0 May 30 16:54 coredump_filter
-r--r--r-- 1 root root 0 May 30 16:54 cpuset
lrwxrwxrwx 1 root root 0 Mar 24 02:36 cwd -> /
-r-------- 1 root root 0 May 30 16:54 environ
lrwxrwxrwx 1 root root 0 Mar 7 15:03 exe -> /usr/sbin/auditd
dr-x------ 2 root root 0 Mar 7 15:03 fd
dr-x------ 2 root root 0 May 25 10:09 fdinfo
-rw-r--r-- 1 root root 0 May 30 16:54 gid_map
-r-------- 1 root root 0 May 30 16:54 io
-r--r--r-- 1 root root 0 May 30 16:54 limits
-rw-r--r-- 1 root root 0 Mar 7 15:03 loginuid
dr-x------ 2 root root 0 May 30 16:54 map_files
-r--r--r-- 1 root root 0 May 30 16:54 maps
可以看出,即可追踪服务地址lrwxrwxrwx 1 root root 0 Mar 7 15:03 exe -> /usr/sbin/auditd
可查看详细信息USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.1 41108 2924 ? Ss Mar07 6:02 /usr/lib/systemd/systemd --system --deserialize 25
root 2 0.0 0.0 0 0 ? S Mar07 0:00 [kthreadd]
root 3 0.0 0.0 0 0 ? S Mar07 1:28 [ksoftirqd/0]
root 5 0.0 0.0 0 0 ? S< Mar07 0:00 [kworker/0:0H]
[root@VM_0_12_centos data]# du -sh |
linux SSH默认端口是22,不修改的话存在一定的风险,要么是被人恶意扫描,要么会被人破解或者攻击,所以我们需要修改默认的SSH端口。vi /etc/ssh/sshd_config
默认端口是22,并且已经被注释掉了,打开注释修改为其他未占用端口即可。
开启防火墙端口并重复服务即可。systemctl restart sshd.service
docker 必须掌握得命令
命令 | 描述 |
---|---|
docker images | 列出所有镜像文件 |
docker images -a | 列出所有得镜像文件-包括历史 |
docker rmi | 删除一个或多个镜像 |
命令 | 描述 |
---|---|
docker ps | 列出当前所有正在运行得容器 |
docker ps -l | 列出最近一次启动得容器 |
docker ps -a | 列出所有容器(包括历史,即运行过得容器) |
docker ps -q | 列出最近一次运行得容器ID |
命令 | 描述 |
---|---|
docker start/stop/restart | 开启/停止/重启container |
docker start [container_id] | 再次运行某个container (包括历史container) |
docker attach [container_id] | 连接一个正在运行的container实例(即实例必须为start状态,可以多个窗口同时attach 一个container实例) |
docker exec -it <container_id> /bin/bash | 进入容器 |
docker start -i | 启动一个container并进入交互模式(相当于先start,在attach) |
docker run -i -t | 使用image创建container并进入交互模式, login shell是/bin/bash |
docker run -i -t -p <host_port:contain_port> | 映射 HOST 端口到容器,方便外部访问容器内服务,host_port 可以省略,省略表示把 container_port 映射到一个动态端口。 |
注:使用start是启动已经创建过得container,使用run则通过image开启一个新的container。
命令 | 描述 |
---|---|
sudo docker cp host_path containerID:container_path | 从主机复制到容器 |
sudo docker cp containerID:container_path host_path | 从容器复制到主机 |
docker run –name cloud1 -h cloud1 -it jchubby/spark:1.0 | 利用镜像启用容器 |
命令 | 描述 | |
---|---|---|
docker rm <container…> | 删除一个或多个container | |
docker rm docker ps -a -q | 删除所有的container | |
docker ps -a -q | xargs docker rm | 同上, 删除所有的container |
命令 | 描述 |
---|---|
docker commit | 把一个容器转变为一个新的镜像 |
命令 | 描述 |
---|---|
docker export | export命令用于持久化容器 |
命令 | 描述 |
---|---|
docker logs $CONTAINER_ID | 查看docker实例运行日志,确保正常运行 |
docker inspect $CONTAINER_ID docker inspect <image或者container> | 查看image或container的底层信息 |
docker build | 寻找path路径下名为的Dockerfile的配置文件,使用此配置生成新的image |
docker build -t repo[:tag] | 同上,可以指定repo和可选的tag |
docker build -f | 使用指定的dockerfile配置文件,docker以stdin方式获取内容,使用此配置生成新的image |
docker port | 查看本地哪个端口映射到container的指定端口,其实用docker ps 也可以看到 |
Nginx详细配置
#运行用户 |
在项目中使用 Redis,主要考虑两个角度:性能和并发。如果只是为了分布式锁这些其他功能,还有其他中间件 Zookpeer 等代替,并非一定要使用 Redis。
如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的 SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。
特别是在秒杀系统,在同一时间,几乎所有人都在点,都在下单。。。执行的是同一操作———向数据库查数据。
根据交互效果的不同,响应时间没有固定标准。在理想状态下,我们的页面跳转需要在瞬间解决,对于页内操作则需要在刹那间解决。
如下图所示,在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用 Redis 做一个缓冲操作,让请求先访问到 Redis,而不是直接访问数据库。
缓存和数据库双写一致性问题
缓存雪崩问题
缓存击穿问题
缓存的并发竞争问题
这个问题是对 Redis 内部机制的一个考察。很多人都不知道 Redis 是单线程工作模型。
纯内存操作
单线程操作,避免了频繁的上下文切换
采用了非阻塞 I/O 多路复用机制
仔细说一说 I/O 多路复用机制,打一个比方:小名在 A 城开了一家快餐店店,负责同城快餐服务。小明因为资金限制,雇佣了一批配送员,然后小曲发现资金不够了,只够买一辆车送快递。
客户每下一份订单,小明就让一个配送员盯着,然后让人开车去送。慢慢的小曲就发现了这种经营方式存在下述问题:
时间都花在了抢车上了,大部分配送员都处在闲置状态,抢到车才能去送。
随着下单的增多,配送员也越来越多,小明发现快递店里越来越挤,没办法雇佣新的配送员了。
配送员之间的协调很花时间。
综合上述缺点,小明痛定思痛,提出了经营方式二。
小明只雇佣一个配送员。当客户下单,小明按送达地点标注好,依次放在一个地方。最后,让配送员依次开着车去送,送好了就回来拿下一个。上述两种经营方式对比,很明显第二种效率更高。
在上述比喻中:
每个配送员→每个线程
每个订单→每个 Socket(I/O 流)
订单的送达地点→Socket 的不同状态
客户送餐请求→来自客户端的请求
明曲的经营方式→服务端运行的代码
一辆车→CPU 的核数
于是有了如下结论:
经营方式一就是传统的并发模型,每个 I/O 流(订单)都有一个新的线程(配送员)管理。
经营方式二就是 I/O 多路复用。只有单个线程(一个配送员),通过跟踪每个 I/O 流的状态(每个配送员的送达地点),来管理多个 I/O 流。
下面类比到真实的 Redis 线程模型,如图所示:
Redis-client 在操作的时候,会产生具有不同事件类型的 Socket。在服务端,有一段 I/O 多路复用程序,将其置入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。
一个合格的程序员,这五种类型都会用到。
String
最常规的 set/get 操作,Value 可以是 String 也可以是数字。一般做一些复杂的计数功能的缓存。
Hash
这里 Value 存放的是结构化的对象,比较方便的就是操作其中的某个字段。我在做单点登录的时候,就是用这种数据结构存储用户信息,以 CookieId 作为 Key,设置 30 分钟为缓存过期时间,能很好的模拟出类似 Session 的效果。
List
使用 List 的数据结构,可以做简单的消息队列的功能。另外,可以利用 lrange 命令,做基于 Redis 的分页功能,性能极佳,用户体验好。
Set
因为 Set 堆放的是一堆不重复值的集合。所以可以做全局去重的功能。我们的系统一般都是集群部署,使用 JVM 自带的 Set 比较麻烦。另外,就是利用交集、并集、差集等操作,可以计算共同喜好,全部的喜好,自己独有的喜好等功能。
Sorted Set
Sorted Set 多了一个权重参数 Score,集合中的元素能够按 Score 进行排列。可以做排行榜应用,取 TOP N 操作。Sorted Set 可以用来做延时任务。
Redis 是否用到家,从这就能看出来。比如你 Redis 只能存 5G 数据,可是你写了 10G,那会删 5G 的数据。怎么删的,这个问题思考过么?
正解:Redis 采用的是定期删除+惰性删除策略。
为什么不用定时删除策略
定时删除,用一个定时器来负责监视 Key,过期则自动删除。虽然内存及时释放,但是十分消耗 CPU 资源。在大并发请求下,CPU 要将时间应用在处理请求,而不是删除 Key,因此没有采用这一策略。
定期删除+惰性删除如何工作
定期删除,Redis 默认每个 100ms 检查,有过期 Key 则删除。需要说明的是,Redis 不是每个 100ms 将所有的 Key 检查一次,而是随机抽取进行检查。如果只采用定期删除策略,会导致很多 Key 到时间没有删除。于是,惰性删除派上用场。
采用定期删除+惰性删除就没其他问题了么
不是的,如果定期删除没删除掉 Key。并且你也没及时去请求 Key,也就是说惰性删除也没生效。这样,Redis 的内存会越来越高。那么就应该采用内存淘汰机制。
在 redis.conf 中有一行配置:
该配置就是配内存淘汰策略的:
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 Key。(推荐使用,目前项目在用这种)(最近最久使用算法)
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 Key。(应该也没人用吧,你不删最少使用 Key,去随机删)
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 Key。这种情况一般是把 Redis 既当缓存,又做持久化存储的时候才用。(不推荐)
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 Key。(依然不推荐)
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。(不推荐)
一致性问题还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。前提是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。
另外,我们所做的方案从根本上来说,只能降低不一致发生的概率。因此,有强一致性要求的数据,不能放缓存。首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。
这两个问题,一般中小型传统软件企业很难碰到。如果有大并发的项目,流量有几百万左右,这两个问题一定要深刻考虑。缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。
利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。
采用异步更新策略,无论 Key 是否取到值,都直接返回。Value 值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。
提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的 Key。迅速判断出,请求所携带的 Key 是否合法有效。如果不合法,则直接返回。
缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。
给缓存的失效时间,加上一个随机值,避免集体失效。
使用互斥锁,但是该方案吞吐量明显下降了。
双缓存。我们有两个缓存,缓存 A 和缓存 B。缓存 A 的失效时间为 20 分钟,缓存 B 不设失效时间。自己做缓存预热操作。
然后细分以下几个小点:从缓存 A 读数据库,有则直接返回;A 没有数据,直接从 B 读数据,直接返回,并且异步启动一个更新线程,更新线程同时更新缓存 A 和缓存 B。
这个问题大致就是,同时有多个子系统去 Set 一个 Key。这个时候要注意什么呢?大家基本都是推荐用 Redis 事务机制。
但是我并不推荐使用 Redis 的事务机制。因为我们的生产环境,基本都是 Redis 集群环境,做了数据分片操作。你一个事务中有涉及到多个 Key 操作的时候,这多个 Key 不一定都存储在同一个 redis-server 上。因此,Redis 的事务机制,十分鸡肋。
这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做 set 操作即可,比较简单。
假设有一个 key1,系统 A 需要将 key1 设置为 valueA,系统 B 需要将 key1 设置为 valueB,系统 C 需要将 key1 设置为 valueC。
期望按照 key1 的 value 值按照 valueA > valueB > valueC 的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。
系统 A key 1 {valueA 3:00}
系统 B key 1 {valueB 3:05}
系统 C key 1 {valueC 3:10}
那么,假设系统 B 先抢到锁,将 key1 设置为{valueB 3:05}。接下来系统 A 抢到锁,发现自己的 valueA 的时间戳早于缓存中的时间戳,那就不做 set 操作了,以此类推。其他方法,比如利用队列,将 set 方法变成串行访问也可以。
Redis 在国内各大公司都能看到其身影,比如我们熟悉的新浪,阿里,腾讯,百度,美团,小米等。学习 Redis,这几方面尤其重要:Redis 客户端、Redis 高级功能、Redis 持久化和开发运维常用问题探讨、Redis 复制的原理和优化策略、Redis 分布式解决方案等。
]]>Aginity Workbench for Hadoop
]]>可视化管理HIVE数据、支持远程连接Hadoop根据dfs创建hive外部映射表。
基于Hdfs、hive、mysql数据处理案例,闲时自玩项目
数据采集方式有很多种,一般在项目中采用数据上报方式。本地为了方便测试则采用读取csv文件。后续python自动抓取数据。
链接: https://pan.baidu.com/s/1cOCe1GXAxtkXCUbvY0MWFw 提取码: r23c
数据量不多,侧重于功能
清洗数据,统计分析数据,结果存储HDFS ,加载至HIVE, Sqoop至MYSQL
public String transfer(File file, String folderPath, String fileName) throws Exception { |
//表 |
上述代码中有一步为load data 至hive。在于朋友交流中,他提醒可以直接利用
外部加载数据
,自此代码如下:
外部表
好处---------------------------------java代码----------------------------------------- |
hive支持sql操作(支持连表操作、排序),支持分区(此功能特别实用,比如数据量庞大时一般会按照天分表,此时就可以利用按天分区)
案列
:统计服装制造商主要城市分布 (因为hive字段与值对应错乱,但是导入至mysql不会错乱)hive> select count as addr,count(count) from commodity20190315 GROUP BY count; |
结果
:这是对一千多条的抽样调查,由此可见我们平时的衣物制造商地点广东广州
居多。
主要思想
:sqoop export –connect jdbc:mysql://IP地址:3306/mall –username root –password 123456 –table commodity20190315 –export-dir /hivedata/warehouse/hive.db/commodity20190314 –input-fields-terminated-by ‘,’ –input-null-string ‘\N’ –input-null-non-string ‘\N’
此命令是经过一下错误原因完善出来的。
--export-dir
:代表dfs文件目录,则是hive存储数据的地方
错误原因1
19/03/15 09:20:25 WARN tool.BaseSqoopTool: Setting your password on the command-line is insecure. Consider using -P instead.
19/03/15 09:20:25 ERROR tool.BaseSqoopTool: Error parsing arguments for export:
19/03/15 09:20:25 ERROR tool.BaseSqoopTool: Unrecognized argument: –input-null-string
19/03/15 09:20:25 ERROR tool.BaseSqoopTool: Unrecognized argument: \N
19/03/15 09:20:25 ERROR tool.BaseSqoopTool: Unrecognized argument: –input-null-non-string
19/03/15 09:20:25 ERROR tool.BaseSqoopTool: Unrecognized argument: \N
19/03/15 09:20:25 ERROR tool.BaseSqoopTool: Unrecognized argument: –input-fields-terminated-by
解决方式
:命令输入错误,注意“-connect”应该是“–connect”杠
错误原因2
19/03/15 09:41:47 ERROR mapreduce.TextExportMapper: Exception:
java.lang.RuntimeException: Can't parse input data: '2019春季新款chic条纹套头毛衣女装学生韩版宽松显瘦百搭长袖上衣,39.98,42.98,广东 广州,350'
at commodity20190314.__loadFromFields(commodity20190314.java:487)
at commodity20190314.parse(commodity20190314.java:386)
at org.apache.sqoop.mapreduce.TextExportMapper.map(TextExportMapper.java:89)
java.lang.Exception: java.io.IOException: Can't export data, please check failed map task logs |
解决方式
:检查数据是否包含“ ”空格,去掉空格,hive默认分割符–input-fields-terminated-by ‘,’,后续发现mysql表多了id,hive没有导致转码出错。
成功将HIVE数据导入MYSQL
因数据量较小,则想利用python爬取数据,数据量偏少。则通过第三方地址下载。
今日头条每天新闻信息在100条左右,最多抓取5天之内的数据。数据量极少。
数据集资源来源
:http://dataju.cn/Dataju/web/home 里面包含各种类数据集M-T级文件不等。是一个自娱自玩数据来源的好地址。
总条数
14270481
条
hive> select count(*) from commodity20190320; |
commodity20190320
此表是通过csv导入的全量数据,包含了时间段。
使用动态分区需要注意设定以下参数
:
默认值
:false 是否开启动态分区功能
: 默认false关闭默认值
:strict 动态分区的模式
,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。默认值
:100默认值
:1000默认值
:100000//查看表结构 |
---------------------------------java代码----------------------------------------- |
注意
:分区数据支持sql查询
对于大数据初学者的我,这才是我的第一步,都说万事开头难,坚持吧。
下一章则会着重介绍
.主要用于在Hadoop(Hive)与传统的数据库(mysql、postgresql…)间进行数据的传递,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中
sqoop主要有两个版本:1.4.x、1.99.x ; sqoop1和sqoop2两个版本。
报错
【-bash: sqoop: command not found】
报错
sqoop:000> show job |
原因是没有指定服务端,需设置 set server –host 主机名或IP地址
sqoop:000> set server --host 主机名或IP地址 |
可通过设置,查看错误原因
sqoop:000> set option --name verbose --value true |
export SQOOP2_HOME=/usr/local/sqoop/ |
org.apache.sqoop.submission.engine.mapreduce.configuration.directory=/usr/local/hadoop-2.7.7/etc/hadoop |
报错
Setting conf dir: /usr/local/sqoop/bin/../conf |
检查Hadoop环境是否配置正确
export HADOOP_HOME=/usr/local/hadoop-2.7.7 |
注意
:配置这个变量主要是让Sqoop能找到以下目录的jar文件和Hadoop配置文件:
官网上说名了可以单独对各个组建进行配置,使用以下变量:
$HADOOP_COMMON_HOME, $HADOOP_HDFS_HOME, $HADOOP_MAPRED_HOME, $HADOOP_YARN_HOME
若$HADOOP_HOME已经配置了,最好不要再配置下面的变量,可能会有些莫名错误。
第一种查看日志
[root@localhost bin]# sqoop2-server start |
第二种执行访问 http://IP地址:12000/sqoop/version
[root@localhost bin]# jps |
再次尝试 show job、show connector 没有报错 这说明安装部署成功
sqoop:000> show connector |
我想要的功能是将hive数据移入mysql,经对sqoop2的使用发现,sqoop2并不支持。遗憾。接下来将尝试sqoop1。
功能 | Sqoop 1 | Sqoop 2 |
---|---|---|
用于所有主要 RDBMS 的连接器 | 支持 | 不支持 解决办法: 使用已在以下数据库上执行测试的通用 JDBC 连接器: Microsoft SQL Server 、 PostgreSQL 、 MySQL 和 Oracle 。 此连接器应在任何其它符合 JDBC 要求的数据库上运行。但是,性能可能无法与 Sqoop 中的专用连接器相比 |
Kerberos 安全集成 | 支持 | 不支持 |
数据从 RDBMS 传输至 Hive 或 HBase | 支持 | 不支持 解决办法: 按照此两步方法操作。 将数据从 RDBMS 导入 HDFS 在 Hive 中使用相应的工具和命令(例如 LOAD DATA 语句),手动将数据载入 Hive 或 HBase |
数据从 Hive 或 HBase 传输至 RDBMS | 不支持 解决办法: 按照此两步方法操作。 从 Hive 或 HBase 将数据提取至 HDFS (作为文本或 Avro 文件) 使用 Sqoop 将上一步的输出导出至 RDBMS | 不支持 按照与 Sqoop 1 相同的解决方法操作 |
堆内存性能、垃圾回收性能
参数 | 含义 | 案例 |
---|---|---|
-Xmx | 设置JVM 最大堆内存 | -Xmx3550m |
-Xms | 设置JVM 初始堆内存,此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存 | -Xms3550m |
-Xss | 设置每个线程的栈大小.JDK5.0以后每个线程栈大小为1M,之前每个线程栈大小为256K应当根据应用的线程所需内存大小进行调整在相同物理内存下。减小这个值能生成更多的线程但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右需要注意的是:当这个值被设置的较大(例如> 2MB)时将会在很大程度上降低系统的性能 | -Xss128k |
-Xmn | 设置年轻代。大小为2G在整个堆内存大小确定的情况下,增大年轻代将会减小年老代,反之亦然此值关系到JVM垃圾回收,对系统性能影响较大,官方推荐配置为整个堆大小的3/8 | -Xmn2g |
-XX | 设置年轻代初始值为1024M | -XX |
-XX:MaxNewSize | 设置年轻代最大值 | -XX:MaxNewSize = 1024 |
-XX:PermSize | 设置持久代初始值 | -XX:PermSize = 256 |
-XX:MaxPermSize | 设置持久代最大值 | -XX:MaxPermSize = 256 |
-XX:NewRatio | 设置年轻代(包括1个伊甸和2个幸存者区)与年老代的比值 | -XX:NewRatio = 4(表示1:4) |
-XX:SurvivorRatio | 设置年轻代中伊甸区与幸存者区的比值。表示2个幸存者区(JVM堆内存年轻代中默认有2个大小相等的幸存者区)与1个伊甸区的比值为2:4,即1个幸存者区占整个年轻代大小的1/6 | -XX:SurvivorRatio = 4 |
-XX:MaxTenuringThreshold | 表示一个对象如果在幸存者区(救助空间)移动了7次还没有被垃圾回收就进入年老代如果设置为0的话,则年轻代对象不经过幸存者区,直接进入年老代,对于需要大量常驻内存的应用,这样做可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在幸存者区进行多次复制,这样可以增加对象在年轻代存活时间,增加对象在年轻代被垃圾回收的概率,减少Full GC的频率,这样做可以在某种程度上提高服务稳定性。 | -XX:MaxTenuringThreshold = 7 |
参数 | 含义 | 案例 |
---|---|---|
-XX:+ UseSerialGC | 设置串行收集器 | -XX:+ UseSerialGC |
-XX:+ UseParallelGC | 置为并行收集器此配置仅对年轻代有效即年轻代使用并行收集,而年老代仍使用串行收集。 | -XX:+ UseParallelGC |
-XX:ParallelGCThreads | 配置并行收集器的线程数,即:同时有多少个线程一起进行垃圾回收此值建议配置与CPU数目相等。 | -XX:ParallelGCThreads = 20 |
-XX:+ UseParallelOldGC | 配置年老代垃圾收集方式为并行收集.JDK6.0开始支持对年老代并行收集。 | -XX:+ UseParallelOldGC |
-XX:MaxGCPauseMillis | 设置每次年轻代代垃圾回收的最长时间(单位毫秒)如果无法满足此时间,JVM会自动调整年轻代大小,以满足此时间。 | -XX:MaxGCPauseMillis = 100 |
-XX:+ UseAdaptiveSizePolicy | 设置此选项后,并行收集器会自动调整年轻代伊甸区大小和幸存者区大小的比例,以达成目标系统规定的最低响应时间或者收集频率等指标此参数建议在使用并行收集器时,一直打开。 | -XX:+ UseAdaptiveSizePolicy |
-XX:+ UseConcMarkSweepGC | 即CMS收集,设置年老代为并发收集的.cms收集是JDK1.4后期版本开始引入的新GC算法它的主要适合场景是对响应时间的重要性需求大于对吞吐量的需求,能够承受垃圾回收线程和应用线程共享CPU资源,并且应用中存在比较多的长生命周期对象的的的.cms收集的目标是尽量减少应用的暂停时间,减少全GC发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代内存。 | -XX:+ UseConcMarkSweepGC |
-XX:+ UseParNewGC | 设置年轻代为并发收集可与CMS收集同时使用.JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此参数。 | -XX:+ UseSerialGC |
-XX:CMSFullGCsBeforeCompaction | 由于并发收集器不对内存空间进行压缩和整理,所以运行一段时间并行收集以后会产生内存碎片,内存使用效率降低。此参数设置运行0次Full GC后对内存空间进行压缩和整理,即每次Full GC后立刻开始压缩和整理内存。 | -XX:CMSFullGCsBeforeCompaction = 0 |
-XX:+ UseCMSCompactAtFullCollection | 打开内存空间的压缩和整理,在Full GC后执行。可能会影响性能,但可以消除内存碎片。 | -XX:+ UseCMSCompactAtFullCollection |
-XX:+ CMSIncrementalMode | 设置为增量收集模式一般适用于单CPU情况。 | -XX:+ CMSIncrementalMode |
-XX:CMSInitiatingOccupancyFraction | 表示年老代内存空间使用到70%时就开始执行CMS收集,以确保年老代有足够的空间接纳来自年代代的对象,避免Full GC的发生。 | -XX:CMSInitiatingOccupancyFraction = 70 |
服务器配置:8 CPU,8G MEM,JDK 1.6.X
参数方案:-server -Xmx3550m -Xms3550m -Xmn1256m -Xss128k -XX:SurvivorRatio = 6 -XX:MaxPermSize = 256m -XX:ParallelGCThreads = 8 -XX:MaxTenuringThreshold = 0 -XX:+ UseConcMarkSweepGC
调优说明: