从2019年2月开始开发矿池程序时,从矿池开发的一个陌生人,从不懂到学习,到实践,本文没有办法记录全部细节,只将在实践过程当中遇到的重点问题记录一下,供后续人士参考。html
因为从事矿业软件开发的人,在全球都不多,从事矿池开发的就更少了,找不到能够参考的完整例子及各类问题的解答,因为遇到的问题又与各币种、算法、各厂家矿机等多因素相关,致使排查问题时,特别难以锁定。 算法
在网上搜索后,被普遍使用的矿池程序有mpos,nomp,unomp,CoiniumServ,以及基于nomp的各类变种矿池。咱们在对比了 CoiniumServ以及unomp后,选择基于unomp作基础,改造开发。数据库
性能问题:unomp 对nomp 改造主要是基于nomp使用MySql 后,MySql成为了整个系统的性能瓶颈。缓存
咱们在第一个版本开发时,也使用了基于 MySql(也兼容其它关系型数据库)作数据持久化存储,发如今 4000台机器时,MySql 已严重拖累了整个系统的效能,好在MySql虽然性能差,但并未出现过死机等状况,可靠性仍是很高的。基于此,若是多矿池,每一个矿池几万台矿机的量,MySql是扛不住了。所以,考虑更换持久化存储。能过性能测试,选择了MongoDB,它有超过10-100倍的性能提高,仍是在未作性能优化的前提下的测试结果。 性能优化
通过一周左右的时间,将数据存储更换为MongoDB, 目标选定为3万台矿机,在一台24核,16G的服务器上,能够稳定运行48-72小时,时有宕机,缘由未明。服务器
又是莫名的问题,排查陷入无头绪的各类尝试。首先,下降 CPU使用率,经过优化MongoDB,CPU使用率降到了 平均40%左右,最高90%,硬件在这个水平是恰好,知足需求。但宕机的问题,在48-72小时时,仍然发生,所以能够确信,问题没有获得根本解决。运维
查看分析日志,错误有: ide
这个异常提示,Redis内存耗尽, 为何为这样?缘由为缓存已达到Redis的内存使用上限,解决办法为:设置当Redis达到内存上限时,设置淘汰策略。这样可使已分配的内存置换出来。 性能
Redis 持久化存储时,若是数据量很大,好比10G以上,而服务器的内存又只有16G,此时将致使Redis转储失败,中止服务。解决办法:将Redis可使用的最大内存设置为 系统内存的一半如下。此时Redis 在Fork一个进程转储时能够正常进行。学习
另外,当Redis达到最大内存时,设置其不能中止服务。
如下错误至今没法解决:
2019-03-25 05:33:24,485 [79] ERROR IBeam.Cache.Redis.RedisProvider [(null)] - GetRedis Host=127.0.0.1,Port=6379,Error=System.InvalidOperationException: No servers are connected or configured. 在 CacheManager.Core.BaseCacheManager`1..ctor(String name, ICacheManagerConfiguration configuration) 在 CacheManager.Core.BaseCacheManager`1..ctor(ICacheManagerConfiguration configuration) 在 CacheManager.Core.CacheFactory.Build[TCacheValue](String cacheName, Action`1 settings) 在 IBeam.Cache.Redis.RedisProvider.GetRedis(String host, Int32 port, Int32 database, String password)
2019-03-25 05:33:24,485 [79] ERROR System.RuntimeType [(null)] - TryTimesDo TryTimes=2, ActionHandler=System.Object CGet(System.String),Val1=CPpI4tlMoULGbhXAx+FAg7nXox4=,Error=StackExchange.Redis.RedisConnectionException: No connection is available to service this operation: EVAL; SocketFailure on 127.0.0.1:6379/Interactive, origin: CheckForStaleConnection, input-buffer: 0, outstanding: 62, last-read: 1s ago, last-write: 1s ago, unanswered-write: 1s ago, keep-alive: 60s, pending: 0, state: ConnectedEstablished, in: 0, ar: 0, last-heartbeat: 1s ago, last-mbeat: 0s ago, global: 0s ago, mgr: RecordConnectionFailed_ReportFailure, err: never; IOCP: (Busy=0,Free=1000,Min=16,Max=1000), WORKER: (Busy=98,Free=925,Min=16,Max=1023), Local-CPU: n/a ---> StackExchange.Redis.RedisConnectionException: SocketFailure on 127.0.0.1:6379/Interactive, origin: CheckForStaleConnection, input-buffer: 0, outstanding: 62, last-read: 1s ago, last-write: 1s ago, unanswered-write: 1s ago, keep-alive: 60s, pending: 0, state: ConnectedEstablished, in: 0, ar: 0, last-heartbeat: 1s ago, last-mbeat: 0s ago, global: 0s ago, mgr: RecordConnectionFailed_ReportFailure, err: never --- 内部异常堆栈跟踪的结尾 --- 在 IBeam.Cache.Redis.RedisProvider.InternalGet(String cacheKey) 在 IBeam.Cache.Redis.RedisProvider.CGet(String cacheKey) 在 IBeam.MDAA.ActionHelper.TryTimesDo[T1,TResult](MAction`2 actionHandler, T1 val1, Int32 tryTimes)
表现出的现象为:Redis没有可用链接,重启Redis服务,故障排除,但问题是不知道Redis何时出故障,运维难度高。目前为了排除这个故障,将Redis部署为集群节点,由Redis节点保证服务的高可用。可能存在Socket端口耗尽的问题,因为没有时间去排查,直接将Redis服务移到Linux平台上,由专门的机器运行,或直接使用云平台的 集群节点。
另外,MongoDB在运行的近一个月时间中,前期运行一直都正常,但后面几天,伴随Redis宕机时,MongoDB也宕机,为了保证高可用及可靠性,建议仍是单独移出来单独部署或使用分片+复本集。
根据以上经验分开部署后的单机节点运行状况以下:
Redis服务器(8核16G):
能够看出,在3000台负载中,整个8核的使用率很低,能够将此节点降为 1核16G便可,咱们在实际使用中,Redis只是做为缓存使用,不开启持久化存储
Web及适配器服务器(4核4G):
在实际cpu负载监测下,CPU在计算期间的峰值达到了 40%,知足使用。
MongoDB服务器(4核8G):
从实际的运行中能够看出,一开始10000台矿机负载时,CPU占用为100%,能够运算出正常的结果,但建了索引优化后的负载为30000台,cpu占用只有7%左右,可见运行优化的重要性。
如下为Redis配置要点,生产环境中不能使用默认配置:
全部这些都影响Redis的可靠性和可用性,Linux中Redis的配置文件所在目录为:
/etc/Redis/Redis.conf
另外,配置完成后,检查绑定IP地址,检查端口号,检查ufw防火墙设置
集群配置参考连接: