Слияние кода завершено, страница обновится автоматически
DatabaseTikv.OperatesTikv
DatabaseDynamoDb 还需测试。
------------------------------------------------------------------------------------------------------------------------------
2024/ v1.4.9
------------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------------
2024/10/22 v1.4.8 History Compatible & Test; NewSolution; FreeMarker; Thymeleaf;
------------------------------------------------------------------------------------------------------------------------------
History Compatible 兼容性;@zl
NewSolution 新建项目助手; @zl
BUG History List2.indexOf 不能用默认的,因为它是equals判断,应该引用判断。@zl
BUG Record1.commit 需要加fair锁,跟load之间有竞争:load的if (... !dirty)和setSoftValue之间有时间窗口,
会导致commit的值(删除的时候是null)被还原成旧的值,删除语义失败,造成数据错误。
FreeMarker 接入,支持Web服务器端渲染。
Thymeleaf 接入,支持Web服务器端渲染。
------------------------------------------------------------------------------------------------------------------------------
2024/5/17 v1.4.7 Histroy; ServiceManager; Id128(udp); TimeAdaptedFund;
------------------------------------------------------------------------------------------------------------------------------
History 使用 Id128。
History 专门的Tid(使用Id128)分配服务器(基于udp)和Agent。
Id128UdpServer,Id128UdpClient.
TimeAdaptedFund 一个时间相关自适应数字,用来提供缓存方式分配器,用于AutoKey,PersistentAtomicLong。
Bean.followerApply 直接修改私有变量,可能需要修改成使用setter。
【放弃】
【1. 为followerAppy支持事务没有意义;2. 改动较大;3. 改动复杂;】
History 正确性验证,每次执行完Simulate做一次apply all并比对当前数据。只支持DatabaseMemory.
History TidCache 完成。
Histroy 数据库变更历史记账系统。
SM 删除updateService及相关。
检测内存占用,比如80%,做一次checkpoint。@zl
------------------------------------------------------------------------------------------------------------------------------
2024/4/26 v1.4.6 ServiceManager(incompatible); Profiler; decimal; HttpSession; SM.Exporter;
------------------------------------------------------------------------------------------------------------------------------
ServiceManager 删除启动延迟通知机制;【完成】
ServiceManager 删除ReadyCommit订阅模式;【完成】
TestAll Memory 【除了Direct,Sm,Timer相关测试,应该是配置问题】
ServiceManager.Agent 清理ReadyCommit订阅模式;由于暴露的接口对于不同模式有混合,需要小心;【完成】
Arch 清理ReadyCommit订阅模式相关代码,进行简化;【完成】
ServiceManager 完全去掉订阅模式;【完成】
ServiceManager 不兼容修改,简化回调,统一编辑接口。【完成】
Subscribe 改成批量模式,第一次的结果通过Rpc.Result返回。
UnSubscribe 改成批量模式。
# 删除c#ServiceManagerServer的服务器部分。
ServiceManager 增加服务多Version支持。
app.taskonebyone 删除了。
HttpSession 组件。
SM.Exporter 独立进程服务,输出SM信息到其他系统。
c# SM.agent 修改成适配新版SM协议。【编译通过】
------------------------------------------------------------------------------------------------------------------------------
2024/4/17 v1.4.5 ThreadDiagnosable;Service;StatLog; Raft; Dbh2; AppBase & Gen; ConcurrentHashMapOrdered; Hot;
------------------------------------------------------------------------------------------------------------------------------
Hot 所有服务器为单位进行原子的热更,避免新旧版本同时运行。能不能用就看实际疗效了。
Raft.Agent 去掉 urgentPending,统一使用 Zeze.Util.ConcurrentHashMapOrdered.
ConcurrentHashMapOrdered 【准备替换Raft.Agent.pending urgentPending.】【已修改!】
AppBase extends ReentrantLock & Gen.exe
synchronized -> ReentrantLock
Dbh2 Master.createTable synchronized (table) 改成 ReentrantLock,适配虚拟线程,否则很可能饥饿。
Raft 去掉两个ExecutorThreadPool. 使用 taskOneByOne 和 criticalPool;
全局唯一统计Logger,专门用来日志统计信息。使用者可以用log4j配置把统计日志记录到其他文件。@zl
ThreadDiagnosable 打印中断目标线程的堆栈。
Service 增加InstanceName,当前用于统计日志的输出,其他地方需要再加上。目前Dbh2RaftServer会设置这个属性。
------------------------------------------------------------------------------------------------------------------------------
2024/3/29 v1.4.4 DatabaseRedis; Operates; Dbh2PrefixTable;
------------------------------------------------------------------------------------------------------------------------------
Dbh2.Table 下构建 PrefixTable;
Dbh2 RocksDB多Table共享;【废弃,参考PrefixTable】
Raft RocksDB同一进程的Raft共享;【废弃,参考PrefixTable】
Dbh2 多个桶(raft)是并发初始化的吗?怎么启动那么久?【rocksdb必须一个一个打开,raft是异步的】【parallelStream】
Operates.tryLock unlock 本进程可重入。
DatabaseRedis
------------------------------------------------------------------------------------------------------------------------------
2024/3/15 v1.4.3 Raft.Dbh2; Halt Test; OfflineNotify;
------------------------------------------------------------------------------------------------------------------------------
Hot alter 测试,需要mysql。
在Dbh2上跑test all。
TestDatabaseHalt Dbh2 启动错误(再执行一次正常)怀疑问题(table创建等)。
ServiceManager::OfflineNotify 选择目标遍历优化。
【问题】
1. gs会注册自己关心的慢速离线通知,允许不同的gs注册不同的notifyId。
2. 当有gs离线时,需要遍历这个gs注册的notifyId,并从同时关注这个notifyId的gs中“随机”挑选一个作为通知对象(未来的接管gs)。
【放弃优化】
1. 现有的随机挑选是顺序选择,一般循环很少次数就能挑到。
2. 实际的注册方式是所有的连接等同,即大部分gs都是一样的,不会随便异构。
3. 顺序挑选在上千个gs时效率都足够高。
*. 最终,根据notifyId把相关gs组织到一个容器进行快速挑选没有必要,也过度复杂了。
Halt Test: 验证分布式后端数据库事务提交原子性。
Raft: Agent.ConnectorProxy; ProxyAgent.ConnectorEx; 解决proxy和raft-node之间映射的问题。
------------------------------------------------------------------------------------------------------------------------------
2024/2/29 v1.4.2 Global.Releaser; CheckpointMode; 3Others Component; Online Local; MetaGame; Timer;
------------------------------------------------------------------------------------------------------------------------------
MetaGame 迁移Task,World到这个独立项目。
Game.Online Local 表改成持久化+实现一个Clear,在停止和启动的时候执行一遍。
Dbh2 Query 是不是没有必要,可以省掉,
因为agent已经实现了永久重试,而查询也是agent实现的功能。重试+反向查询,功能重复了。
【保留】反向查询也有点用,用来处理agent出现问题数据就是,无法重试时,dbh2可以通过这个查询恢复状态。
3Others Component 第三方组件库,参见:git@gitee.com:e2wugui/ZeroBpm.git
规范一:
<Solution name="MySolutionName"> 项目自定义解决方案名字
<module name="builtion" id="1"> 所有第三方组件库的模块必须放在这个builtiin模块里面
<module name="" id="2"> 自定义模块...
规范二:
<component name="CExample" gendir="src/main/java" genrelativedir="zerobpm" platform="zeze+java"> genrelativedir 必须指定,比在提供默认值。
Global.Releaser reduceInvalidAllLocalOnly不在flush,改成全服checkpoint。
CheckpointMode 多线程及合并流程改成parallelStream.
------------------------------------------------------------------------------------------------------------------------------
2024/2/2 v1.4.1 World.Polygon;
------------------------------------------------------------------------------------------------------------------------------
World Polygon旋转移位。
World 根据line2d参数计算直线另一端点坐标。
------------------------------------------------------------------------------------------------------------------------------
2024/1/19 v1.4.0 Task; Dbh2 Doc; Doc; Bench Global Raft;
------------------------------------------------------------------------------------------------------------------------------
Dbh2 文档归档
Task 系统及相关继续完善。任务配置缓存!!!
------------------------------------------------------------------------------------------------------------------------------
2024/1/5 v1.3.9 Log4jQuery; Token; Dbh2.Operates; World; Astar.ScanNodes.maxScanNodes; Task & Reward; Database.Walk
------------------------------------------------------------------------------------------------------------------------------
Task & Reward 通用任务系统,包括奖励。
Database.Walk BUG 修复在soft被清除时没有装载的问题。
Astar.ScanNodes.maxScanNodes 限制。每次搜索创建结构来用。不共享Astar,ScanNodes变量。
World.ResourceMap2d, HugeMappedFile
Dbh2.Operates 实现完成。实现方式为,Master.Rpc服务。
Token SoftReference, RocksDb
Log4jQuery rotate的处理和测试。
------------------------------------------------------------------------------------------------------------------------------
2023/12/22 v1.3.8 Onz; Zoker; Dbh2; Log4jQuery
------------------------------------------------------------------------------------------------------------------------------
Log4jQuery TODO: loadIndex seekManager seekFile
Dbh2 Proxy Unknown问题解决:Raft.Server.OnHandshakeDone报告的LeaderIs在Proxy下不会给Agent,也不用包装了。
Onz Commit 持久化:抵抗网络和OnzServer宕机问题。
Onz 加上错误处理。
其中最难处理的commit丢失还没找到解决办法。
另外触发zeze.Checkpoint要不要更加可靠。
Onz flush 失败处理
Onz事务都是马上flush的,如果flush超时失败,会引起OnzServer触发丢失FlushReady的zeze.checkpoint。
Zeze服:rrs.flush协调超时后继续提交,退化为FlushAsync.
OnzServer: 2段式等待超时,也给已经ready的发送commit,退化为FlushAsync.
如此,Flush阶段的2段式并没有严格保证,正常情况下安静工作,超时时提供了日志共分析。
Onz=On Zeze,跨不同Zeze集群(不一样的Global)的分布式事务支持。
------------------------------------------------------------------------------------------------------------------------------
2023/12/4 v1.3.7 Writerside; Schemas; Memory Table; selectDirty; PLIst; IByteBuffer; BinLogger; Virtual-Thread;
------------------------------------------------------------------------------------------------------------------------------
Schemas 反悔新实现;【记住所有删除的变量】
zeze.docx 格式化成新的Writerside格式。
(请假了两周,@zl修订了一些中还要bug,记录一下打一个tag)
Memory Table.size 现实不正确,原因是cache的设计允许value为null,但这个对于momory表不合适,
旧修订:remove时,马上删除null value的记录。
更多修订:所有会导致null value进入cache的地方都需要设置事务回滚时删除记录。
zl修改了好多地方,大概率补全了。
selectDirty 在whileCommit中比较广泛的使用,此时保持了锁,而selectDirty旧实现可能会去global申请锁,导致分布式死锁。
修改方式是重新定义selectDirty,给他降级。即不再访问global,仅看本地有没有,没有直接从后端数据库读取,不管
数据是否最新。这个新定义仍然符合"dirty"的定义,而且避免了死锁的发生。
PList.replaceAll .sort 方法【加强】。
IByteBuffer 抽象和引用到decode中。
BinLogger
Virtual-Thread 的应用和相关修订。
------------------------------------------------------------------------------------------------------------------------------
2023/11/13 v1.3.6 DeadlockBreaker; Dbh2; Zoker; Raft;
------------------------------------------------------------------------------------------------------------------------------
Raft.Agent.driveOutNotSuggestMajorityLeader
把 Raft.Agent 包装进函数,用来检测Leader已经产生(有超时),
第一个应用是Dbh2异地备份方案的远程节点启动前用来等待Leader产生。
dbh2 0. raft异地备份方案,其中1/3 or 2/5异地运行,正常启动时,异地延迟启动,等主机房leader选出后再启动,
异常时异地可能成为leader,但故障恢复后,强制退出异地节点,把leader赶回主机房后再启动。难点在正常异常的判断。
Zeze内部errorCode带上模块Id,review!
死锁风险:限制在Listener中调用selectCopy;
dbh2 move走raft config更新确认
dbh2 4. dbh2 txnid 持久化生命期确认,是否仅针对执行中的事务?
【确认为tid仅在事务持续期间存在,数据里面没有,但是存在于raft-log中】
是否需要改成自己分配用long?
【已经改成long】
先禁用“自动删除不兼容的表。”以后删除相关代码。
jdk.findDeadLock(); 监控进程健康,否则要全部线程都死了,才可能被发现。
策略如下:
定时死锁检测,尝试打断环(优先打断事务-数据更安全)。告警。
连续3次发现死锁告警,启用了daemon的话,告知它进一步处理。紧急告警。
--- 测试,开启监控线程,unitetest专门的main制造死锁,daemon测试。
perf.txt @zl 其中slo待定.
"""
PerfCounter 现有的功能,统计次数,时间累计,protocol-recv-send-size?
现有功能需要zl理一下,翻了一下,没完全总结出来。
直接提需求,逐点讨论。一下提到的数字都应该可以配置。
1. 全局排名。
Perf定时计算排名,记录日志,是否存在某个负载比较均衡的,排名上不去,但是总计可能很高的?最终被忽略了。
2. 定时记录结果自动处理困难,会淹没管理员的问题。
slo: 99.9%请求处理时间在200ms内。否则记录日志并联系LogWeb告警。
同时对于超过200ms的请求每一条记录日志,用来做长尾分析。
3. Procedure正常处理结果99.9%都是0,不满足目标(错误累计超过0.1%)的记录日志,并联系LogWeb。
a) 结果不为0的已经有详细日志了。
b) Procedure本来在另一个统计里面,要不要合并到PerfCounter里面。在PerfCounter里面增加错误结果统计即可。
4. 连接流量统计99.9%的时间低于10MB,LogWeb高于告警。
5. Table 统计里面的Cache命中率 Cache Hit。默认90%。不达标警告LogWeb。
参考资料:区分平均值的“慢”和长尾值的“慢”的一个最简单办法是将请求按延迟分组计数(可以用来制作直方图):
延迟为0~10ms之间的请求数量有多少,30~100ms之间,100~300ms之间等。
将直方图的边界定义为指数型增长(这个例子中倍数约为3)是直观展现请求分布的最好方式。
"""
------------------------------------------------------------------------------------------------------------------------------
2023/10/27 v1.3.5 Raft & Dbh2; For IPV6 Format; Schemas; LogWeb; TableX.walk;
------------------------------------------------------------------------------------------------------------------------------
Protocol.getCriticalLevel 定义和Gen实现。其中Dispatch实现@zl。
zeze.doc 运维和配置
TableX.walk 回调改成copy-unlock-callback,去掉Runnable after。
Zeze.Auth: protocol 权限
1. 参考http的auth和acl,service dispatch 前增加调用:String authCheck(String account, moduleId, protocolId)。return null表示没有权限,否则表示权限detail。
2. auth detail是否需要?authCheck已经能控制每条协议权限,有这个detail,可以把它传到protocol.authDetail中,当协议实现的时候做更细权限控制。
3. Service 接口(例子):authCheck,默认返回"";
4. 第三方acl系统接入:为了接入这些可能的第三方系统,moduleId,protocolId可能需要合并成typeId。但是分开的好处是允许按module分配权限。
5. zeze 所需要的接口很小,"acl"管理需要一个系统。要使用第三方acl管理系统,必然做不了特殊的东西,所以考虑:::自己写一个管理系统?
6. "acl"用account,暂不考虑roleid,因为游戏系统看起来不需要这么细的权限控制,只有企业系统才可能需要。
7. authCheck可能不能做成service的接口,因为account只有再Provider.Dispatch里面才有。做成provider的扩展?这样权限检查就只能检查来自客户端,功能有所限制,但符合http性质了。
Zeze.Component.Auth 设计草稿
AuthKey=Beankey(moduleId, protocolId)
AuthValue=Bean(Map<AuthKey, String>) String: AuthDetailFlags,保留来扩展,默认为""。
table<account, AuthValue> tAuth;
问题,
AuthValue仅仅按单条记录来维护权限,存在表示有权限,要不要扩展成更多控制方式,
比如:AuthValue.GrantAllDefault,map此时表示deny,DenyAllDefault,map此时表示allow,
我暂时的想法是仅支持 AuthKey(moduleId, 0)表示整个模块grant,上面的all,deny,allow方式不支持。
大家看看有没有更好的办法。
ResetDB 删除,不再支持清除部分表。
把logweb发展成zeze.platform, @牛海涛
Schemas 为 dynamic 类型增加错误检查:1. 旧的映射不能被删除;2. typeId映射的className不能改变;
为了隔离代码,zeze部分代码的配置在创建时候拷贝一份传值进去,为了以后可能的支持配置重新加载,让配置尽可能“马上”生效,需要把配置的引用尽量改成对Config的直接读取。
这里存在几个问题:1. 马上应该是尽量的;2. Config里面的一个配置对象通常保存在容器中,每次使用需要查询一次,虽然是map,有没有好办法优化这个。
3. TableConf,ServiceConf都是把引用传入,以后不会跟随配置装载发生变化。这里考虑的优化是Config.reload实现的时候复用原来存在的TableConf,ServiceConf变量。
【配置尽量支持热更结论:不支持了,改成,当需要热更支持时,使用专门的控制台命令去修改,并且修改相应的支持。因为尽量支持热更没什么用,也很难。】
Tls 加入 AsyncSocket,可以利用 Netty 的类或者参考其中的实现,迁移代码出来。@zl
Connector & RaftConfig.Node 编码方式 host:port 在ipv6下有问题,需要改造。
1. raftagent会建立所有node的连接并保持,由于已有新链接建立能力,发现leader后可以关闭其他node的连接;
2. manager上有多个桶,每个桶都有独立连接,可以考虑用代理隧道复用连接使得一个manager只需要一个连接。
3. 优先级不高,后期优化再考虑。
raft异地备份分start,restart两个入口。dbh2共享链接master分配管理。
0. Master分配到同一个manager的桶的配置加上manager的ip,port给Agent,Agent先可选的使用,支持复用连接也可以直接联系raft。
1. Manager监听port用于服用连接。
2. Agent启用复用连接,把RaftRpc打包并且带上raft-bucket-id(目前直接可用的是raftconfig,比较长)。
3. Manager根据raft-bucket-id找到raft并dispatch,并且把当前服用连接设置到RaftRpc 中。
4. RaftRpc在sendResult的时候,发现有服用连接,则用服用连接的rpc打包并回复结果。
*. 【要点】raft-bucket-id的定义;复用rpc定义;首先需要搞清楚manager和bucket和raft的关系,确定新增ip,port保存在哪里;
*. raftConfig.node 增加manager的自定义。还挺麻烦!!!,先放放吧。应该修改RaftConfig.Node,增加RealHost,RealPort。
Raft/Proxy 多个raft节点运行在一个进程中,允许通过一个代理连接收发协议,共享这个连接,而不用每个节点建立自己的连接。
------------------------------------------------------------------------------------------------------------------------------
2023/10/9 v1.3.4 doc; Dbh2; LogService; TimeCounter; Arch; OverLoad;
------------------------------------------------------------------------------------------------------------------------------
【Arch加强】
二,负载均衡 参考Ribbon
Arch choice 负载均衡,需要按最近请求数量选择。适应用于无状态服务。
【LogService】
LogService 测试。
sessionall remain ”或“起来返回。
sessionall 自动维护已经remain false的。
1. sessionAll 全局搜索对局部remain的优化处理。
logservice 仅提供账号视图,角色有特殊性,角色自行进一步分析?
2. 某个用户的全局Log视图,仅提供账号视图,角色有特殊性,这个关键是Linkd需要记录account,roleId(即context)
【Redo与事务外交互的更强支持】
事务外交互只能whileCommit或者whileRollback,极大的限制逻辑流程编写的灵活性。
redo 与事务外交互的支持,提供txnid,外部服务用id唯一化请求,缓存结果,重复调用直接返回缓存结果。
参数变化问题,也加入txnid一起作为key判断?
这个事务外交互只适用于rpc,最低解决目标是搞定redirect,通用任意rpc性质调用lambda搞得定吗?
Rpc类请求.cache if in txn { txn.cache.put(txnid, result);/* 事务持续期间都不会失效 */} else { global.cache.put(txnid, result); /* 超时失效,比如5秒。 */ }
答案:经过讨论,rpc.cache 看来没什么用,如果要事务执行过程中使用rpc,整体逻辑以及第三方的实现应该能支持直接用。
可靠的方式,还是whileCommit,进行事务外调度比较好。
【Zeze多数据库两段式提交不完善】
zeze 多数据库时两段式提交不完善。如果局部commit失败,没有重做。但是重做需要侵入后端数据库,需要协作,有没有没办法???一般现有的中间件怎么处理这个问题的?
答案:zeze 在提交失败时,做了一定处理,下一次checkpoint.flush时,会再次重新执行保存(replace),对于kv数据库,这个应该足够安全了。
LogAgent 搭建完成。
Str.format;
Application.createServiceManager;
Connector.Name ip:port “:"是ipv6分隔符问题。【有点多,保留不修改了,需要解析麻烦点,也可以解析】
LogService 架子搭建完成。
Log4jQuery 完成核心算法。
Dbh2 增加 rpcTimeout 配置,用于raft和一般rpc请求。
------------------------------------------------------------------------------------------------------------------------------
2023/9/20 v1.3.3 Hot; Service KeepAlive(java c# c++); Memory;
------------------------------------------------------------------------------------------------------------------------------
0. dbh2.rocks 层调用不允许出错,有点过于相信底层了,怎么解决?出错了现在是abort,改成reset raft?
reset风险在于,如果多个节点都出错,都reset,最终导致数据状态丢失,无法恢复,而可能问题没那么严重,
可能只是磁盘满了,导致新数据不能写入,扩容后就可以恢复正常的。
检测某些错误才reset,不好定义,需要一点一点分析。
reset改成一个建议?让管理员决定操作,会不会让他们烦?
【Raft.addAtFatalKill注册事件,自行处理】
Memory Table Remove When Commit;
Linkd - Client KeepAlive 删除;以后开关纯走配置;
1. KeepAlive开启需要客户端实现onSendKeepAlive,然后走配置即可。
2. 原来Linkd的KeepAlive是用户代码,需要应用自己删除。
3. Zezex Zege 等地方删除KeepAlive?
4. serverdev 删除KeepAlive?
Linkd - Provider KeepAlive;开关走配置,原来没有KeepAlive,应该不需要改动;
【onSendKeepAlive 已实现,以后配置启用】
GlobalManager KeepAlive 确认?保留现有的或者改造成新的。
【GlobalKeep也绑定了逻辑,并且独立配置的(去使用底层会使得配置混乱),不修改了】
ServiceManager KeepAlive 确认?保留现有的或者改造成新的。
【SMKeep是服务器发送给客户端,绑定了不少逻辑,不修改了】
Online.Local Detect Test【内存表没有马上删除导致size不正确】【修改为commit时马上删除】
cxx KeepAlive NOT TEST.
KeepAlive 加入Service层,由Service负责踢掉超时的。Service需要增加回调。
HotManager 错误处理测试
1. stop 异常;2. _install 异常; 3. upgrade 异常; 4. start 异常;
* 1-3需要能恢复旧版如常工作,* 4将模块禁用,需要禁
删除Zeze.Util.Zezex.cs,注释掉Gen参数"ExportConf"
------------------------------------------------------------------------------------------------------------------------------
2023/9/8 v1.3.2 Hot; Online.Local; StartLast; Rank;
------------------------------------------------------------------------------------------------------------------------------
HotManager 错误处理。
两个不一样的目标:
1,尽量完成热更,模块热更失败,禁用模块。缺点是一旦发生错误,部分模块变得不可用。如果模块是有状态的,状态丢失。
2,发生错误,回滚恢复到热更前的状态,恢复程序执行。非常完美,但是任何错误都能完全恢复,难度很大。
*,现在是上俩目标的混合模式。
1. stop 【已完成】 已经停止的重新start并恢复,还没有停止的恢复(加入modules.Map),当前错误模块不再启动。
2. _install,upgrade,start 等任何其他错误,恢复热更安装前的状态。
var txn = new transaction(backup jar file);
try {
do ... _install.
3. upgrade 或者 start 错误的模块直接停止服务。
txn.commit(); // delete backup
} finally {
txn.rollbackIfNotCommit(); // restore backup jar file, restart stopped module, publish again 这里的部分逻辑同stop失败的处理差不多。
}
start,stop条件看zeze.doc;txn思路看todo.txt;install 流程介绍;未完成的rollback;halt与start;
Rank 加强。
1. test all redirect choiceServer 异常;
2. test all timer相关测试hot验证异常;以及app not start异常;
3. dbh2 redo咱么造成的以及超时异常。
Gen 增加 startLastModules, Module 增加 StartLast ... 改动兼容。
HotManager 错误处理。stop OK
Online.verifyLocal 增加功能,检测是否在linkd上存在session。Local.activeTime.
Online.setLocalBean,getOrAddLocalBean 限制只能在线时设置。
TimerRole.cancel 需要检查数据状态决定操作,getOrAddLocalBean改成getLocalBean。
Hot Memory 表格修改测试;Memory改成非,或反之测试。
Hot install new module need register sm,还需要module config choice type.
------------------------------------------------------------------------------------------------------------------------------
2023/8/25 v1.3.1 Hot; EventDispatcher; Memory-Table.SoftReference; CsQueue; CHashMap;
------------------------------------------------------------------------------------------------------------------------------
TestCsQueue
Zeze.Collections.Queue 不能使用DelayRemove,因为DelayRemove依赖了它。
因为Queue的删除只发生在Head,并且是单向链表,只会从Head往后Walk,
所以对于并发Walk,不会出现后面的node被删除找不到(_tQueueNodes.selectDirty返回null),导致中断Walk。
但是poll很快,删除node很快,超过Walk速度时,还是会出现_tQueueNodes.selectDirty返回null,
这会导致walk中断。采取的处理是,如果walk发现返回null,重新从头开始。哈哈哈。
Hot Module 拥有内存表现在禁止热更。允许的话需要像Online.Local一样做个retreat。这个操作框架可以帮忙完成,可能的实现代码和Online.Local的处理一样。
CsQueue,CHashMap还是值得写一个。
1. CsQueue就按昨天说的每server一个实例,server宕机其他server接管。
整体上破坏了一个队列FIFO的特性,但稍微打破一下这个整体概念,使用多队列并发模式对很多应用都是合适的。
我相信RockMQ也是类似的思路。这里提供全局的walk都没有必要,只要每个server walk自己+接管能力,最终数据都能得到处理。
2. class CHashMap {
private LinkedMap[] buckets;
public void put(String key, T value) {
buckets[stableHash(key) % buckets.length].put(key, value);
}
// 这里不叫CLinkedMap是因为使用了hash之后,LinkedMap的队列特性有点问题,只能当作hashmap来用了。
// linked特性想想有没有一个合适的处理和解释,否者就不提供了。
}
Hot Redirect 返回结果参数是自定义结构时不能作为接口暴露,怎么处理比较好。【有redirect的模块不支持热更】
Hot Test;
Hot TimerRole.Offline.CustomData 【属于Timer.Custom.Custom已由Timer处理】
Hot TimerAccount.Offline.CustomData 【属于Timer.Custom.Custom已由Timer处理】
Hot TimerAccount.CustomData 【保存在Online.Local中,已由Online处理】
Hot TimerRole.CustomData 【保存在Online.Local中,已由Online处理】
Hot Timer.CustomData
9. Game.Online.setLocalBean,热更后读取访问。
16. Game.Online.setUserData
7. TimerRole.scheduleOnlineHot, scheduleOnlineNamedHot, 相关方法调用
8. Timer.schedule 方法测试。这个方法在热更非热更下都能工作,但需要验证。
10. 有状态模块的热更测试,实现 HotService.upgrade 并验证热更正常。
4. 协议增加
5. 协议删除,旧版客户端现在会发生Dispatch错误,会被踢掉?
6. 协议修改
1. 表增加
2. 表删除
3. 表.Value结构修改
13. LinkedMap
14. Queue
15. DepartmentTree
linkd choiceHash 加入AppVersion。【实际上修改choiceProviderAndBind,总流程里面加了补丁】
Hot replace relationalTable
【每次更新,不管更新几个模块,都发布一个最新的 __hot_schemas__{SolutionName}.ja】
【Zeze.Application.schemas会给更新】
【然后,table.open按正常方式查询relationTable】
HotBeanFactory
Hot Redirect 返回结果参数是自定义结构时不能作为接口暴露,怎么处理比较好。
【暂定就不能暴露,自己定义可以暴露的接口,然后内部使用redirect】
Hot Zeze服务保存的状态(一般是dynamic里面的bean)
2. Collections.LinkedMap
_tInnerTable.cache.clear();
_tInnerTable.BeanFactory.put(BeanName) & BeanFactory 使用 HotRedirect 能找到模块内的新的类。
1. BeanFactory.resetHot(hotModuleJars_Current_JarFile_List); // bean只会增加或修改,不会删除。
2. HotRedirect.loadClass
class.forName(name) -> hotmanager.load(name).getConstrutor().newInstance();
Hot Zeze服务保存的状态(一般是dynamic里面的bean)
1. Online.LocalData, Timer.CustomData
upgrade() { bb = current.encode(); Cl.Class.newInstance().deocde(bb); }
tlocal 实际上是内存表,这个表不能clear,只能升级。
内存表怎么让local_cache生效,可以让SoftReference生效。
setDirty永远不会true,并且不引用成strongDirtyValue,
这样SoftReference就能生效,看看有没有其他问题。
【关键点验证这个:内存表的dirty没什么意义,除了soft这里,checkpoint不会跟它打交道。】
TableX.walkCache 有Bug,SoftReference 被回收,会遍历不到。【由于内存表肯定是脏的,不会被切换出去,所以刚好可以工作】
Bean.Hot 删除,以及删除名字相关的操作代码。
Online模块:事件订阅(EventDispatcher)
HotHandle Ok, HotClass 不缓存,直接依赖Cl的缓存即可。
Test 热更后重新注册协议【重新注册已经确认,但没有测试协议生效】。
Test 热更后Zeze里面Table的引用替换。
【多个模块一起热更的启动顺序】已经支持顺序。但是顺序定义从哪来?暂定在发布集合里增加一个顺序配置txt。
------------------------------------------------------------------------------------------------------------------------------
2023/8/11 v1.3.0 Timer Bug; Hot; Record1 snapshotXLocal Bug; Timer Hot; Bean.variables & toPrevious
------------------------------------------------------------------------------------------------------------------------------
HotManager interface.jar findClass 方式一个一个搜索有效率。
2. Bean Version Managed. 多个版本如:BeanSome_2_, BeanSome_1_, BeanSome,版本为0的Bean没有后缀,兼容非多版本模式.
3. DistributeServer. 发布包服务器(java),Gen(c#)需要访问获得发布Bean的信息。
Bean.toPrevious() 实现方案选择:
1. reflect 有风险,需要准确识别var,有一点点会影响扩充bean的方法,最大的问题是varid不好找了。
2. reflect 还是用这个方案,生成bean的时候,在getter方法里面生成注解,标明varid,有这个注解的就是var并且varid也有了。
【3选定】. 定义下面的Variable结构,生成提供原始信息。
public static class Variable implements Serializable {
public final int id;
public final String name;
public final String type;
public final String key;
public final String value;
}
public List<Variable> Bean.variables() {
var vars = super.vaiables();
vars.add();
return vars;
}
GenModule.instance.compiler.classloader 只设置一次,只维护一个实例。
Timer 热更模块Handle测试。
Hot Timer:HotRedirect + Cache: 关键 Cache 在模块热更后怎么清除?
Hot TimerRole & TimerAccount
这两个handle不会持久化,只发生在本进程中,原来直接传入引用。
旧版限制只能非热更模块使用;
新版接口如下:
scheduleHot(... Class<? extends TimerHandle> handleClass, Class<? extends TimerHandle> handle...)
方法名字增加Hot,明确区分原有方法,参数改成handleClass。
直接暴露数据表 @zl
TODO 模块内的bean跟随module.interface.jar发布。
TODO 多版本Bean的TypeId需要一样。
【Redirect】Zezex Build 的时候redirect在名字空间生成了,这个需要确认一下,不用修改。
打包(Zeze.Hot.Distribute)的时候需要把这个class归类到对应的module里面。
HotRedirect & GenModule.compile @zl
Hot bean.data 是Bean的内嵌类,TypeId已经兼容处理,不需要其他额外操作。
Hot zeze 功能之Timer规范。
Hot Bean版本管理基本支持。
Hot redirect 参数结果类型规范。
Hot Demo,完成核心,改造了Zezex用于测试。
Timer Bug: 1. LoadTimer first参数in|out,直接修改导致redo的时候跳过当前node。2. 注册futues避免重复。
------------------------------------------------------------------------------------------------------------------------------
2023/7/28 v1.2.9 World mmo.MoveSimple; World.Astar; ThreadDiagnosable; TaskOneByOneByKeyLru; AppVersion
------------------------------------------------------------------------------------------------------------------------------
热更发布之ClassLoader调研。doc/热更发布.txt
c) server 给linkd报告Info时带上版本号。
d) linkd 发现多个版本号,则只给最新的分发新登录。
*) 上两个功能只影响choiceLoad,choiceFeedFullOneByOne, 其他方式不判断版本号,这个需要确认一下。
Transaction 抛出 Redo 异常,但是没有 Redo。【确认是Timer的BUG,已修复】
TaskOneByOneByKeyLru 每个key一个队列的版本。
ThreadDiagnosable 对线程执行状况进行保护:目前只有超时interrupt功能。
World.Astar
World mmo.MoveSimple
World Framework first test
------------------------------------------------------------------------------------------------------------------------------
2023/7/14 v1.2.8 World Framework; Gen conf+cs+net component; c# BeanFactory;
------------------------------------------------------------------------------------------------------------------------------
confcs CreateBeanFromSpecialTypeId_ 用于客户端,可能存在老的客户端,此时发现不支持新增bean,不抛出异常。
c# beanFactory? @zl
这个方案需要考虑一下。
不一定需要实现成java的全部class搜索。
错误处理应该更加温和。
【实际实现,工厂在没有找到时返回null,并在DynamicBean里面设置EmptyBean】
Gen component
客户端(c#)无实现时,看成普通模块引入生成即可。
客户端(c#)包含实现时的:
1. 每个客户端模块一个项目。需要时加入自己项目的依赖。
2. 按无实现方式生成好并实现;提交所有生成。
3. 这个客户端模块不包含App,网络等。
4. 先按目前Gen走一遍,看看是否需要做点修改。
【实际修改是,conf+cs+net支持组件生成】
Wold Framework
------------------------------------------------------------------------------------------------------------------------------
2023/6/30 v1.2.7 Dbh2 Move; Threading; Zege;
------------------------------------------------------------------------------------------------------------------------------
Zege 群的操作客户端。
Zege 群加密。
Zege 群成员之间发送Notify。用来发送群秘密证书等。
Zege 好友列表的Id好像必须编码???
Zege Notify使用了LinkedMap,节点数据可能较大,还是保持增量更新。【XXX】
Zege 客户端增加登录窗口步骤(现使用Shell实现,也不知道对不对,反正能工作)。
Zege 【重构,更加清晰的逻辑层和界面层】UI 自己从底层模块获取ItemSource并设置,而不应该把窗口传入,让里面设置。【底层模块应该完全不知道UI】
Zege MainUI:Tab,整合Notify窗口。
Zege 重新能跑啦。
c# 并发比冲突还慢【怀疑Nito.AsyncEx的性能问题,换成DotNext.Threading】
==> 换成DotNext.Threading,并发还是慢。其中AsyncMonitor还是用老的,但应该对主要性能没有影响。
==> 有个现象,当async task收集完成的时间和加上wait all的时间几乎一样。这说明存储过程任务太简单,导致性能统计
==> 会被其他微小的条件影响。
==> 虽然还是没找到为什么并发模式就是慢一倍。
Dbh2 全桶迁移? 【未测试】
0. 全桶迁移发起策略:单个manager负载超过max*0.6,但是每个桶都没有达到分桶负载。
1. 拷贝算法数据同分桶。
2. 迁移完以后,本地数据全部删除,但是桶的Meta保留,需要保存迁移目的桶的Meta信息用来在拒绝时重定向。
3. 迁移桶完成时,更新到新的Meta的原子化问题需要重新考虑。
java finalize 只能执行一次?复活以后也不会再次调用 【zl确认,确实如此!】
Semaphore 没有acquire就release,表现为资源增加。
Threading timeout max。
Threading 基本完工。
------------------------------------------------------------------------------------------------------------------------------
2023/6/9 v1.2.6 Config.Customize; Dbh2 Lock Options, Walk, CreateTableAsync;
------------------------------------------------------------------------------------------------------------------------------
Dbb2 方案3 !!!【重新确认用了方案3】
Dbh2 接入Zeze:CheckpointFlush 慢。???
Dbh2 BenchClient 输入"exit" 退不出。
Dbh2 BenchClient.Query 哪来的,问题需要追踪。这个也会导致split end结束不了。
拒绝模式的分桶信息没有写完全!!!
Dbh2 walk;
Dbh2 事务实现方案。【采用了方案2】
1. rocks.writeBatch 统计记录undoLogs。缺点进行中的事务的数据马上可见了。(现方案)
2. rocks.TransastionDB 真正到达rocks的两段式提交协议。有prepare阶段。
优点,真正落地到底层的两段式。
缺点,性能降低近20%,不支持deleteRange(endSplit需要自己实现成一点点删除)。
3. (zl提供)我们自己把Batch数据系列化并写入表的另一个ColumnFamily(提交中事务专门保存点)。
commit时把事务数据取出写入真正的ColumnFamily,同时删除。
rollback时直接删除事务数据。
优点,进行中事务落地,不需要维护事务对象了。
缺点,没有测试过,不知道性能如何,应该不比方案1差。
Dbh2 事务模式回滚成RocksDb.Batch模式。TransactionDB模式下,deleteRange不支持,备份(Snapshot)需要修改。
Dbh2 OptimisticTransactionDB(Two phase commit not supported for optimistic transactions.) --> TransactionDB
Zeze.Util.RocksDatabase 增加事务支持。
Dbh2 create table async. & connect to all bucket.
Dbh2 【锁】
Get 不再加锁,完全信任Zeze;
Write-Trans加锁加一个开关,默认实现加锁,对写进行系列化保护,但是可以关闭,也完全信任Zeze;
Config.Custom 修改接口。去掉一开始注册。
【问题】
Custom实例需要预先new出来,在Config.loadAndParse之前注册到Config中。
这个方式在涉及到Config传递给多个地方,以及多个地方可能都有自己的Custom时非常不好用。
【这是不兼容修改】
1. Config.Load时记住map<CustomName, XmlElement>。
2. 增加方法 parseCustom(custom),查找map并调用解析。
3. 其他Custom方法都删除。
【现有代码怎么改】
去掉addCustom调用,改成调用config.parseCustom。parseCustom可以随时根据需要调用。
------------------------------------------------------------------------------------------------------------------------------
2023/6/2 v1.2.5 Netty DispatchMode; Dbh2; Game.Online.sendOnlineRpc;
------------------------------------------------------------------------------------------------------------------------------
Dbh2 接入Zeze跑通单元测试。
Zeze.Component 里面用到的DynamicBean注册class不需要了。
【持久化到表的清理,register的调用保留使得beanFactory可以使用局部map,效率更高】
LinkdUserSession.keepAlive 机制每次重新调度定时任务比较费。
改成集中式或者更高效的方式(TimerWheel).
还有保活时间10m太长了吧。
Dbh2:超时事务回查超时。
【重构以后Dbh2AgentManager启动手动start】
【Commit.ProcessQueryRequest DispatchMode.Critical,否则可能产生饥饿】
Dbh2:splitting end ... 之后没有到达splitting end done。(但是较长时间以后,会重启split),
怀疑中间raft出现问题或者setupPrepareQueue()有问题或者有事务一直结束不了。
事务一直没有结束问题需要解决一下,它会阻止splitting end导致一直无法进行其他服务。
【增加每秒超时暂时放行机制】
Dbh2:重启之后splitting restart,但是一段时间后又开启了新的split【性能统计设置loadSwitch时需要清除旧的负载统计】
+++Raft 心跳改成总是间隔发送,不再优化(真的空闲才发送);原因如下:
+++Dbh2 需要识别出LeaderReady。此事件Follower通过心跳判断。这个识别用来设置Dbh2负载统计开始工作。
Game.Online.sendOnlineRpc
Dbh2 LogCleanEndSplit 操作合并到 LogEndSplit 中。原子的完成删除(deleteRange)操作。
Dbh2 分桶结束需要删除源桶的已经分出去的数据。
Dbh2 重启服务如果需要需要继续splitting or cleanSplit.
Dbh2 分桶不均匀。【分桶后旧数据没有删除的原因】
Dbh2 性能统计移到StateMachine中,Raft.Follower也需要计算性能。
Dbh2: 分桶服务器测试,出现client timeout【新的Batch漏了设置Master,Database,Table参数】,并且后来再次启动,性能很低【分桶不均匀BUG导致的】。
Dbh2: 很多桶的时候,Dbh2RaftServer.Stat 一直打印,并且其中select次数一直很多。【正常的,是Raft.Heartbeat,由于桶多,累计起来有一些】
Netty DispatchMode 完善,包括事务Redo情况等。
------------------------------------------------------------------------------------------------------------------------------
2023/5/19 v1.2.4 Arch.Online.selectDirty; Load Balance & Overload; Raft Async; Dbh2 1.0; Online;
------------------------------------------------------------------------------------------------------------------------------
c# ProtocolPool
Dbh2 Get Benchmark. (直接运行UnitTest.CheckpointFlush只有80/s)直接client.bat "-get"有5w左右。
Dbh2 dbh2Splitting 生命期管理:endSplit可以阻止新的需要拷贝的事务,但是进行中事务需要等待完成。
Dbh2 创建表选择负载低的服务器的策略。
创建表负载。不能用分桶的load,否则批量创建都会创建到同一个manager。这里可用的策略是完全轮询manager,或者按load=manager中的桶数量的方式定义。
Dbh2 分桶阶段二,1. refused 服务器已处理。2. refused Agent
Dbh2 endSplit 【原子化】
Dbh2 根据负载或什么策略并发拆分桶。
统计:put count; delete count;get count;db file size
达到阀值(单桶并发的80%),在找得到能接收的manager(单桶并发✖️max_cpu✖️80%)时开始分桶。
max_cpu:最大并发是cpu核数,但是瓶颈在io,所以这里max_cpu会小一些,经验值是4。
单桶并发的80%不能是一天的平均,应该是2分钟的平均。TimerRole.transmit 带上调用时的LoginVersion,接收方判断是否当时的登录。缩小当前登录这个条件的时间窗口。
TimerRole.transmit 判断customData.class是否存在反了。
Arch.Link 删除StableLinkSid相关功能。
Arch.Online 1. 合并online,version表。2. BLink中增加State。
【已删除,现有的LinkdName,LinkSid足够了】3. Link Broken 增加 loginVersion 参数,其中本地触发使用当前值(即实际上是无效比较)。
Game.Online 1. 合并online,version表。2. BLink中增加State。
【已删除,现有的LinkdName,LinkSid足够了】3. Link Broken 增加 loginVersion 参数,其中本地触发使用当前值(即实际上是无效比较)。
Raft.Agent 允许重载NetClient。
Raft timeout/cancelPending 使用普通Task.run有可能线程饥饿。这两个操作提升到critical池执行。
Online 状态 eOffline=_tnline.remove, eLinkBroken=link上的连接断开,但逻辑上还处于登录状态,用来处理重连,eLogined=登录状态
Dbh2 启动 redo timeout。启动顺序有问题?【@zl CommitRocks串测试时导致ip,port不一样,连接不到目的地导致timeout。】
Dbh2 请求处理异步化。
Raft appendLog 支持异步。
【过载保护;更多。】目测目前做的很简陋,可能远远不足。
1. 判断ThreadPoolExecutor.getQueue().size(); 是否超过配置值overload,threshold。
【对于虚拟线程需要使用TaskCount并且配置更大的数字,或者虚拟线程非虚拟线程设置一个倍数关系,100倍?】
【负载均衡;全面审核。】
Linkd以模块为单位进行负载派发。可配置。
0. choiceLoad 负载低的provider优先分配。
1. ChoiceTypeHashAccount 根据账号的hash进行一致性hash选择provider。
2. ChoiceTypeHashRoleId 根据roleid的hash进行一致性hash选择provider。
3. ChoiceTypeFeedFullOneByOne 根据配置的值,按轮询的方式优先喂饱一台算一台的方式分配,对于游戏,当玩家较少时,把玩家集中到一起可能更优。
Arch.Online selectDirty 去掉事务发送。【@zl】
Dbh2 Tid 改成 long,master 分配?【决定采用随机20字节】
------------------------------------------------------------------------------------------------------------------------------
2023/4/21 v1.2.3 Dbh2 CommitServer; Online Kick BUG; Game.OnlineSetName; Raft; TimeRole;
------------------------------------------------------------------------------------------------------------------------------
UnitTest 去掉不必要的demo.App.Start/Stop。加快测试速度。
Dbh2 Commit/Undo RedoTimer.
TimerRole 和 OnlineSet 匹配。
Raft.commitSnapshot 延迟提交文件名命名规则修改:原来构造的时候,信息加到path前面不对,应该加到文件名中间。
Game.OnlineSetName 支持创建多个在线集合。
Dbh2 事务提交方案:【采用了方案方案一(用去嵌入Agent所在的进程直接提交)和方案三(用于独立CommitServer)】
1. 方案一,完备状态。
a) agent事务提交流程:
try
{
save_preparing_state_and_index;
prepare();
save_committing_state_and_index;
}
catch (any error)
{
undo(); // 这里简化了错误处理。
remove_index();
throw;
}
commit();
remove_index();
b) 事务继续流程:
foreach(var index)
{
switch (index.state)
{
case preparing:
undo();
remove_index();
breadk;
case committing:
commit();
remove_index();
break;
}
}
2. 方案二,完备状态,独立CommitServer,有点像事务管理器。
a) agent事务提交流程:
try
{
var cs = choiceCommitServer(); // 分布是多个。
cs.save_preparing_state_and_index; // 网络rpc。
prepare();
cs.commit(); // cs接管了后续操作。
}
catch (any error)
{
undo(); // 这里简化了错误处理。
cs.remove_index(); // ugly
throw;
}
b) CommitServer流程:
commit_implement()
{
save_commtting_state_and_index;
commit();
remove_index;
}
c) CommitServer重启继续流程,同方案一的foreach。
由于undo可能在agent那边执行,这边又可能执行,所以这里需要一个prepareMaxTime控制CommitServer可以undo流程。
3. 方案三,完备状态,独立CommitServer,完全接管所有的事务处理流程。
相当于把agent的事务数据全部发送到CommitServer,全部由CommitServer处理。
缺点是数据需要在网络上完整的再传输一次,有点浪费带宽。
具体伪码就是方案一换个地方实现。
意见
zl:
我建议方案2, commit server比agent更稳定些, 事务流程和回查状态更可靠些.
李成华:
我是觉得结构上方案三优雅一点,除了带宽这个问题。
---
实际上方案一agent完全本地处理commit流程也是要实现的,作为可选方案。
问题就是独立CommitServer方案采用哪套交互手段。
------------------------------------------------------------------------------------
Dbh2 CommitServer Query 超时。
Dbh2 CommitServer Query 调试。【OK】
【合并分支Dbh2SingleTidMode】
Dbh2 【重构】TransactionId:
1. 使用随机16字节作为TransactionId;本地(CoimmitServer)可发现冲突,异地由于有前缀(ip,port),允许冲突。
2. 整个事务和Query模式修改为新的TransactionId模式。
3. 事务状态(Prepareing, Committing, CommitDone);
【分支】Dbh2SingleTidMode Agent生成随机Tid,整个事务使用一个Tid。提交多个阶段都分别记录状态。
Dbh2 Commit中断【结论:开始Commit前,持久化记录保存点,重启以后继续Commit】
Dbh2 桶在agent.prepare中断后的悬挂事务需要主动探测agent的查询接口并undo掉。
实现两个版本:
1. 嵌入Agent所在进程,基于RocksDB,也由这个进程提供查询服务。
prepare with local ip, port;
rocksdb.put();
commit;
2. 独立服务器CommitServer,基于RocksDB,提交过程也有这个服务器完成。
Agent:
var commitServer = choice();
prepare with commitServer ip, port);
commitServer.commit();
CommitServer:
rocksdb.put();
commit;
* 上面两个方案,每个事务带上ip,port是可行的。有一点浪费。但比较简单,也灵活。
* CommitServer独立以后可以加上raft。
3. 基于文件共享的多进程,同步互斥,索引等问题,比较复杂,【废弃】。
------------------------------------------------------------------------------------------------------------------------------
2023/4/14 v1.2.2 Timer; Dbh2 Go; BUG c# AsyncSocket BeginSendAsync; RocksDatabase; Raft; Online; TimerFuture;
------------------------------------------------------------------------------------------------------------------------------
CheckpointFlush.benchFlush::CheckpointFlushMode.SingleThread 没有Merge的时候吞吐很低,需要profile一下。【本地Rocks.CacheDb用成Sync选项了】
TableStatistics,ProcedureStatistics 每分钟按访问量排序输出前20名到log.
Game.Online/Arch.Online Login/ReLogin 流程调整:当出现补Logout时,先完成当前事务,触发重做。
TimerFuture 安全的取消Timer(如果正在运行会等待执行完成)@zl 版本。
Dbh2 Raft-Snapshot 回退避开正在进行中的事务。
【糟糕,这个不好实现啊,因为raft-log都是apply进到stateMachine的,回退raft-log可以实现,但是stateMachine怎么办?】
【想到一个办法,就是stateMachine.checkpoint,backup操作先完成,但是这个snapshot不提交(有这个操作),知道raft-log继续往前走了“回退数量”了以后才提交。】
Raft.Agent 调整Rpc Timeout和总Timeout时间,使得Agent的请求一般可以重发一次才超时。
RocksDatabase backup restore 重构;增加reset能力;
Dbh2 Commit 的两个问题。
1. Commit失败【结论:不准失败,一直重试直到成功】
2. Commit中断【结论:开始Commit前,持久化记录保存点,重启以后继续Commit】【!!!还没实现!!!】
Dbh2 Transaction.Undo:prepareBatch 修改数据库的同时,构造出undoLogs,以后rollback的时候undo。
Dbh2 事务改成Batch模式,否则Raft.Snapshot不好处理。【能跑起来了】
Dbh2Manager 桶的数据合并到一个RocksDb里面,用ColumnFamily区分。
【由于桶和raft.logs需要独立备份和传输,是raft管理的一部分,不能合并】
【raft.rafts,unique合并,rocksdb数量至少减少一个,最多8个(配置)】
BUG c# AsyncSocket BeginSendAsync 同一个ArraySegment发送多次,由于没有加上Offset,导致数据发送错误。
Dbh2 简单轮转分配Manager策略。
Dbh2 Bench Env
Raft.Unique 性能占比挺大的,做成可选的?【服务器创建Raft.Log时可控】
对于Dbh2,
Transaction:Begin可以重新开始一个,Commit,Rollback有状态可以抵抗重复请求。
Data: Get,Put,Delete 都可以重复执行,没有问题。
所以Dbh2的这些操作可以关闭Unique。
【Dbh2以上操作关闭Unique】
Dbh2 PC机性能瓶颈是Selectors只开了一个线程,此时占用核2,开到8个线程,可到100%。【zl机器】
Dbh2.MasterDb,为每个manager.Acceptor(IP)保存Port种子,并分配。
【Timer redirectCancel 改成同步等待远程执行完成。有点风险。需要考虑一下。】【废弃,见下一条】
Timer.Cancel 实现方案改为:直接事务修改任意ServerId分片下的Timer,仅redirect.cancel.future。
------------------------------------------------------------------------------------------------------------------------------
2023/3/31 v1.2.1 cxx net & bean; Online.send use selectDirty; TaskOneByOne.Barrier; RelationalTableMapping; Timer Bug;
------------------------------------------------------------------------------------------------------------------------------
TaskOneByOne 改成 ConcurrentQueue,是否有任务执行使用CompareAndSet之类的标志,去掉Batch恢复一个一个任务执行的方式。
【无锁版本zl写了一个,性能没有Batch高,先保留但不启用】
BUG Dbh2 跑完测试没有关闭Raft服务,后续的单元测试还在继续尝试链接(不断输出链接refused错误)。是Connector没有停止?
【Dbh2AgentManager单件没有关闭,增加clear方法关闭,正常进程可以不调用这个方法】
RelationalTableMapping Alter Table Test
【Agent的Resend Timer没有停止】
DatabaseMySql.TableMysqlRelational
RelationalTableMapping
1. Bean encodeJson/decodeJson; prepareStatement/decodeResultSet OK!
2. Bean columns; Table create table sql;(从Schemas中构建)
3. Schemas alter table; *. FrameWork & 细节
4. alter table 修改字段类型时,数据库的兼容修改检查。
5. 多server(gs)同时启动,create table, checkCompatible, alter table 流程的互斥。
【使用大锁原则】atomicOpenDatabase
a) checkCompatible并且保存成功时,原子的在数据库表里设置一个标记。
b) 开始diff & alter。
c) 清除数据库标记。
-------------------------------
a) Database.Table 增加新方法?Database.TableMapping 新接口?TableX下沉到 find,replace,delete?
倾向于【增加】【下沉方法】。
b) TableX.walk<K, V> 使用a)的方案,walk<byte[], byte[]>对于Mapping方式不支持。
e) Table为单位配置,还是整个Project配置?Table RelationalMapping="true|false|project" Project RelationalMapping=”true|false"
【这些配置选择在Gen阶段就完成,然后仅在Table的子类实现中提供,不再提供其他配置手段】
f) flush-snapshot的问题。编写新的flush流程?或者定义新的snapshotSqlValue?
或者使用原来的snapshotValue,改成Object类型,具体保存什么数据,encode0根据当前表是否映射关系表进行编码,并且最终由Database.Table解释执行。
TableX.decodeKeyResultSet
TableX.encodeKeySQLStatement
Raft.Agent ResentTimer cancel when close;
Add Dbh2AgentManager.clear
Timer BUG: OnTimer 回调中取消马上注册,需要识别并中断回调后续代码执行。
decodeResultSet(ArrayList<String> parents, ResultSet rs)
encodeSQLStatement(ArrayList<String> parents, SQLStatement st)
TaskOneByOne.Barrier 当提交的任务需要的桶数量大于线程数量导致线程饥饿问题解决:
barrier需要wait时不进行wait操作,而是马上返回,等待barrier任务真的执行时,对所有的桶执行runNext。
cxx Module 生成 cpp h 两个文件。
cxx Net Handshake Protocols 运行在网络线程。
cxx Rpc
cxx Rpc std::future
cxx Net Handshake & Protocol Send Recv OK.
cxx Protocol,Rpc使用指针管理参数。
Online BeanKey(LinkName, LinkSid)可以原子的设置;Send 使用 selectDirty 查询。@zl
cxx ready?
------------------------------------------------------------------------------------------------------------------------------
2023/3/15 v1.2.0 Dbh2; TaskOneByOneByKey Dead-Lock-Bug; cxx
------------------------------------------------------------------------------------------------------------------------------
cxx Net
cxx Bean 1. ByteBuffer &; 2. Binary-std::string; 3. Bean, DynamicBean;
TaskOneByOneByKey 死锁BUG。
Gen 第二次运行才生成 Data,windows文件名大小写不区分。【实际实现给成了Bean内的嵌套静态类】
Dbh2 麻雀版跑起来 OK!
Online.Group.serverId不需要,设置这个参数导致需要读取version表,最终导致Linksid重用失效。
Dbh2 麻雀版完成 【待测试】
RocksDb Test key+commit_ts 的查询。
------------------------------------------------------------------------------------------------------------------------------
2023/3/1 v1.1.9 Zeze.Transaction.Data; protocolref import; New Dispatch Protocol For Procedure; Online.sendOneByOne;AutoKey Random
------------------------------------------------------------------------------------------------------------------------------
AutoKeyRandom -> Uuid? 或者纯粹随机?
考虑冲突的可能,Table增加辅助函数
Binary insertWithRandomKey(T value) {
var rKey = randomKey();
while (!add(rKey, value))
rKey = randomKey();
return rKey;
}
randomkey 类型选择。
1. Binary 弄个16字节或更长之类的。减少冲突。
2. long 8个字节凑合着用?
3. String 如果用uuid,需要这个类型。否则内部还是long或binary。
Dispatch 也是传参数给事务,需要考虑重置参数问题。@zl
Timer 允许在事件回调里面直接取消。
LinkBroken.Delay 使用Timer(持久化的),防止Logout丢失。Timer中记录LoginVersion。
Online.sendResponse TaskOneByOne 的问题。【如果已经登录则按RoleId排队,没有登录直接发送】
协议处理流程修改:当协议在事务中处理时,重新Decode,达到重置参数的目的。
旧流程Dispatch在网络线程中执行,对于Rpc.Client很友好。
新流程Rpc.Handle已经是新的线程了。有一点浪费。
Find Usage ProtocolFactoryHandle.Handel 检查是否有多余的null判断(新的流程不能判断这个)
DispatchRpcResponse 不再需要。【考虑改变流程】
DispatchProtocol2 不再需要
Protocol.Dispatch恢复,Rpc特别实现它,其实现与Handle差不多。
Timer BUG
Arch BUG
linkd提供给gs查询接口;以及自定义查询-linkd重载的provider service可以增加自定义模块?
UserIp 传给gs的问题。方案:
1. ProviderService 自定义模块协议中gs提供保存ip功能,linkd-auth的时候调用并保存。
2. 在需要访问UserIp的客户端协议中定义变量,linkd拦截这条协议并且填上。
需要在linkd引入这条协议,现有的protocolref除了引入还注册进Service。需要选项仅仅引入而不注册。
serverdev的linkd知道所有的gs协议,刚好不需要protocolref,但这个方式是几个project生成到common目录达到目的的。有点特殊。
3. linkd提供ProviderService自定义模块提供查询能力,让gs主动查询。缺点是查询跨进程,延迟较高。
看看,有什么zeze要做的,
1. protocolref新参数或者新增protocolref import来表达是一个点。【已实现,import可以定义在任意模块内部】
2. 其他的都是项目自定义就行了。
Zeze.Transaction.Data Bean的无事务版本。
-- 没有选择,全部Bean生成完成。
-- 根据协议配置选择协议依赖的Bean生成Data。
-- 协议相关生成。
-- BeanKey. 【不做了】
-- Bean.assign(Data data).
------------------------------------------------------------------------------------------------------------------------------
2023/2/16 v1.1.8 initRootInfoWithRedo c#; Timer.OfflineNotify; DatagramChannel; Log.TypeId;
------------------------------------------------------------------------------------------------------------------------------
Log.TypeId 方案,主要是模板类型。
-- Bean增加hashLogMap hashLog专门用来生成模板类型的LogTypeId。
-- 使用可以继续的hash64方法,和原来的hash32方式【兼容】。
-- 修改方案,改一个地方算一个:PMap1, 改完!
-- RocksRaft 改完!
-- c# 改完。
Zege c# GetPublickUserInfo & encrypt message;
DatagramChannel java
1. UdpServer:DatagramService 1--* DatagramSocket 绑定多个Socket,防止单个Socket超量。
2. UdpClient:DatagramService 1--1 DatagramSession 一一对应。
3. DatagramSession 不能使用PeerInetAddress建立映射,需要逻辑SessionId,这样能允许会话使用过程中端口地址发生变更。
4. DatagramSession创建需要通过服务器验证并分配SessionId。zl建议随机long值(未用)。有一定防止攻击能力。
5. 加密,SessionId不加密+加密(递增SerialId+Data),SerialId使得相同的数据也加密出不一样的结果。
6. 加密重放防止:Session记录当前最大的SerialId和时间,允许比当前SerialId大的包和一小段时间之前的未收到的包。
一小段时间之前的未收到的包:记录当前时间之前3秒之间的所有SerialId,不处理收到的重复的,小于记录的最小时间的也丢弃。
加密数据最后加上SessionId用于简单解密验证。
【这策略有必要吗?】
7. 可靠Udp和加密,【不实现可靠Udp】,实现的话,使用流加密即可。
8. a) 乱序丢弃,这种策略,第6点不需要复杂控制,只需要记录最大的serialId即可。
b) 允许乱序,
initRootInfoWithRedo c#; @zl
Timer.OfflineNotify
------------------------------------------------------------------------------------------------------------------------------
2023/2/6 v1.1.7 TimeThrottle; Linkd.OverBandwidth; CheckpintFlushMode; AutoKeyAtomic;
------------------------------------------------------------------------------------------------------------------------------
AutoKeyAtomic
使用ImportantTable记录种子,
使用另外一个线程执行事务递增种子。
BUG initRootInfoWithRedo 导致isManager失败,最终数据没有保护到。
BUG FlushSet 没有setDirty(false)【已解决】
BUG FLushSet 会出现破坏acid的现象【===============未解决===============】
CheckpintFlushMode 以及相关性能测试。
Mysql halt 程序在没有提交和回滚的情况下,服务器的行为。
过载保护;更多。--- linkd流量过载保护。
统计LinkdService出入?
统计ProviderService出入?
根据配置,达到80%以后就限制某些地方(哪里)?达到90%就更严格限制?
思路:
ProviderService的总输入或者LinkdService的总输出达到各自配置值
80%开始限制客户端部分请求(如Move),
90%开始限制所有客户端请求。
ProviderService,LinkdService统计以后,加拦截点。
丢弃高层接口:限制丢弃策略接口定义在LinkdApp中。
丢弃底层接口:丢弃实现必须是底层,怎么让Linkd控制这个丢弃。
设计:
a) Service带宽统计,可以得到每秒的速率。getBandwidth();
b) Service.discard(int moduleId, int protocolId) return true discard protocol,default false。
c) override LinkdService.discard(int moduleId, int protocolId) {
//【新修订:实现成忽略ProviderService的带宽过载配置,因为ProviderService的输入最终也会反映到LinkdService的输出。否则这里应该是max(LinkdService.Rate, ProviderService.Rate)】
var opt = options.getOverBandwidth();
if (null == opt)
return false; // disable
var rate = (double)getBandwitch() / opt;
// 总控
if (rate > 0.9)
return true; // 熔断: discard all,其他级别在回调中处理。
if (rate < 0.6)
return false; // 整体负载小于0.6,全部不丢弃
/*
对于游戏可以针对【Move协议】使用下面的策略.
if (moduleId == Map.ModuleId && protocolId == Map.Move.ProtocolId)
return Zeze.Util.Random.getInstance().nextInt(100) < (int)((rate - 0.6) / 0.3 * 100);
return false; // 其他协议全部不丢弃,除非达到熔断。
*/
if (linkdApp.discardAction != null)
return linkdApp.discardAction.call(moduleId, protocolId, rate);
}
TimeThrottle Queue | Counter 限制请求数量和带宽
linkd对客户端应该限速,比如,限制5秒内最多25个包,这个算法是允许突发。
------------------------------------------------------------------------------------------------------------------------------
2023/1/19 v1.1.6 DelayRemove; LinkedMap; TaskOneByOneByKey; LinkdProvider.ProcessSendRequest Async; RocketMQ; throws Throwable; Acceptor @internal @external Port=0
------------------------------------------------------------------------------------------------------------------------------
BUG DelayRemove 每个Application只需要创建本ServerId的实例。
DelayRemove 增加延迟立即执行任务;
LinkedMap.clear 使用DelayRemove.addJob。
java bench 大大超过 c# 分析: 初步结论是c# async开销很大,在单线程(ABasicSimpleAddOneThread)模式下,开销占比80%。
AsyncSocket 降低Chain.Flush频率。
TaskOneByOneByKey.executeBatch
一、LinkdProvider.ProcessSendRequest
使用TaskOneByOneByKey.executeCyclicBarrier把发送的任务放到其他线程,减轻Provider的线程压力。
1. OneByOne比直接写快,减少wakeup负载传递给ProviderService的线程。
2. 整体操作复杂了,但是cpu交给了其他线程执行。
二、AsyncSocket.send.wakeup 放到其他线程执行。【不实现】
1. 增加了整体复杂读,减轻直接调用者的开销。增加了一次线程唤醒的开销。
RocketMQ;
throws Exception 替换 throws Throwable。部分catch(Throwable)修改为catch(Exception)
ServiceConf.Acceptor ip="@internal" "@external"
Acceptor.Port == 0 允许随机选择端口。需要改动:等到bind之后,读出正确的端口,并修改外面的需要注册到ServiceManager的配置。
------------------------------------------------------------------------------------------------------------------------------
2023/1/13 v1.1.5 TaskOneByOneByKey Performance; CommandConsole; Task; Table.walkDesc; New Handshake;
------------------------------------------------------------------------------------------------------------------------------
TaskOneByOneByKey 一次提交一批给Executor执行。减少锁的开销。
Benchmark Encrypt/Decrypt 250M/250M Compress/Decompress 90M/100M
CommandConsole
Task
Table.walkDesc descendingMap.tailMap是什么。
新的Handshake协商流程。doc/handshake.txt
1. new java-new java Ok
2. old c# - new java Ok
3. 需要确认确实启用了加密,压缩之类的。Ok
4. new c# - new java Ok
5. encrypt no; compress mppc Ok
【2022/12/28】
------------------------------------------------------------------------------------------------------------------------------
v1.1.4 ProviderDirectService.WaitDirectServerReady; Timer cancelAlways; ServiceManagerWithRaft;
------------------------------------------------------------------------------------------------------------------------------
【全面】升级Zeze到serverdev
2. 全面升级Arch。@zl
主要流程测试。
比如,linkd的Netty【可选的】换成Zeze.Netty(gs.online可能需要点改动。
下周开始启动?
ServiceManagerWithRaft 测试
Timer.cancel 无法redirect时,直接从db中cancel掉。
ProviderDirectService.WaitDirectServerReady
【2022/12/21】
------------------------------------------------------------------------------------------------------------------------------
v1.1.3 ServiceManagerWithRaft; BUG BeginSavepoint;
------------------------------------------------------------------------------------------------------------------------------
Global所有版本AchillesHeelDaemon不再总是记录log,仅仅记录有释放锁的session的日志。
New RocksRaft.Table.selectDirty(); 没有仔细考虑。
ServiceManagerWithRaft
1. 大锁内处理所有rpc和Rpc结果(单线程);
2. 原来的ServiceManager只需要一个网络(Service)配置,新加WithRaft以后怎么配置和选择
【全面】升级Zeze到serverdev
1. 不兼容协议编码升级。@zl
测试客户端登陆通过即可。
难点是所有的客户端版本都需要升级一次。
本周启动。
BUG 1. LogOne LogDynamic BeginSavepoint EndSavepoint 遗漏;
2. LogXXX 大部分 BeginSavepoint 复制时遗漏 dup.This = This;
确认:GlobalCacheManagerWithRaft Recude 需要 TransactionLevel="Serializable" ?【不需要】
------------------------------------------------------------------------------------------------------------------------------
tag v1.1.2 Multi-Selectors; Zeze.Net.OutputBuffer; SortedMap; ConsistentHash;
------------------------------------------------------------------------------------------------------------------------------
可以自建Selectors实例,并设置到Service中,使得Service中新建连接使用设置的Selectors。
java::Zeze.Net.OutputBuffer @zl
合并协议到固定的buffer中,以后才调用jdk.writes。
加密操作的输出可以直接定向到新的outputbuffer中。
ServiceConfig.maxConnections 限制服务最大连接数量。
SortedMap 基于ArrayList的排序映射。
一致性hash;基于SortedMap
【2022/11/29】
------------------------------------------------------------------------------------------------------------------------------
tag v1.1.1 DatabaseDynamoDb; Database.SetInuse; Table SQL-Type; Table Walk Page; Task ...;
------------------------------------------------------------------------------------------------------------------------------
DatabaseDynamoDb 还需测试。
Database.Operates.SetInuse 总是Clear的代码改成使用系统属性参数。
Daemon 杀掉重启Server设置ClearInuse的参数。
Table key,value都定义成VARBINARY(eMaxKeyLength)。
Table.WalkPage
@return K lastKey
K Walk(K exclusiveStartKey, int proposeLimit, TableWalkHandle<K, V> handle)
K WalkKey(...)
------------------------------------------------------------------------------------------------------------------------------
tag v1.1.0 TableDynamic; Zege ...; Task ...;
------------------------------------------------------------------------------------------------------------------------------
Zege Add Friend
* 总则:双向好友,可以从一方的状态推测对方状态。
* 操作:Invite-Accept-Deny-Expire;Remove;
* 状态:Invite,Normal,Deny,Remove,(None)
(None) 表示数据不存在。
TableDynamic
------------------------------------------------------------------------------------------------------------------------------
tag v1.0.9 Task ...; MappingClass(dynamic); Overload(java); Variable Bean Set; Druid; Zege ...;
------------------------------------------------------------------------------------------------------------------------------
Task & Achievement & Statistics @项洋呈
(java)Dbcp -> Druid
Bean.setBean CollOne<> LogOne<>
Linkd 过载保护,响应rpc.request和报告错误。
Zeze 过载保护。1. 负载报告完成;2. 负载分配。
Zeze.Net.FamilyClass 增加FamilyClass,中间转发服务(如Linkd)可用来区分Protocol和Rpc,
顺便加入压缩Protocol.ResultCode,Rpc.IsRequest的能力。
Zege Notify Module Added
gen.exe dynamic 到类继承的映射。
类实例的数据关联到table.bean,不能保存实例,每次使用的时候创建,用完就丢弃。
每一级Bean.Dynamic只允许一个。
【2022/10/28】
------------------------------------------------------------------------------------------------------------------------------
tag v1.0.8 TableReadOnly BeanReadOnly ...; FollowerApply between conf+cs+net and java; Zega ...;
------------------------------------------------------------------------------------------------------------------------------
TableReadOnly ...
table现在是module私有的,因为只读访问可能比较多,为了避免很多包装,提供只读接口给其他模块读取用。
1. BeanReadOnly getter 名字,统一 ReadOnly 后缀。不可变变量还是不加ReadOnly了。
2. Collections增加一个模板参数,现有三个模板参数。PMap2<K, V, VReadOnly> OK!
3. 容器提供如 PListReadOnly 包装。
a) 修改操作不提供。
b) 内部Bean可修改是,访问内部Item需要得到BeanReadOnly。
Zege c#
c# login bug; done?
c# friends listener; done
Topmost 重新实现:done
1. 使用另一个LinkedMap存储,
2. 有数量限制?读取的时候装载全部Node?
3. 复杂度放在服务器:判断好友的时候用"或者的关系"判断两个LinkedMap。需要Review所有好友相关操作。
c# MessageView; 1 先用控件版 2 自画版暂停开发 3 WebView 版未来考虑
c# friend message;
c# MessageFriend 管理数据。
c# IMessageView, MessageViewControl 消息窗口接口和控件方式的实现。
c# 未读红点算法确定。
------------------------------------------------------------------------------------------------------------------------------
tag v1.0.7 Table.DelayRemove; dynamic in collection; Zeze.Util.Cache; New LogDynamic
------------------------------------------------------------------------------------------------------------------------------
Table.DelayRemove 删除的实现。
dynamic is bean? 支持放入容器。@zl
LogDynamic:encode/decode 【大问题】
1. 当整个Bean替换的时候需要传递Bean.Encode
2. 当Bean发生了编辑时需要传递LogBean。
x. 需要像容器一样实现一个专有LogBean管理类。
Zege c#
Mission.cs 增加错误处理Action; Done!
c# create account;auth;login;friends; Done!
【2022/9/22】
------------------------------------------------------------------------------------------------------------------------------
tag v1.0.6 Timer; conf+cs+net; ServiceManager.OfflineNotify
------------------------------------------------------------------------------------------------------------------------------
Component.Timer 安全加强:
1. fire是检查Index.ServerId确认自己是否拥有者。错误时cancel future,注意不是cancel timer。
2. fire并发去重。
3. Online Timer 记录版本号。并在fire时检查。
1. 调度使用的何种java底层机制
基于Zeze.Table嵌入用户事务
2. 调度在分布式之间如何保证不会重复调度
基于系列号
3. 调度丢失怎么处理的
a) 基于事务,事务成功,Timer调度肯定也成功。
b) ThreadPool.schedule,这个目前相信LoadTimer没有出错。
或者下一次LoadTimer会恢复。要完全可靠的话就定时LoadTimer,
当然需要自动忽略重复的TimerId。
4. 调度失败如何处理的
这个调度是什么?
a) 用户回调触发按刚才说的,除了异常,忽略其他错误。
b) 或者这个和“调度丢失”一样的问题?
5. 调度超期(比如服务器down机重启)调度是如何进行的 -- simpleTimer cronTimer是否有不同
a) 服务器宕机,其他服务器接管。
b) 服务器正常重启,不接管(未实现)。
c) simple,cron一样的。*现在simple已经改成每次ThreadPool.schedule(delay),不使用它的period能力了。
6. 调度的创建和清理是如何做的, 清理如果失败了, 如果保证后续调度的非法性
Timer.basic是持久的。
a) 只有一个cancel接口,也是基于事务的。
b) 如果ThreadPool.future没有清理,将发生上面的第2点。去重已经实现。
Component.Timer TimerArchOnline TimerGameOnline
ServiceManager.OfflineNotify.NormalClose
正常关闭不发送server-down通知。
【采用延迟发送通知的方案】额外规则:全系统停止时需要先停止ServiceManager.
直接暴露Zeze.Builtin.Collections.LinkedMap的数据结构给客户端。
ServiceManager::OfflineNotify
Zege
GetPublicUserInfo,GetPublicUserPhoto 实现和linkd拦截处理;
provider.module.binds.xml,模块默认hash(account);
创建账号和登录。
Friend 完善:参数检查,权限相关。
消息历史基本完工:保存和读取和设置已读。
calculateMessageRange: eGetMessageFromAboutRead, eGetMessageFromAboutLast, eGetMessageToAuto, ...
Friend 协议参数和数据库结构分开定义。
管理员管理。
Linkd hash(group) 改成 hash(group,departmentId)
BFriend.Memo。
群成员增加所属的部门。
conf+cs+net (+ts? +lua?)
精简客户端,拷贝部分源码到自己的目录。
1. conf+cs 系列化;使用gen命令输出系列化需要的源文件:gen -c ExportConf -ZezeSrcDir ../zeze
2. 拷贝Net目录;在项目中定义宏 USE_CONFCS,这样Net模块就不再依赖事务Bean和存储过程。
3. 需要建立一个几乎空的 Zeze.Application,用来传递Config和避免修改Gen.exe。
4. 拷贝 Zeze.IModule;Zeze.AppBase;Zeze.Config;Zeze.Util.ResultCode;Zeze.Util.Mission;Zeze.Util.Scheduler。
【这几个文件应该没有依赖其他东西,可以直接拷贝,需要确认。】
%. FollowerApply: 实现增量日志
------------------------------------------------------------------------------------------------------------------------------
tag 1.0.5 Certificate; Netty-Web More; Change Protocol Provider.Send To Rpc And Report Error;
------------------------------------------------------------------------------------------------------------------------------
Linkd重启,Server还在给它发送Send。此时,linkd发现Client不在线,补发LinkBroken缺少context的问题。
*** 实际方案是 ***
Send从Protocol改成Rpc,当Linkd发现发送失败时,通过Send.Result返回结果给Server并处理。
Netty-Web @zl
1. close 确认 sending标志;遵守netty计数规则释放资源。
2. KeepAlive & Idle Timeout。
3. HttpExchange 不考虑多线程访问?
4. 对上层掩盖连接,基于请求(HttpExchange)进行处理。
Zege 加密基础(基于证书)
1. 任意CA签发的证书,默认提供一个不是权威的。
2. 创建账号,上传public-key并签字,verify-sign之后,把pub跟账号绑定。
3. 验证账号,签字随机串,服务器用绑定的pub验证签字。
4. 增加绑定新的pub,同时用新旧pri签字,服务器都验证通过,绑定新增pub。同时不会作废旧的pub,用来读取消息历史。
5. 小问题:x509 只支持rsa吗?
6. 看看这个设想对不对,可不可实现。Self Sign Cert:不验证chain; 自己构建的 Linux Root Ca,可以发布根证书到服务器,可选验证chain; 权威Ca,需要验证chain。
------------------------------------------------------------------------------------------------------------------------------
tag 1.0.4 Bean Construct With Parameter; Task.run auto detect transaction;Vector2 ... java support
------------------------------------------------------------------------------------------------------------------------------
Vector2 完善。@zl
Task.run 默认判断是否事务中,自动whileCommit。去掉Task.runWhileCommit。@zl
Bean 初始化构造函数(varid构造改成方法初始化,仅给内部使用)@zl
【2022/8/15】
------------------------------------------------------------------------------------------------------------------------------
tag 1.0.3 Netty-Web;Task;AsyckSocket.closeGracefully
------------------------------------------------------------------------------------------------------------------------------
Netty-Web-File
AsyncSocket 如果outputbuf不为空,关闭时增加一个closing状态,等待全部写完然后自动关闭。
closing状态不准再写入新数据。closing状态连接从Service中注销(这个需要权衡)。
closeGracefully();
哦,从service中去掉,外面就看不到了,这样closing状态可以省略(但是可能有地方记住了socket的引用,
这样还需要提前触发原来的OnSocketClose的回调)。
最终的结果就是连接已经不再可用,仅仅等待flush完成或者超时,真正关闭。
考虑一下。应用得到OnSocketClose,但是连接还在写数据,可能会造成点小麻烦。应用层如果要时序的话。细节还是有几点。
【closeGracefully还是提前从Service中注销并且触发OnSocketClose,不引入closing状态】
RedirectBase.RunVoid 前面的if分支漏了return
Netty-Web see zeze.docx::Web(Netty)
Netty-Web 生命期管理规则。
1. Exception HttpServer.java::Handler::exceptionCaught,来自Netty错误报告。
a) x = exchanges.remove(ctx);
b) 可配置的x.send500(cause) stacktrace。
c) netty-ctx.flush();
d) finally netty-ctx.close();
2. HttpExchange.close() 用于请求正常处理完毕时关闭
void close() {
if (null != server.exchanges.remove(context)) {
context.flush();
context.close();
}
}
Task: void run; void runWhileCommit; future runUnsafe
------------------------------------------------------------------------------------------------------------------------------
tag 1.0.2 ResetRootInfo While Redo; Simple Web; @DispatchMode
------------------------------------------------------------------------------------------------------------------------------
InitRootInfo 可回滚
1. Transaction.WhileRedo
内部用,这个行为不可预测,不开放给应用。
2)Bean.InitRootInfoWithRedo
// 这个方法仅在把用户创建的Bean加入到Zeze内变成受管理状态时调用。
// PList2 PMap2 中所有的InitRootInfo替换成这个方法。
// TableX 除了Load,GetOrAdd之外的主要是外部传入的Value的InitRootInfo替换成这个方法。
public final void InitRootInfoWithRedo(Record.RootInfo rootInfo, Bean parent) {
InitRootInfo(rootInfo, parent);
Transaction.WhileRedo(ResetRootInfo);
}
3)Bean.ResetRootInfo
private void Bean.ResetRootInfo() {
RootInfo = null;
Parent = null;
// 需要生成一个新的,区别是去调用ResetRootInfo。
// 这个不能重用InitRootInfo。
// 看看还有什么更简单的办法。
ResetChildrenRootInfo(rootInfo);
}
4)分析
a)
昨天的Log方式,本来想的是能对将要被管理的Bean的并发有一定的很受限的保护。
现在WhileRedo方式,原则上不对自己新建的Bean又传递给多个存储过程的情况进行保护了。
保护不完。
b)
ResetRootInfo 是否会导致树里面的分支重复重置?
由于Redo的时候,Log没有Commit,新加入容器的Bean还没有生效,我认为是不会重复重置的,但对这个情况需要确认。
即使重复重置,由于都是简单的set null,也不会有致命问题。
大家分析看看。
c)
原则:
WhileRedo方式更加有的放矢,即只解决传入的Bean重做的时候RootInfo没有重置倒是重做失败的问题。
不进行功能扩展了。
@DispatchMode
这是一个协议处理函数的注解,用来控制协议的调度方式(仅用于Java):
• 在普通线程池中执行。默认是这种。
• 在重要线程池中执行。
• 在调用者线程执行。
协议的线程调度方式除了用这个注解单独控制。还可以在Zeze.Net.Service子类中重载DispatchProtocol,DispatchRpcResponse等控制。
重载会覆盖默认实现,优先级比注解高。默认实现按注解方式调度协议的执行。
Http In Linkd(java基于HttpServer或者更高级的包装类-感觉有新的了)
GET 马上关闭InputStream。
POST 已知Content-Length,记录已读取长度,比较Length,在读够时马上设置Finish,避免判断eof还需要读取一次(read==-1)。
BUG Server.HttpExchange 没有关闭。
WAINING Linkd.CloseOutputStream 多调用了一次。
a) 去掉json,query对path的入侵
b) 流支持
c) HttpExchange,HttpServlet
简单的Web服务器,侧重和Server的交互。逻辑由Server实现,Linkd只管转发。
1. 简单查询(Request,Response)
是否KeepAlive由Http协议自己支持,上层只处理简单查询。
用途,在线管理系统。
2. WebSocket,不是很了解,需要调研。关键:linkd是否需要侵入管理这个长连接。
长连接应用。
3. 少量文件的下载
提供js文件下载,用来实现基于js的交互系统。
可以利用js(ts.ByteBuffer)实现Zeze.Protocol.Encode/Decode。
4. Linkd 本来是全透明的,所有请求转发给Server即可。
为了某些系统中,Server不包含Auth信息,有专门的Auth服务器提供验证服务。
需要Linkd可以Auth请求,所以定义一个Auth的Handler用于这种情况。
这个Handler通过回调处理,回调不是必要的。
5. 多WebApp支持。url-path的第一级为appname;需要传递url-path给Server;
每个WebApp包含自己的Auth?、Session,Servlet注册。
/webappname/servletpath.../query[.serverid]
/webappname/servletpath.../json[.serverid]
/webappname/servletpath.../queryauth[.serverid]
/webappname/servletpath.../jsonauth[.serverid]
------------------------------------------------------------------------------------------------------------------------------
tag 1.0.1 AchillesHeelDaemon.ProcessDaemon & RelativeRecordSet.FlushSet
------------------------------------------------------------------------------------------------------------------------------
Immediately TableX::Load 立即保存。
Also Delete OldTable When Record Deleted 【in transaction】
AchillesHeelDaemon.ProcessDaemon for c# 重新实现一次当作review。【zl】
MemoryMappedFile 未映射到磁盘上的现有文件的内存映射文件
Mutex 跨进程锁,不需要用文件锁。
UdpClent UDP,感觉这个是比较新的高级包装,不知道有没有UDPSocket的类。SocketError.TimedOut
exec 还不知道用什么,由于c#运行环境不大一样,可能比较特殊。
TableCache Checkpoint 时机修改;java 不捕捉 sleep 异常,此时一般是程序退出;while 增加 App.isStart() 判断。
CheckpointMode.Table.Flush 在后台数据库的一个事务内提交多个rrs。【RelativeRecordSet.FlushSet】
Arch.Online Login+Logout 中间补充触发一个Logout事件?
程序退出的时候怎么办?难道也要补?还有程序异常退出呢?
由于实现可靠的Login+Logout匹配难度太大,
逻辑还是需要处理Logout丢失的问题:一般在处理Login时发现上一个还没有Logout,自动完成相应处理。
checkpoint concurrent:Config.CheckpointModeTableFlushConcurrent
DatagramSocket Test
Exec Test
AchillesHeelDaemon:安全级别从jvm级别提升到操作系统。保留线程守护,增加进程守护。两个守护兼容:
gs启动的时候检查mmap,发现自己是daemon启动的,就开启进程守护(向mmap报告和读取命令),否则还是原来的线程守护。
【2022/7/15】
------------------------------------------------------------------------------------------------------------------------------
tag 1.0.0 Stable? ^_^
------------------------------------------------------------------------------------------------------------------------------
Bean 依赖环检测。允许容器依赖环。
TableX.FlushWhenReduce 去掉回调方式,去掉Period支持(直接抛异常)。
raft.agent 永远尝试会造成大量服务不可用风险。
java Remove ServiceInfo.LocalState
1. BUG,ReduceInvalidAllLocalOnly 没有Flush。
2. BUG,TableX.Load 发现 Invalid 再去Acquire并Storage.Load时,如果本地记录是脏的,数据就会被覆盖。
刚才TableX.Load的问题造成的可能原因分析:本地数据被Daemon.Release,是没有刷新到后台的,
如果中间重新连上Global就会出现这个情况。但奇怪的是Daemon在你跑测试的时候是没有在工作的。
这点的其他可能原因你也分析一下?
虽然补丁好像可以Load时,if (!Record.Dirty) Storage.Load;但这个没有找到真正原因前,这个补丁有点危险。
【修改:Reduce的时候,锁内执行Flush】
RedirectHash & RedirectAll & ChoiceHash - 单点数据分块支持与一致性Hash算法修改(原方案有问题:数据分块不能在服务器选择之后保持独立性)
DataConcurrentLevel:数据分块数量。
1. DataConcurrentLevel大于1 服务器选择:
var ha = hash(account);
var di = ha % DataConcurrentLevel; // account被分成Level个集合,每个集合访问一块数据
var h = hash(di); // 不再考虑原始hash,参见后面第2.点。
var server = ConsientHash(h);
问题:
DataConcurrentLevel个数据块的访问是不是被分割成独立集合,每个集合在一个server内访问?
2. DataConcurrentLevel=1服务器选择。
var ha = hash(account);
var server = ConsientHash(ha);
问题:
相同的account在一个server上。这个显然没问题了。
ServiceManager.Agent Remove ServiceInfo.LocalState
【重大BUG】 即使锁内。Record.Global.State 可能没有提升到需要水平。需要重新_check_。
一致性hash负载分配算法, 【c# 没有TreeMap.tailMap。】
Table.WalkKey
Global-Server错误码分析
1. Warning
global 统计增加了Acquire和Reduce ResultCode的统计, GlobalRaft跑Simulate时,Acquire出现过以下失败情况:
public static final long Exception = -1;
public static final long RaftRetry = -15;
int AcquireShareDeadLockFound = 21;
int AcquireShareAlreadyIsModify = 22;
int AcquireModifyDeadLockFound = 23;
int AcquireModifyAlreadyIsModify = 25;
int AcquireShareFailed = 26;
int AcquireModifyFailed = 27;
2. Fatal
ERROR [] Table: RocksRaft Process Exception
java.lang.IllegalStateException: CacheState state error
at Zeze.Services.GlobalCacheManagerWithRaft.AcquireShare(GlobalCacheManagerWithRaft.java:188)
【2022/6/11】
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.9 Random Sleep For Global-Dead-Lock and Too-Many-Try & Global Restart ...
------------------------------------------------------------------------------------------------------------------------------
【TryWaitFlushWhenRecude 去掉啦】
Too Many Try: Fresh机制下由Global提供排队方案草稿:
1. Server发现本地Fresh,拒绝Reduce。
2. Global发现由于Fresh的拒绝,把申请者加入队列。
3. Server把set Fresh=false时,发送通知给Global。
4. Global收到Fresh==false通知,选择队列中的一个申请者开始处理。
5. Global-Fresh队列管理。
需要定时轮询的方式启动队列中的请求进行重做,防止Fresh=false通知丢失。
请求总超时管理按一般请求超时处理。
问题:请求第一次来的时候要不要判断Fresh队列不为空,然后马上加入队列。
【死锁检测忙等问题】
由于死锁检测必须返回结果,没法使用队列,所以这个问题不好解决。
死锁检测原来的忙等解决方案是:TryWaitFlushWhenRecude,但仍然存在一个忙等窗口:
当一个申请在进行过程中,CacheState还没有更新时,忙等仍然存在。
【总结】
用随机延迟一起解决Fresh排队和死锁检测忙等,上面的Fresh队列也不实现了。
-------------------------------------------------------------------------------------------
Arch:模块默认订阅类型设置为,SubsribeTypeSimple。(准备以后改成一致性hash算法)。
Global宕机:Server重连发送ReLogin,此时新启动的Global需要拒绝ReLogin,然后Server释放本地所有锁,重新发Login才能登录。
Gen: transient 应用到所有版本。
Too Many Try: Fresh机制下由Global提供排队方案草稿:
0.【先采用临时方案】Server在RedoAndReleaseLock时随机Sleep延迟。
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.8 AchillesHeel & Handshake & Too Many Try
------------------------------------------------------------------------------------------------------------------------------
Handshake 是否加密可以配置。默认不加密。
AsyncSocket.VerifySecurity 在 CHandshakeDone处理时调用一次。不再需要在DispatchProtocol时调用。
Global错误处理:GS增加AchillesHeelDaemon,申请token(特别的keepalive)机制,本地释放锁超时,如果稍有不正常,就自杀。
too many try: 从Global得到锁以后,确保本地至少用过一次(事务成功),才允许Reduce。
Global-Server 错误恢复测试。1. Server 强制杀掉,8秒内重启。2. Server 强制杀掉,Global一定时间后回收记录锁。
Java Apply Zeze.Transaction.Logs
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.7 Java TableCache SoftReference Fix Bug Timestamp Value Access Order
------------------------------------------------------------------------------------------------------------------------------
Global错误处理:GS增加AchillesHeelDaemon,申请token(特别的keepalive)机制,本地释放锁超时,如果稍有不正常,就自杀。【草稿】
LinkedMap.BLinkedMapNodeValue 里面保存了key,但是walk接口没有返回,需要在dynamic里面再次定义。【callback返回key(id),而不是nodeid】
LinkedMap.GetOrAdd
Zege 框架搭建完成。
java ServiceManager.AgentClient.DispatchProtocol Run In IO-Thread。
java Zeze.Applicate.deleteDirectroy: while(exist) { delete() }
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.6 zege start & c# raft ready
------------------------------------------------------------------------------------------------------------------------------
简介
一个简单IM系统,支持大量好友,大量群成员。
目的
用来验证zeze消息发送转发能力。
语言
Server=java,Robot=java,Client=???
详细
. 基于账号(不是Roleid)
. 相同账户允许重复登录。
. 给群发送消息使用RedirectHash。
比如有1000台server,那么群成员大概率平均分布,那么每个成员发送消息广播时,对群列表的利用率极低。
使用hash(group.Id)把群的广播请求固定分配到某台server上,提高群成员列表的利用率。
缺点是需要转发一次消息,但相当合理。
. 大量群成员一起说话是没法聊的。所以实际上当群成员超过一定量(比如1000)时,需要分目录。
最终群成员被组织到一个部门树中。每个部门(包括根)都有自己的成员列表,限定数量内允许聊天。聊天不包含子部门。
产出
Zeze.Collections.Tree
可能
元宇宙实现一个基于RoleId的客户端内的好友系统,意义不大,应该独立成一个系统。
可以考虑把这个测试程序发展成元宇宙的好友系统。以后提供unity内的client,以及android,ios,等等等...
另外元宇宙server端需要访问好友系统,则通过server-server接口。
代号
"Zege",泽哥的意思
c# raft BUG: Zeze.Raft.LogSequence:849行TryAdd失败【zl找到,异常导致LeaderAppendLogs没有Rollback,然后在关闭Raft的时候,并发的还在处理中请求进入锁导致失败】
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.5 c# ready(except raft)
------------------------------------------------------------------------------------------------------------------------------
1. raft 异步测试【未解决TryAdd失败BUG】
2. Global With Raft 异步测试【未进行】
3. 查找所有Wait并确认【Done】
4. Net Full Async【Done 但没有达到Global可以直接在DispatchProtocol里面await的目的】
5. Rewrite Scheduler【简单处理一下,使用的地方比较多,先这样啦】
6. UnitTest TestBag没过(呼叫肖丽杨)。
ServiceManager.ServiceInfo.Identity 编码:'@'开头为string,否则为int。Identity排序如果int按int的大小排序。
java ASYNC GlobalWithRaft Question:1. Transaction.Current is ThreadLocal?2. try ... finally? 3. exception? 【决定使用虚拟线程】
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.4 Online.ReliableNotify & Global.LruTryRemoveCallback
------------------------------------------------------------------------------------------------------------------------------
ReliableNotify - Sample(Zezex).client: 客户端可以延迟确认,如果发现Index不匹配,可以发送确认Rpc并且带上Sync标记进行重新同步。
Global.RocksRaft.LruTryRemoveCallback
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.3 inherit bean (conf+cs only)
------------------------------------------------------------------------------------------------------------------------------
1. bean继承实现
【注意】class B : A; List<A>中被放入B时,Decode成A或者失败或者Encode报错。
【注意】继承要实现动态,必须配合dynamic使用。如,List<dynamic:A>这样里面可以放A及A的子类,可以被正确encode/decode。
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.2 Gen: new type format; collection can hold dynamic type now
------------------------------------------------------------------------------------------------------------------------------
1. 新的模板参数声明格式
<variable id="1" name="ListInt" type="list[int]"/>
<variable id="2" name="SetInt" type="set[int]"/>
<variable id="3" name="MingIntInt" type="map[int,int]"/>
# 兼容旧的key,value声明方式,同时指定将抛异常。
2. dynamic 统一包含Bean的定义方式
<variable id="1" name="Dynamic" type="dynamic" value="bean1,bean2">
<value bean="bean3"/>
</variable>
改成
<variable id="1" name="Dynamic" type="dynamic">
<value bean="bean1"/>
<value bean="bean2"/>
<value bean="bean3"/>
</variable>
直接在variable的属性value中声明方式不再支持,统一在包含的element中声明。
3. dynamic 指定基类&可以放入容器中
【基类即Bean将实现继承,仅在dynamic中才支持声明基类,下面是例子】
【继承实现将有 @zl 完成,目前仅完成声明基类的解析】
【解析基类是所有版本的,计划具体实现仅用于platform="conf+cs",由zl决定】
<variable id="1" name="ListInt" type="list[dynamic:BBase]"/>
<variable id="2" name="SetInt" type="set[int]"/> set不支持包含dynamic,特别放这里说明一下
<variable id="3" name="MingIntInt" type="map[int,dynamic:BBase]"/>
<variable id="4" name="BeanWithBase" type="dynamic:BBase"/>
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.1 Java TableCache SoftReference 2022.5.13
------------------------------------------------------------------------------------------------------------------------------
TableCache增加一级RocksDb的缓存,不容易受限于内存。Java SoftReference<T>.
TableCache.Clean 整体考虑。
<<<
TableCache 原来想增加一级基于RocksDb的巨大缓存,由于这个缓存有不少状态需要快速访问,完全增加一级效率不够高,所以决定做个简化版本。
1. TableCache.Lru 还是拥有所有配置的容量内的记录,总是持有必要的状态数据。
2. 记录的用户数据使用 SoftReference 引用。
3. 记录本身还是按旧的机制管理生命期和状态。需要的时候会同步RocksDb。
4. SoftReference 回收的时候,保存一份到RocksDb中。【原子问题需要考虑】
5. SoftReference 不存在,从RocksDb装载。【原子问题需要考虑】
6. RocksDb虽然是持久化到硬盘的,但是重启会全部删除。
9. 使用RocksDb保存被GC的用户数据这个特性做成可选(又是需要if判断)?【没有实现】
*. Cache 实现草稿
【一】
private KV<Record1<K,V>, V> TableX.Load(K key) {
...
if (r.getState() is right) {
var strong = r.Soft.get();
if (null == strong && false == r.getDirty()) { // dirty 时意味着应用做出了修改但还没保存,此时不需要load
strong = RocksDb.get();
r.Soft.set(strong);
}
// strong需要返回,不能从r.soft里面再次获取
// 使用Load的地方:
// 1. Transaction.get等。需要把strong记到事务的RecordAccessed中,在事务结束前都不能触发soft回收。
// 2. selectDirty。可以事务外使用,使用者自己管理strong生命期。
return KV.Create(r, strong);
}
...
// load from storage
var strong = TStorage.Find(key, this);
RocksDb.put(); // 【原则】保持Rocks和后台数据库一致。
r.Soft.set(strong);
...
return KV.Create(r, strong);
}
【二】
Record.setDirty(bool value) {
Dirty = value; 【原来的】
StrongRef = value ? soft.get() : null; // 脏数据在记录内保持一份强引用。
// 由于记录不存在时,StrongRef可为null,所以原来的bool Dirty不能使用 StrongRef != null 代替。
// 需要分成明确的两个变量。
}
【三】
RecordAccessed 增加 Bean StrongRef,保存Load的返回值里的bean引用。
【四】
public void Record1.Flush(Database.Transaction t) {
...
if (null != snapshotValue)
RocksDb.put();
else
RocksDb.Remove();
}
【五】
public void Record1.SetDirty() {
...
case Immediately:
RocksDb.put(); // Immediately 模式需要在这里保持Rocks和后台数据库一致。它走不一样的Flush流程。
break;
}
【六】
private boolean TableCache.Remove(Map.Entry<K, Record1<K, V>> p) {
...
RocksDb.remove();
// 从cache中删除,也需要删除持久化的,这个违背了【原则:RocksDb和后台数据库一致】,
// 但是不删除,会导致长期运行,本地cache一直积累。
return true;
}
【七】
public void Record1.Encode0() {
...
snapshotValue = StrongDirtyValue != null ? getTTable().EncodeValue((V)StrongDirtyValue) : null;
// StrongDirtyValue 最新的value。
}
【原则】
1. RocksDb和后台数据库一致。
2. 事务内访问的记录不能被回收。
3. selectDirty返回的strongref需要使用者自己管理。
>>>
【2022/5/11】
Global 性能测试
------------------------------------------------------------------------------------------------------------------------------
tag 0.9.0 java ready
------------------------------------------------------------------------------------------------------------------------------
TableKey,GlobalTableKey TableName -> TableId
Java New Changes: 1. Gen 2. Collections 3. Log 4. Changes & remove CreateChangeVariableCollector 5. Transaction & Savepoint
Java Global Performance: 【zl】26w/s 200M带宽
3. Test TestGlobal Simulate 异步测试【已经通过测试了 2022.5.9】
把 RocksRaft Changes 应用到 Zeze 中,让 Zeze 实现Bean任意级别的更新。
仅支持整个Bean的订阅。
log factory 问题。(不同步到其他进程没有这个问题)
动态订阅。add listener和notify原子问题。【收集和通知一致,不会出现收集丢失。】
Game.Bag Listener
Online Account (c#)
Global java 异步化: TaskQueueAsync 任务需要参与到队列的推进。全异步和RocksRaft.Transaction.ThreadLocal问题,需要自己实现一个类似AsyncLocal的机制。
StableLinkSid Done(Need Test)
StableLinkSid Prepare:分离LinkName,LinkSid到独立表中。
Arch remove ProviderSessionId;Rename ProviderId to ServerId
Online Test 【肖丽杨】Java
RocksRaft Collection.List LogList
【zl已完成】OpLogs=List<OperateLog>。list中的Bean更新规则:Encode的时indexOf所有的Changed找到索引,Apply=list.get(index).Apply(beanLog)。
2. c# 1) LoadReporter.
3. java 1) LoadReporter.
1. Online Memory Table 可以存储在线相关数据。
功能
a) Local.Online.Count
b) Foreach Local Online
c) LocalData Set Get
维护 memory Table 准确的机制
a) 本机正常Login/Logout/LinkBroken
b) 本机Logout/LinkBroken丢失或迟到,而已经在其他机器上Login,此时需要Redirect过来。
c) Redirect丢失,本机需要一个机制遍历TableCache,慢慢检测并清除Memory中登录状态无效的数据。
事件
Logout事件需要带上当前Memory表中存的用户数据。
1. c# Arch RedirectAll & Test
2. c# Game.Rank TODO GetRankAll Test
1. Zezex Onlines TransmitInProcedure 需要重写。需要改成使用ProviderDirectService.ProviderByServerId。
1. FewModifyList
2. FewModifyMap
c# RedirectGenMain 内建模块Redirect生成。
Java RedirectGenMain 内建模块Redirect生成。
Java 2) Online Logout Check Not Owner.
Java 3) ProviderImplementWithOnline
Java 4) ProviderDirectWithTransmit
c# 2) Online Logout Check Not Owner.
c# 3) ProviderImplementWithOnline
c# 4) ProviderDirectWithTransmit
Global 死锁. lock(CacheState) lock(CacheHolder)之间互相依赖。
3月份调整代码,试图对同一个session(每个serverId对应一个,即CacheHolder)进行互斥同步时的改动引进的bug。
去掉了 lock(session),恢复成原来的 tryBind,tryUnbind里面lock,不持有。仔细想了一下。
互斥由tryBind,tryUnbind的逻辑保证,只允许一个serverid的实例的session前进到下一步,其他都失败。
Builtin Module UnRegister 实现。
c# Zeze.Game.Bag
c# Zeze.Game.Rank
c# Zeze.Game.Online
Java Zeze.Game.Rank Test【zl】
Java Zeze.Game.Bag Test【王鹏安排】
Java Zeze.Game.Online 【zl】
Java Zeze.Game.Bag
Java Zeze.Game.Rank
Redirect 支持异步实现。【Javazl】 c# RedirectAll 错误处理。
c# Arch : redirect Hash & Server Test Ok
c# Arch Redirect Hash & Server async ready.
c# Collections Queue LinkedMap
c# Component DelayRemove AutoKey RedoQueue RedoQueueServer
Java Arch Test:RedirectToServer,RedirectHash Done
ServiceManager.Agent lock 模式:改成全局锁Agent。单线程化。回调也在锁内执行。【放弃,锁内回调风险太高】
ServiceManager: Provider之间连接成功的时候,Pending还没到达。
ServiceManager.ReadyCommit模式时,订阅启动全新广播。
【2022/4/11】
Load 移到 Zeze.Arch 里面,里面使用的MyConfig相关配置移到LoadConfig中。【使用OnSetServerLoad,Game.Load复用暂不考虑了】
Java Arch Callback在不同Redirect模式下的限定和检查
CommitServiceList,ReadyServiceList 不发送整个列表,仅发送系列号。
问题:Java Arch ServiceManager ReadyCommit 依赖Provider之间的连接,但是连接又依赖Indentity-List-Ready。【暴露Pending状态的列表】
ProviderSession 增加 Set(ServiceName,Identity) OnSocketClose 时 foreach (var (s,i)) SetServiceIdentityReadyState(s, i, null);
SetServiceIdentityReadyState(+ServiceName, identity, state);【误会,这个定义在SubscribeState里面的,不需要ServiceName了】
Linkd-Provider之间的连接建立比Provider-List通告早,需要查询得到。【没问题,异步问题已经处理。当连接任何时候准备好,调用SetServiceIdentityReadyState设置进去】
java Arch: ModuleRedirect 重构。
【左尧完成Java了?】Zezex.ModuleRedirect 增加 TransactionLevel 注解配置。
Zezex.ModuleRedirect 去掉依赖Session生成hash模式;RunMyMethod去掉mode;
java Arch: 重构 Provider:分为 Provider(linkd-gs),Provider2(gs-gs)。预计负载算法还需要公用。
Load ServiceManager 新增按按Ip-Port组织的订阅和通告。
Load 更新。
RedoQueue Client 【未测试】
RedoQueue
{
1)存储:QueueId。 RocksDb<TaskId, Full_Encoded_Net_Rpc> 持久化的。
2)Task.Id long 递增 Rpc
Zeze.ServerApp
1) zeze.table<QueueId, LastTaskId> 记住已经同步的最后的任务id,
2) 功能:每个QueueId,for (LastTaskId, end) { Run(task); zeze.table.LastTaskId = task.Id; }
* 特性:允许 Zeze.ServerApp 回档,回档以后,从旧的LastTaskId开始重做任务。
}
Zeze.Component dynamic bean动态增加类型的能力。
LockAsync 单元测试。关键:TryEnterXXXLock。
Queue
GCTable(每个ServerId一个Queue), rename to DelayRemove
Component.AutoKey
java LinkedMap dynamic 动态注册问题。
换换脑子,写一个java版基于KV的LinkedMap
async Connector GetReadySocket WaitReady
GlobakWithRaft java test【zl】【基本可用了】
GlobalAgent NormalClose 超时设置。必须加大或者无限等待。
zeze async await test。remove SimpleThreadPool!
database 异步测试
ServiceManager 异步化
TestCheckpoint 整个跑会失败,单独一个一个测试跑成功。【加了async,没有await】
async TestCheckpointModeTable 直接运行 Trans 目录会出错,单个或者选择开始的几个运行没问题。【AsybcLocal<Transaction>重用有问题,去掉重用】
rocksraft 异步测试【raft还有bug,但这个能测试通过】
Raft.AppendLog 加一个try catach,所有的内部错误都转换成RaftRetryException,这样就不会把内部异常漏给应用了。
AsyncRocksDb
AsyncExecutor
database 异步化
Global With Raft 异步化
rocksraft 异步化
raft 异步化
Global 异步化
c# zeze 嵌套存储过程RunWhileRollback在外层事务Commit时需要处理的问题。还有按调用顺序回调的问题。
Savepoint 成员变量 CommitActions RollbackActions
Savepoint.Commit(nest) CommitActions.AddAll(nest.CommitActions);
Savepoint.Rollback(nest) CommitActions.AddAll(nest.RollbackActions); RollbackActions.AddAll(nest.RollbackActions);
Transaction.FinalCommit() foreach (var a in LastSavepoint.CommitActions) a.trigger();
Transaction.FinalRollback() foreach (var a in LastSavepoint.SavedRollbackActions) a.trigger();
zeze async await compile ok!
Raft.Shutdown 先关闭网络,有错误也不返回了。
TaskOneByOne 重构,新增支持调用异步存储过程和异步协议处理。
Global PulseAll 必须,需要全部等待在死锁检测的线程全部再来一遍,否则仍有可能死锁。
GlobakWithRaft java compile ok!
RaftLog.DecodeTermIndex 仅Decode两个内部变量,不包含应用日志。避免初始化循环依赖。
GlobalWithRaft c# test 1111
CacheHolder 访问 Instance 是旧的代码,引用到旧的static上面了。
AcquireModify Reduce Share 的时候,比如返回原来的事务才能修改数据。
* 这点非Raft版本Global(c#&java)都改成返回主流程修改状态数据。
GloblWithRaftAgent c# WaitLoginSuccess
RocksRaft java
RocksRaft rrjava
GlobalRaft Agent.Initialize & Test
GlobalRaft Agent GetReadySocket() Login ReLogin
GlobalRaft GlobalSerialId 问题解决初步想法:由RocksRaft提供AtomicLong实现,每个事务结束,
成功同步到其他节点。这个Global拿来区分记录申请次数,需要一直递增,可以跳着分配(浪费)。
细节:lock (Raft) { if (atomiclong.get() > lastAppendLog) doAppendLog; }
【2022/3/11】
Global 流程确认:独占排他性,Raft版本部分操作仅Leader有效?
Global NormalClose 需要锁定Session,释放所有锁,确保释放完之前新的服务器不会登录进来。【raft及非raft版本都需要考虑】
Global Cleanup 需要锁定,释放所有锁,这里无法通过lock(session)保护。
Global Login Bind以后,释放存在的锁,看来没有问题,需要确认。
Global ReLogin 不涉及所释放,能Bind成功就表示ReLogin成功,看来没有问题,需要确认。
GlobalCacheManagerWithRaft 关键Transient:CacheState.AcquireStatePending 仅在Leader上使用,不需要同步到Follower。
RocksRaft & rrcs GenTable OpenTable 提供模板化打开表格能力。
RocksRaft Gen Bean.Variable.Transient Attribute
RocksRaft Gen
. Bean.Kind : "bean" "beankey" "rocks" "dynamic" ""
. project platform add type: "internal+cs" "internal+java" 增加属性 IsInternal 仅把原来Gen/下的类生成到src空间下,src下的代码不生成。
RocksRaft Collection.Set
RocksRaft Raft.AppendLog
RocksRaft NestProcedureContainer Test
RocksRaft Simple NestProcedure Test
RocksRaft Edit Bean In Container
Raft.AppendLog Future Add Duplicate Index. Fatal!【观察不到了!】
c# Global 慢?【网络事件也和普通Task共享了一个线程池,造成rpc.result处理也排队的结果,等async解决】
RocksRaft 日志收集基本完工。
Raft.Test 只删除日志相关数据库。保留重复请求数据库。
Raft.UniqueRequestSet.Put 优化:先读取并检查状态,减少写操作。
Raft.UniqueRequest.Expired
Raft.Expired
Raft.AppendLog 带上当前Rpc.Result,当发现重复请求的时候返回
Raft.LogSequence.FindMaxMajorityLogIndex 新实现,不需要遍历Log。
Raft.LogSequence.FindMaxMajorityLog 里面的 ReadLog 优化掉。
1. Log.cs: logger.Fatal("truncate committed entries"); Fatal!【选举移动代码的BUG:Term在递增前使用】
Raft.Apply 分批进行,让其他操作有运行机会。解决启动时,apply整个日志锁住时间太长的问题。
Raft.State.Timeout 恢复状态模式。【不恢复,就轮询了】
RaftLog.ToString More Detail
Raft.Agent TryGetReadySocket 总是 null。【没有发现问题】
Net.Connector.OnSocketHandshakeDone Fail 原因。【没有发现问题】
Raft.Shutdown 的时候快速失败-Cancel在Future上等待的任务。【有时shutdown会很慢】
2. Raft.Vote Leader 第一个Hearbeat被拒绝; 导致不停的选举。
SaveLog.RocksDb.Put 卡住导致超时?
3. Raft.Count 错误处理问题?请求已经被处理,但是结果丢失,重发请求发生了不会重做的异常,这会导致Count统计不正确。【Raft.AppendLog 检查LogSequence是否null】
Raft.Vote 优先级++++++++++++++++++++++++++ 初步考虑仅使用不同的延迟。RandomDelay + DelayPriority;
Raft.Agent 客户端卡住了? 【锁内 Env.Exit卡住了,导致OnTimer任务不停积累,最终线程数量巨大】
Raft.RocksDb.Open Try N Times
Raft.Vote 投票后推迟自己再次选举的时间,免得浪费。【现在代码注释掉了】
Raft.Log.FollowerOnAppendEntries 优化。
Raft.Log.Index 必须递增,去掉原来支持跳着分配的代码,并且在需要的地方增加错误检查。
Raft.Agent ActiveTime 重连功能删除,
Net.Connector 轮询重连,【恢复回状态检查实现,轮询改为10分钟的错误处理】
Net.Connector 轮询重连?以后恢复成连接断开才启动timer?先轮询,等raft稳定了再考虑。
Raft.Test 关闭2节点后,一直没有重启。【测试程序出错了】
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )