• 编写云计算计费系统


    上一篇介绍了自建一个Laxcus云服务需要了解的基础知识,这一篇咱们从编程角度,来说说如何编写一个简单的云服务计费系统,如果你有更复杂的需求,可以在这个上面扩展。更进一步,如果你非常熟悉Laxcus分布式操作系统的运行流程,那么可以去GitHub拿源代码修改,甚至直接操作底层或者硬件获取必要信息,这样会更贴近你的需求。
    闲话不多说,咱们正式进入主题。
    编写一个简单的Laxcus云服务计费系统,需要这样三步:
    1.了解Check User Cost命令。
    2.了解Check User Cost命令的返回结果。
    3.生成Check User Cost命令,调用系统DSDK软件包的API,把命令投递到Laxcus计算机集群上执行,然后等待返回结果,解析结果中的信息,结合你的计费算法,得出计费结果。

    目前Laxcus分布式操作系统的DSDK软件包,只支持Java编程,同类型的C、C++接口、Python接口,还处于Alpha状态,暂时没有公布出来。所以咱们这篇文章就以Java编程的方式,来介绍编写Laxcus云服务计费的系统。

    一、Check User Cost命令
    Check User Cost命令的源代码如下

    1. public class CheckUserCostProduct extends EchoProduct {
    2. private static final long serialVersionUID = 3146106632408001248L;
    3. /** 用户签名 -> 单元 **/
    4. private Map array = new TreeMap();
    5. /**
    6. * 构造默认的服务器系统信息检测结果
    7. */
    8. public CheckUserCostProduct() {
    9. super();
    10. }
    11. /**
    12. * 从可类化数据读取器解析服务器系统信息检测结果
    13. * @param reader 可类化数据读取器
    14. */
    15. public CheckUserCostProduct(ClassReader reader) {
    16. this();
    17. resolve(reader);
    18. }
    19. /**
    20. * 构造服务器系统信息检测结果的数据副本
    21. * @param that CheckUserCostProduct实例
    22. */
    23. private CheckUserCostProduct(CheckUserCostProduct that) {
    24. super(that);
    25. array.putAll(that.array);
    26. }
    27. /**
    28. * 加一个
    29. * @param product
    30. */
    31. public void add(CheckUserCostProduct product) {
    32. for (UserCostElement element : product.array.values()) {
    33. add(element.getIssuer(), element);
    34. }
    35. }
    36. /**
    37. * 加全部
    38. * @param issuer 用户签名
    39. * @param element 成员
    40. */
    41. public void add(Siger issuer, UserCostElement element) {
    42. UserCostElement that = array.get(issuer);
    43. if (that != null) {
    44. that.addAll(element.list());
    45. } else {
    46. array.put(issuer, element);
    47. }
    48. }
    49. /**
    50. * 加一个单元
    51. * @param issuer 签名
    52. * @param item 成员
    53. */
    54. public void add(Siger issuer, UserCostItem item) {
    55. UserCostElement element = array.get(issuer);
    56. if (element != null) {
    57. element.add(item);
    58. } else {
    59. element = new UserCostElement(issuer);
    60. element.add(item);
    61. array.put(element.getIssuer(), element);
    62. }
    63. }
    64. /**
    65. * 输出全部
    66. * @return
    67. */
    68. public List list() {
    69. return new ArrayList(array.values());
    70. }
    71. /**
    72. * 查找一个成员
    73. * @param siger 签名
    74. * @return 返回匹配的成员
    75. */
    76. public UserCostElement find(Siger siger) {
    77. return array.get(siger);
    78. }
    79. /**
    80. * 判断是空
    81. * @return
    82. */
    83. public boolean isEmpty() {
    84. return array.isEmpty();
    85. }
    86. /**
    87. * 有效单元数目
    88. * @return 整数
    89. */
    90. public int size() {
    91. return array.size();
    92. }
    93. /* (non-Javadoc)
    94. * @see com.laxcus.echo.product.EchoProduct#duplicate()
    95. */
    96. @Override
    97. public CheckUserCostProduct duplicate() {
    98. return new CheckUserCostProduct(this);
    99. }
    100. /* (non-Javadoc)
    101. * @see com.laxcus.echo.product.EchoProduct#buildSuffix(com.laxcus.util.ClassWriter)
    102. */
    103. @Override
    104. protected void buildSuffix(ClassWriter writer) {
    105. writer.writeInt(array.size());
    106. for (UserCostElement e : array.values()) {
    107. writer.writeObject(e);
    108. }
    109. }
    110. /* (non-Javadoc)
    111. * @see com.laxcus.echo.product.EchoProduct#resolveSuffix(com.laxcus.util.ClassReader)
    112. */
    113. @Override
    114. protected void resolveSuffix(ClassReader reader) {
    115. int size = reader.readInt();
    116. for (int i = 0; i < size; i++) {
    117. UserCostElement element = new UserCostElement(reader);
    118. add(element.getIssuer(), element);
    119. }
    120. }
    121. }

    Check User Cost类中的变量需要做点解释
    1. 节点类型,它的定义,可以查阅SiteTag类的源代码,目前是除Front节点和Watch节点之外,都能够支持,Front节点和Watch注册用户和系统管理员使用的节点,并不涉及计费问题。如果指定全部节点,那么all变量设成“true”。
    2. 用户签名,对应Siger类,它的本质就是一个SHA256签名。生成SHA256签名可以使用Laxkit类的doSiger方法来实现,doSiger方法的作用是把一个字符串转换成数字签名,输入是字符文本,输出是Siger类。
    3. 查询的命名。在Laxcus集群里,所有分布式计算工作都有一个名称,比如执行大型的分布式计算工作,对应CONDUCT名称,如果上传文件到云端,对应UPLOAD CLOUD FILE名称。依此类推。Naming的作用是忽略大小写,即一个 CONDUCT和conduct等价。如果置空,表示搜索与用户签名相关的全部命令
    4. 忽略的命令。它的作用和查询命名相反,即不查询某些命名。
    5. 开始、结束命令。这个参数是一个长整数值,使用转义函数来取得。

    比如我们想查询2022年12月1日到2022年12月2日两天,一个名为“Tubex“的用户记录,但是不包括CONDUCT命名,那么生成CheckUserCost的命令可以这样写:

    1. CheckUserCost cmd = new CheckUserCost();
    2. cmd.setAll(true);
    3. Siger siger = Laxkit.doSiger(“tubex”);
    4. cmd.addUser(siger);
    5. cmd.addExclude(new Naming("conduct"));
    6. long timestamp = CalendarGenerator.splitTimestamp("2022-12-1");
    7. cmd.setBeginTime(timestamp);
    8. timestamp = CalendarGenerator.splitTimestamp("2022-12-2");
    9. cmd.setEndTime(timestamp);

    二、Check User Cost命令的返回结果
    Check User Cost命令的返回结果对应CheckUserCostProduct类,CheckUserCostProduct继承自EchoProduct,保存所有检索结果。参数是基于用户签名和查询单元的TreeMap,CheckUserCostProduct类中包含了UserCostElement类,而UserCostElement类又包含UserCostItem类,这样就形成了“CheckUserCostProduct -> CheckUserCostElement -> UserCostItem”三级关系。因为CheckUserCostProduct类和UserCostElement类比较简单,咱们重点说说UserCostItem类。如果开发者想增加更多的计费元素,可以结合需求调用系统底层修改UserCostItem的源代码。

    UserCostItem源代码如下:

    1. public final class UserCostItem implements Classable, Cloneable, Serializable, Comparable {
    2. private static final long serialVersionUID = -6293384810197643693L;
    3. /** 节点类型 **/
    4. private byte family;
    5. /** 调用器编号 **/
    6. private long invokerId;
    7. /** 迭代次数 **/
    8. private int iterateIndex;
    9. /** 操作命名 **/
    10. private String command;
    11. /** 开始和结束时间 **/
    12. private long initTime, endTime;
    13. /** 被线程调用,在EchoInvoker中的迭代时间 **/
    14. private long threadIterateTime;
    15. /** 接收数据流量 **/
    16. private long receiveFlows;
    17. /** 发送数据流量 **/
    18. private long sendFlows;
    19. /** 服务号,对应Command的slogan,全局唯一 **/
    20. private long slogan;
    21. /** 服务迭代编号,对应服务号,根据分布流程,从1开始逐次传递增加 **/
    22. private int sloganIndex;
    23. /** 命令级别,对应Command类 **/
    24. private byte priority;
    25. /**
    26. * 构造默认的被刷新处理单元
    27. */
    28. public UserCostItem() {
    29. super();
    30. family = 0;
    31. invokerId = 0;
    32. iterateIndex = 0;
    33. command = null;
    34. initTime = 0;
    35. endTime = 0;
    36. threadIterateTime = 0;
    37. receiveFlows = 0;
    38. sendFlows = 0;
    39. slogan = 0;
    40. sloganIndex = 0;
    41. priority = 0;
    42. }
    43. /**
    44. * 根据传入实例,生成用户消费单元的数据副本
    45. * @param that UserCostItem实例
    46. */
    47. private UserCostItem(UserCostItem that) {
    48. super();
    49. family = that.family;
    50. invokerId = that.invokerId;
    51. iterateIndex = that.iterateIndex;
    52. command = that.command;
    53. initTime = that.initTime;
    54. endTime = that.endTime;
    55. threadIterateTime = that.threadIterateTime;
    56. receiveFlows = that.receiveFlows;
    57. sendFlows = that.sendFlows;
    58. slogan = that.slogan;
    59. sloganIndex = that.sloganIndex;
    60. priority = that.priority;
    61. }
    62. /**
    63. * 从可类化数据读取器中用户消费单元
    64. * @param reader 可类化数据读取器
    65. */
    66. public UserCostItem(ClassReader reader) {
    67. this();
    68. resolve(reader);
    69. }
    70. /**
    71. * 设置节点类型
    72. * @param who
    73. */
    74. public void setFamily(byte who) {
    75. family = who;
    76. }
    77. /**
    78. * 返回节点类型
    79. * @return
    80. */
    81. public byte getFamily() {
    82. return family;
    83. }
    84. /**
    85. * 设置调用器编号
    86. * @param id 编号
    87. */
    88. public void setInvokerId(long id) {
    89. invokerId = id;
    90. }
    91. /**
    92. * 返回调用器编号
    93. * @return 毫秒
    94. */
    95. public long getInvokerId() {
    96. return invokerId;
    97. }
    98. /**
    99. * 设置迭代次数
    100. * @param i
    101. */
    102. public void setIterateIndex(int i) {
    103. iterateIndex = i;
    104. }
    105. /**
    106. * 返回迭代次数
    107. * @return
    108. */
    109. public int getIterateIndex() {
    110. return iterateIndex;
    111. }
    112. /**
    113. * 设置命令
    114. * @param s
    115. */
    116. public void setCommand(String s) {
    117. command = s;
    118. }
    119. /**
    120. * 返回命令
    121. * @return
    122. */
    123. public String getCommand() {
    124. return command;
    125. }
    126. /**
    127. * 设置初始时间
    128. * @param ms
    129. */
    130. public void setInitTime(long ms) {
    131. initTime = ms;
    132. }
    133. /**
    134. * 返回初始时间
    135. * @return
    136. */
    137. public long getInitTime() {
    138. return initTime;
    139. }
    140. /**
    141. * 设置结束时间
    142. * @param ms
    143. */
    144. public void setEndTime(long ms) {
    145. endTime = ms;
    146. }
    147. /**
    148. * 返回结束时间
    149. * @return
    150. */
    151. public long getEndTime() {
    152. return endTime;
    153. }
    154. /**
    155. * 设置被线程调用,在EchoInvoker中的迭代时间
    156. * @param ms 毫秒
    157. */
    158. public void setThreadIterateTime(long ms) {
    159. threadIterateTime = ms;
    160. }
    161. /**
    162. * 返回被线程调用,在EchoInvoker中的迭代时间
    163. * @return 毫秒
    164. */
    165. public long getThreadIterateTime() {
    166. return threadIterateTime;
    167. }
    168. /**
    169. * 设置接收数据流尺寸
    170. * @param len 数据长度
    171. */
    172. public void setReceiveFlows(long len) {
    173. receiveFlows = len;
    174. }
    175. /**
    176. * 返回接收数据流尺寸
    177. * @return 数据长度
    178. */
    179. public long getReceiveFlows() {
    180. return receiveFlows;
    181. }
    182. /**
    183. * 设置发送数据流尺寸
    184. * @param len 数据长度
    185. */
    186. public void setSendFlows(long len) {
    187. sendFlows = len;
    188. }
    189. /**
    190. * 返回发送数据流尺寸
    191. * @return 数据长度
    192. */
    193. public long getSendFlows() {
    194. return sendFlows;
    195. }
    196. /**
    197. * 设置服务号
    198. * @param no 服务号
    199. */
    200. public void setSlogan(long no) {
    201. slogan = no;
    202. }
    203. /**
    204. * 返回服务号
    205. * @return 服务号
    206. */
    207. public long getSlogan() {
    208. return slogan;
    209. }
    210. /**
    211. * 设置服务编号,不定义是0
    212. * @param no 长整型
    213. */
    214. public void setSloganIndex(int no) {
    215. sloganIndex = no;
    216. }
    217. /**
    218. * 返回服务编号
    219. * @return 长整型
    220. */
    221. public int getSloganIndex() {
    222. return sloganIndex;
    223. }
    224. /**
    225. * 设置命令优先级
    226. * @param no 命令优先级
    227. */
    228. public void setPriority(byte no) {
    229. priority = no;
    230. }
    231. /**
    232. * 返回命令优先级
    233. * @return 命令优先级
    234. */
    235. public byte getPriority() {
    236. return priority;
    237. }
    238. /**
    239. * 生成当前实例的数据副本
    240. * @return UserCostItem实例
    241. */
    242. public UserCostItem duplicate() {
    243. return new UserCostItem(this);
    244. }
    245. /*
    246. * (non-Javadoc)
    247. * @see java.lang.Object#clone()
    248. */
    249. @Override
    250. public Object clone() {
    251. return duplicate();
    252. }
    253. /*
    254. * (non-Javadoc)
    255. * @see java.lang.Object#hashCode()
    256. */
    257. @Override
    258. public int hashCode() {
    259. return (int) ((invokerId >>> 32) ^ invokerId);
    260. }
    261. /*
    262. * (non-Javadoc)
    263. * @see java.lang.Object#equals(java.lang.Object)
    264. */
    265. @Override
    266. public boolean equals(Object that) {
    267. if (that == null || getClass() != that.getClass()) {
    268. return false;
    269. } else if (that == this) {
    270. return true;
    271. }
    272. // 比较
    273. return compareTo((UserCostItem ) that) == 0;
    274. }
    275. /* (non-Javadoc)
    276. * @see java.lang.Comparable#compareTo(java.lang.Object)
    277. */
    278. @Override
    279. public int compareTo(UserCostItem that) {
    280. int ret = Laxkit.compareTo(family, that.family);
    281. if (ret == 0) {
    282. ret = Laxkit.compareTo(initTime, that.initTime);
    283. }
    284. if (ret == 0) {
    285. ret = Laxkit.compareTo(command, that.command, false);
    286. }
    287. if (ret == 0) {
    288. ret = Laxkit.compareTo(invokerId, that.invokerId);
    289. }
    290. return ret;
    291. }
    292. /* (non-Javadoc)
    293. * @see com.laxcus.util.Classable#build(com.laxcus.util.ClassWriter)
    294. */
    295. @Override
    296. public int build(ClassWriter writer) {
    297. int size = writer.size();
    298. buildSuffix(writer);
    299. return writer.size() - size;
    300. }
    301. /* (non-Javadoc)
    302. * @see com.laxcus.util.Classable#resolve(com.laxcus.util.ClassReader)
    303. */
    304. @Override
    305. public int resolve(ClassReader reader) {
    306. int seek = reader.getSeek();
    307. resolveSuffix(reader);
    308. return reader.getSeek() - seek;
    309. }
    310. /**
    311. * 保存参数
    312. * @param writer
    313. */
    314. protected void buildSuffix(ClassWriter writer) {
    315. writer.write(family);
    316. writer.writeLong(invokerId);
    317. writer.writeInt(iterateIndex);
    318. writer.writeString(command);
    319. writer.writeLong(initTime);
    320. writer.writeLong(endTime);
    321. writer.writeLong(threadIterateTime);
    322. writer.writeLong(receiveFlows);
    323. writer.writeLong(sendFlows);
    324. writer.writeLong(slogan);
    325. writer.writeInt(sloganIndex);
    326. writer.write(priority);
    327. }
    328. /**
    329. * 解析参数
    330. * @param reader
    331. */
    332. protected void resolveSuffix(ClassReader reader) {
    333. family = reader.read();
    334. invokerId = reader.readLong();
    335. iterateIndex = reader.readInt();
    336. command = reader.readString();
    337. initTime = reader.readLong();
    338. endTime = reader.readLong();
    339. threadIterateTime = reader.readLong();
    340. receiveFlows = reader.readLong();
    341. sendFlows = reader.readLong();
    342. slogan = reader.readLong();
    343. sloganIndex = reader.readInt();
    344. priority = reader.read();
    345. }
    346. }

    下面说说UserCostItem比较重要的一些参数,通过这些参数,结束计费算法规则,你将最终得到你的计费
    1. family,节点类型,它对应SiteTag中的节点类型
    2. invokerId,调用器编号,也可以理解为进程编号。如果查阅系统日志,把它和节点类型结合,可以定位提取出调用器产生的运行记录。
    3. iterateIndex,迭代次数。Laxcus调用器存在被系统多次调用的可能,迭代编号是指它循环执行的次数。多次迭代之间,调用器会被系统悬挂起来,直到运行条件满足再次触发执行。迭代次数理论上最少1次,最多不限。
    4. command,操作命名,这个参数对应CheckUserCost中的includes参数。
    5. initTime, endTime,调用器的第一次启动时间和最后时间,两个参数的差值,就是调用器运行的总时间。如果以时间为标准进行计费,通过这个时间,结合计费结合,可以得出一个计费结果。
    6. receiveFlows,调用器在分布计算过程中,接收得到的数据流量。流量以字节为单位,这个参数通常是各种计费标准的主要依据之一。
    7. sendFlows,调用器在分布计算过程中,发送出去的数据流量。这个参数同样也是计费标准参照之一。
    8. slogan,服务号,是一个64位的整数值。它在分布计算执行前由系统赋值,保证运行环境全局唯一,如果分布计算过程中产生了分裂(类似Linux编程中的fork),这个服务号也会被继承下来。通过服务号,无论分布计算在多少个节点执行,其间发生了多少次分裂,都可以把它们记录下来,然后反向推导出分布计算执行的先后顺序和分布执行情况。如果有需要,在这个基础上,进一步形成可视化的分布计算执行流程图表,必要时提供给用户,做为分布计算的佐证之一。
    9. sloganIndex,服务迭代编号,即关联服务号的调用器,在分布式计算过程中发生了分裂,就在这个编号上做一个加1的操作。服务迭代编号从1开始,随着调用器分裂逐层传递增加。
    10. priority,操作执行优先级,前一篇说过,用户的分布业务,有四个级别,从大到小分为MAX级,NORMAL级,MINI级,NONE级。调整用户优先级由管理员来操作,默认情况下,所有用户都是NONE级,即不定义优先级。获得更高优先级应用业务,总是比低于它一级的应用业务,优先取得Laxcus计算机集群的资源,优先取得执行权限进行分布计算工作。所以priority也是一个计费参照之一,更高优先级的业务,在享受优先处理权利时,也应该付出更多的消费金额。

    下面是UserCostElement类和CheckUserCostProduct类的源程序代码,因为比较简单,就不单独说明了。

    1. public final class UserCostElement implements Classable, Cloneable, Serializable, Comparable {
    2. private static final long serialVersionUID = 5651643178030182283L;
    3. /** 用户签名 **/
    4. private Siger issuer;
    5. /** 未使用容量 **/
    6. private TreeSet array = new TreeSet();
    7. /**
    8. * 构造默认的用户资源消耗成员
    9. */
    10. public UserCostElement() {
    11. super();
    12. }
    13. /**
    14. * 构造用户资源消耗成员
    15. * @param issuer 用户签名
    16. */
    17. public UserCostElement(Siger issuer) {
    18. this();
    19. setIssuer(issuer);
    20. }
    21. /**
    22. * 根据传入实例,生成用户资源消耗成员的数据副本
    23. * @param that UserCostElement实例
    24. */
    25. private UserCostElement(UserCostElement that) {
    26. super();
    27. issuer = that.issuer;
    28. array.addAll(that.array);
    29. }
    30. /**
    31. * 从可类化数据读取器中用户资源消耗成员
    32. * @param reader 可类化数据读取器
    33. */
    34. public UserCostElement(ClassReader reader) {
    35. this();
    36. resolve(reader);
    37. }
    38. /**
    39. * 设置用户签名
    40. * @param who 签名
    41. */
    42. public void setIssuer(Siger who) {
    43. issuer = who;
    44. }
    45. /**
    46. * 返回用户签名
    47. * @return 签名
    48. */
    49. public Siger getIssuer() {
    50. return issuer;
    51. }
    52. /**
    53. * 加一个单元
    54. * @param item
    55. * @return
    56. */
    57. public boolean add(UserCostItem item) {
    58. if (item != null) {
    59. return array.add(item);
    60. }
    61. return false;
    62. }
    63. /**
    64. * 增加一批单元
    65. * @param a
    66. * @return
    67. */
    68. public int addAll(Collection a) {
    69. int size = array.size();
    70. if (a != null) {
    71. for (UserCostItem item : a) {
    72. add(item);
    73. }
    74. }
    75. return array.size() - size;
    76. }
    77. /**
    78. * 返回单元
    79. * @return
    80. */
    81. public List list() {
    82. return new ArrayList(array);
    83. }
    84. /**
    85. * 全部成员
    86. * @return
    87. */
    88. public int size() {
    89. return array.size();
    90. }
    91. /**
    92. * 生成当前实例的数据副本
    93. * @return UserCostElement实例
    94. */
    95. public UserCostElement duplicate() {
    96. return new UserCostElement(this);
    97. }
    98. /*
    99. * (non-Javadoc)
    100. * @see java.lang.Object#clone()
    101. */
    102. @Override
    103. public Object clone() {
    104. return duplicate();
    105. }
    106. /*
    107. * (non-Javadoc)
    108. * @see java.lang.Object#equals(java.lang.Object)
    109. */
    110. @Override
    111. public boolean equals(Object that) {
    112. if (that == null || getClass() != that.getClass()) {
    113. return false;
    114. } else if (that == this) {
    115. return true;
    116. }
    117. // 比较
    118. return compareTo((UserCostElement) that) == 0;
    119. }
    120. /* (non-Javadoc)
    121. * @see java.lang.Comparable#compareTo(java.lang.Object)
    122. */
    123. @Override
    124. public int compareTo(UserCostElement that) {
    125. if (that == null) {
    126. return 1;
    127. }
    128. // 比较参数
    129. return Laxkit.compareTo(issuer, that.issuer);
    130. }
    131. /* (non-Javadoc)
    132. * @see com.laxcus.util.Classable#build(com.laxcus.util.ClassWriter)
    133. */
    134. @Override
    135. public int build(ClassWriter writer) {
    136. int size = writer.size();
    137. buildSuffix(writer);
    138. return writer.size() - size;
    139. }
    140. /* (non-Javadoc)
    141. * @see com.laxcus.util.Classable#resolve(com.laxcus.util.ClassReader)
    142. */
    143. @Override
    144. public int resolve(ClassReader reader) {
    145. int seek = reader.getSeek();
    146. resolveSuffix(reader);
    147. return reader.getSeek() - seek;
    148. }
    149. /**
    150. * 保存参数
    151. * @param writer
    152. */
    153. protected void buildSuffix(ClassWriter writer) {
    154. writer.writeObject(issuer);
    155. int size = array.size();
    156. writer.writeInt(size);
    157. for (UserCostItem e : array) {
    158. writer.writeObject(e);
    159. }
    160. }
    161. /**
    162. * 解析参数
    163. * @param reader
    164. */
    165. protected void resolveSuffix(ClassReader reader) {
    166. issuer = new Siger(reader);
    167. int size = reader.readInt();
    168. for (int i = 0; i < size; i++) {
    169. UserCostItem item = new UserCostItem(reader);
    170. add(item);
    171. }
    172. }
    173. }
    1. public class CheckUserCostProduct extends EchoProduct {
    2. private static final long serialVersionUID = 3146106632408001248L;
    3. /** 用户签名 -> 单元 **/
    4. private Map array = new TreeMap();
    5. /**
    6. * 构造默认的服务器系统信息检测结果
    7. */
    8. public CheckUserCostProduct() {
    9. super();
    10. }
    11. /**
    12. * 从可类化数据读取器解析服务器系统信息检测结果
    13. * @param reader 可类化数据读取器
    14. */
    15. public CheckUserCostProduct(ClassReader reader) {
    16. this();
    17. resolve(reader);
    18. }
    19. /**
    20. * 构造服务器系统信息检测结果的数据副本
    21. * @param that CheckUserCostProduct实例
    22. */
    23. private CheckUserCostProduct(CheckUserCostProduct that) {
    24. super(that);
    25. array.putAll(that.array);
    26. }
    27. /**
    28. * 加一个
    29. * @param product
    30. */
    31. public void add(CheckUserCostProduct product) {
    32. for (UserCostElement element : product.array.values()) {
    33. add(element.getIssuer(), element);
    34. }
    35. }
    36. /**
    37. * 加全部
    38. * @param issuer 用户签名
    39. * @param element 成员
    40. */
    41. public void add(Siger issuer, UserCostElement element) {
    42. UserCostElement that = array.get(issuer);
    43. if (that != null) {
    44. that.addAll(element.list());
    45. } else {
    46. array.put(issuer, element);
    47. }
    48. }
    49. /**
    50. * 加一个单元
    51. * @param issuer 签名
    52. * @param item 成员
    53. */
    54. public void add(Siger issuer, UserCostItem item) {
    55. UserCostElement element = array.get(issuer);
    56. if (element != null) {
    57. element.add(item);
    58. } else {
    59. element = new UserCostElement(issuer);
    60. element.add(item);
    61. array.put(element.getIssuer(), element);
    62. }
    63. }
    64. /**
    65. * 输出全部
    66. * @return
    67. */
    68. public List list() {
    69. return new ArrayList(array.values());
    70. }
    71. /**
    72. * 查找一个成员
    73. * @param siger 签名
    74. * @return 返回匹配的成员
    75. */
    76. public UserCostElement find(Siger siger) {
    77. return array.get(siger);
    78. }
    79. /**
    80. * 判断是空
    81. * @return
    82. */
    83. public boolean isEmpty() {
    84. return array.isEmpty();
    85. }
    86. /**
    87. * 有效单元数目
    88. * @return 整数
    89. */
    90. public int size() {
    91. return array.size();
    92. }
    93. /* (non-Javadoc)
    94. * @see com.laxcus.echo.product.EchoProduct#duplicate()
    95. */
    96. @Override
    97. public CheckUserCostProduct duplicate() {
    98. return new CheckUserCostProduct(this);
    99. }
    100. /* (non-Javadoc)
    101. * @see com.laxcus.echo.product.EchoProduct#buildSuffix(com.laxcus.util.ClassWriter)
    102. */
    103. @Override
    104. protected void buildSuffix(ClassWriter writer) {
    105. writer.writeInt(array.size());
    106. for (UserCostElement e : array.values()) {
    107. writer.writeObject(e);
    108. }
    109. }
    110. /* (non-Javadoc)
    111. * @see com.laxcus.echo.product.EchoProduct#resolveSuffix(com.laxcus.util.ClassReader)
    112. */
    113. @Override
    114. protected void resolveSuffix(ClassReader reader) {
    115. int size = reader.readInt();
    116. for (int i = 0; i < size; i++) {
    117. UserCostElement element = new UserCostElement(reader);
    118. add(element.getIssuer(), element);
    119. }
    120. }
    121. }

    最后,我们需要把它们整合起来,编写成计算机程序,投递给Laxcus计算机集群来处理,这里的代码就非常简单,只有以下几步:
    1.生成命令 (这步上面已经演示)
    2.生成一个异步监听接口,和命令一起,交给命令分派接口处理。
    3.调用Laxcus分布式操作系统DSDK中的命令分派接口,把命令和异步监听器投递给它,DSDK代让命令分派接口投递给Laxcus集群处理。
    4.异步监听接口收到反馈结果,解析CheckUsetCostProduct中的参数,结合计费算法,得出计费结果。
    这些步骤集合起来,就是下面这样一段代码:

    1. class CheckUserCostProductListener implements ProductListener {
    2.         @Override
    3.         public void push(Object e) {
    4.             boolean success = (e != null && e.getClass() == CheckUserCostProduct.class);
    5.             if (!success) {
    6.                 // 不成功,做出错的处理
    7.                 return;
    8.             }
    9.             // 成功,提取返回参数,结束计费算法,得出计费结果
    10.         }
    11.     }
    12. // 1. 生成命令
    13. CheckUserCost cmd = new CheckUserCost();
    14. cmd.setAll(true);
    15. Siger siger = Laxkit.doSiger("tubex");
    16. cmd.addUser(siger);
    17. cmd.addExclude(new Naming("conduct"));
    18. long timestamp = CalendarGenerator.splitTimestamp("2022-12-1");
    19. cmd.setBeginTime(timestamp);
    20. timestamp = CalendarGenerator.splitTimestamp("2022-12-2");
    21. cmd.setEndTime(timestamp);
    22. // 2. 生成异步监听器,返回结果将投递给它处理
    23. CheckUserCostProductListener listner = new CheckUserCostProductListener();
    24. // 3. 生成交互适配器,在命令投递进入集群前出现错误,将由它来处理和显示
    25. MeetDisplayAdapter adapter = new MeetDisplayAdapter(listener);
    26. // 4. 调用系统API,把命令投递给集群处理
    27. CommandDispatcher dispatcher = PlatformKit.findListener(CommandDispatcher.class);
    28. dispatcher.submit(cmd, true, new CommandAuditorAdapter(), adapter);

    上面这些代码通过编译,做成一个Laxcus分布式操作系统的应用软件,就可以运行了。
    另外,如果是在Laxcus管理员桌面环境以外运行,那么就要把DSDK集成起来,并且连接进入Laxcus集群,才能执行上面的操作。
    至此,一个简单的Laxcus云服务计费系统设计完成。有兴趣不妨去试试,把它“润”起来,看看你的Laxcus云服务有多少人在使用,他们在执行什么工作,消耗了多少计算机资源,也或者看看有什么改进工作要做吧。

  • 相关阅读:
    【TypeScript】-- TS之面向对象
    STL-stack、queue和priority_queue的模拟实现
    计算机毕业设计之java+ssm美味厨房点餐系统
    物联网AI MicroPython传感器学习 之 TEA5767 FM收音机模块
    东盟与中日韩(10+3)中小企业人工智能产业论坛
    【JavaScript】 一万字 JavaScript 笔记(详细讲解 + 代码演示 + 图解)
    农林种植类VR虚拟仿真实验教学整体解决方案
    卖出看涨期权的例子:Selling a Call Option
    python逆向基础流程(纯小白教程)
    【Java 基础篇】Java transient 关键字详解:对象序列化与非序列化字段
  • 原文地址:https://blog.csdn.net/laxcus/article/details/128186727