You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

idregister.py 3.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. """
  2. worker id generator
  3. """
  4. # !/usr/bin/python
  5. # coding=UTF-8
  6. from threading import Thread
  7. import time
  8. import logging
  9. import redis
  10. class Register:
  11. """
  12. redis封装
  13. - host 代表redis ip
  14. - port 代表redis端口
  15. - max_worker_id worker_id的最大值, 默认为100
  16. - password redis的密码, 默认为空
  17. """
  18. def __init__(self, host, port, max_worker_id=100, password=None):
  19. self.redis_impl = redis.StrictRedis(host=host, port=port, db=0, password=password)
  20. self.loop_count = 0
  21. self.max_loop_count = 10
  22. self.worker_id_expire_time = 15
  23. self.max_worker_id = max_worker_id
  24. self.worker_id = -1
  25. self.is_stop = False
  26. def get_lock(self, key):
  27. """
  28. 获取分布式全局锁,并设置过期时间为30秒
  29. """
  30. if self.redis_impl.setnx(key, 1):
  31. self.redis_impl.expire(key, 30)
  32. return True
  33. if self.redis_impl.ttl(key) < 0:
  34. self.redis_impl.expire(key, 30)
  35. return False
  36. def stop(self):
  37. """
  38. 退出注册器的线程
  39. """
  40. self.is_stop = True
  41. def get_worker_id(self):
  42. """
  43. 获取全局唯一worker_id, 会创建一个线程给worker id续期
  44. 失败返回-1
  45. """
  46. self.loop_count = 0
  47. def extern_life(my_id):
  48. while 1:
  49. time.sleep(self.worker_id_expire_time / 3)
  50. # 是否关闭了
  51. if self.is_stop:
  52. return
  53. # 更新生命周期
  54. if self.worker_id != my_id:
  55. break
  56. try:
  57. self.redis_impl.expire(
  58. f"IdGen:WorkerId:Value:{my_id}",
  59. self.worker_id_expire_time)
  60. except Exception as exe:
  61. logging.error(exe)
  62. continue
  63. self.worker_id = self.__get_next_worker_id()
  64. if self.worker_id > -1:
  65. Thread(target=extern_life, args=[self.worker_id]).start()
  66. return self.worker_id
  67. def __get_next_worker_id(self):
  68. """
  69. 获取全局唯一worker id内部实现
  70. """
  71. cur = self.redis_impl.incrby("IdGen:WorkerId:Index", 1)
  72. def can_reset():
  73. try:
  74. reset_value = self.redis_impl.incr("IdGen:WorkerId:Value:Edit")
  75. return reset_value != 1
  76. except Exception as ept:
  77. logging.error(ept)
  78. return False
  79. def end_reset():
  80. try:
  81. self.redis_impl.set("IdGen:WorkerId:Value:Edit", 0)
  82. except Exception as ept:
  83. logging.error(ept)
  84. def is_available(worker_id: int):
  85. try:
  86. rst = self.redis_impl.get(f"IdGen:WorkerId:Value:{worker_id}")
  87. return rst != "Y"
  88. except Exception as ept:
  89. logging.error(ept)
  90. return False
  91. if cur > self.max_worker_id:
  92. if can_reset():
  93. self.redis_impl.set("IdGen:WorkerId:Index", -1)
  94. end_reset()
  95. self.loop_count += 1
  96. if self.loop_count > self.max_loop_count:
  97. self.loop_count = 0
  98. return -1
  99. time.sleep(0.2 * self.loop_count)
  100. return self.__get_next_worker_id()
  101. time.sleep(0.2)
  102. return self.__get_next_worker_id()
  103. if is_available(cur):
  104. self.redis_impl.setex(
  105. f"IdGen:WorkerId:Value:{cur}",
  106. self.worker_id_expire_time,
  107. "Y"
  108. )
  109. self.loop_count = 0
  110. return cur
  111. return self.__get_next_worker_id()