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

251 lines
6.3 KiB

Merge accumulated changes related to message queue (#5098) * balance partitions on brokers * prepare topic partition first and then publish, move partition * purge unused APIs * clean up * adjust logs * add BalanceTopics() grpc API * configure topic * configure topic command * refactor * repair missing partitions * sequence of operations to ensure ordering * proto to close publishers and consumers * rename file * topic partition versioned by unixTimeNs * create local topic partition * close publishers * randomize the client name * wait until no publishers * logs * close stop publisher channel * send last ack * comments * comment * comments * support list of brokers * add cli options * Update .gitignore * logs * return io.eof directly * refactor * optionally create topic * refactoring * detect consumer disconnection * sub client wait for more messages * subscribe by time stamp * rename * rename to sub_balancer * rename * adjust comments * rename * fix compilation * rename * rename * SubscriberToSubCoordinator * sticky rebalance * go fmt * add tests * balance partitions on brokers * prepare topic partition first and then publish, move partition * purge unused APIs * clean up * adjust logs * add BalanceTopics() grpc API * configure topic * configure topic command * refactor * repair missing partitions * sequence of operations to ensure ordering * proto to close publishers and consumers * rename file * topic partition versioned by unixTimeNs * create local topic partition * close publishers * randomize the client name * wait until no publishers * logs * close stop publisher channel * send last ack * comments * comment * comments * support list of brokers * add cli options * Update .gitignore * logs * return io.eof directly * refactor * optionally create topic * refactoring * detect consumer disconnection * sub client wait for more messages * subscribe by time stamp * rename * rename to sub_balancer * rename * adjust comments * rename * fix compilation * rename * rename * SubscriberToSubCoordinator * sticky rebalance * go fmt * add tests * tracking topic=>broker * merge * comment
1 year ago
10 months ago
1 year ago
1 year ago
11 months ago
1 year ago
10 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
10 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
9 months ago
10 months ago
  1. package pub_balancer
  2. import (
  3. "fmt"
  4. cmap "github.com/orcaman/concurrent-map/v2"
  5. "github.com/seaweedfs/seaweedfs/weed/pb/mq_pb"
  6. "github.com/stretchr/testify/assert"
  7. "testing"
  8. )
  9. func Test_allocateOneBroker(t *testing.T) {
  10. brokers := cmap.New[*BrokerStats]()
  11. brokers.SetIfAbsent("localhost:17777", &BrokerStats{
  12. TopicPartitionCount: 0,
  13. ConsumerCount: 0,
  14. CpuUsagePercent: 0,
  15. })
  16. tests := []struct {
  17. name string
  18. args args
  19. wantAssignments []*mq_pb.BrokerPartitionAssignment
  20. }{
  21. {
  22. name: "test only one broker",
  23. args: args{
  24. brokers: brokers,
  25. partitionCount: 1,
  26. },
  27. wantAssignments: []*mq_pb.BrokerPartitionAssignment{
  28. {
  29. LeaderBroker: "localhost:17777",
  30. Partition: &mq_pb.Partition{
  31. RingSize: MaxPartitionCount,
  32. RangeStart: 0,
  33. RangeStop: MaxPartitionCount,
  34. },
  35. },
  36. },
  37. },
  38. }
  39. testThem(t, tests)
  40. }
  41. type args struct {
  42. brokers cmap.ConcurrentMap[string, *BrokerStats]
  43. partitionCount int32
  44. }
  45. func testThem(t *testing.T, tests []struct {
  46. name string
  47. args args
  48. wantAssignments []*mq_pb.BrokerPartitionAssignment
  49. }) {
  50. for _, tt := range tests {
  51. t.Run(tt.name, func(t *testing.T) {
  52. gotAssignments := AllocateTopicPartitions(tt.args.brokers, tt.args.partitionCount)
  53. assert.Equal(t, len(tt.wantAssignments), len(gotAssignments))
  54. for i, gotAssignment := range gotAssignments {
  55. assert.Equal(t, tt.wantAssignments[i].LeaderBroker, gotAssignment.LeaderBroker)
  56. assert.Equal(t, tt.wantAssignments[i].Partition.RangeStart, gotAssignment.Partition.RangeStart)
  57. assert.Equal(t, tt.wantAssignments[i].Partition.RangeStop, gotAssignment.Partition.RangeStop)
  58. assert.Equal(t, tt.wantAssignments[i].Partition.RingSize, gotAssignment.Partition.RingSize)
  59. }
  60. })
  61. }
  62. }
  63. func TestEnsureAssignmentsToActiveBrokersX(t *testing.T) {
  64. type args struct {
  65. activeBrokers cmap.ConcurrentMap[string, *BrokerStats]
  66. followerCount int
  67. assignments []*mq_pb.BrokerPartitionAssignment
  68. }
  69. activeBrokers := cmap.New[*BrokerStats]()
  70. activeBrokers.SetIfAbsent("localhost:1", &BrokerStats{})
  71. activeBrokers.SetIfAbsent("localhost:2", &BrokerStats{})
  72. activeBrokers.SetIfAbsent("localhost:3", &BrokerStats{})
  73. activeBrokers.SetIfAbsent("localhost:4", &BrokerStats{})
  74. activeBrokers.SetIfAbsent("localhost:5", &BrokerStats{})
  75. activeBrokers.SetIfAbsent("localhost:6", &BrokerStats{})
  76. lowActiveBrokers := cmap.New[*BrokerStats]()
  77. lowActiveBrokers.SetIfAbsent("localhost:1", &BrokerStats{})
  78. lowActiveBrokers.SetIfAbsent("localhost:2", &BrokerStats{})
  79. singleActiveBroker := cmap.New[*BrokerStats]()
  80. singleActiveBroker.SetIfAbsent("localhost:1", &BrokerStats{})
  81. tests := []struct {
  82. name string
  83. args args
  84. hasChanges bool
  85. }{
  86. {
  87. name: "test empty leader",
  88. args: args{
  89. activeBrokers: activeBrokers,
  90. followerCount: 1,
  91. assignments: []*mq_pb.BrokerPartitionAssignment{
  92. {
  93. LeaderBroker: "",
  94. Partition: &mq_pb.Partition{},
  95. FollowerBrokers: []string{
  96. "localhost:2",
  97. },
  98. },
  99. },
  100. },
  101. hasChanges: true,
  102. },
  103. {
  104. name: "test empty follower",
  105. args: args{
  106. activeBrokers: activeBrokers,
  107. followerCount: 1,
  108. assignments: []*mq_pb.BrokerPartitionAssignment{
  109. {
  110. LeaderBroker: "localhost:1",
  111. Partition: &mq_pb.Partition{},
  112. FollowerBrokers: []string{
  113. "",
  114. },
  115. },
  116. },
  117. },
  118. hasChanges: true,
  119. },
  120. {
  121. name: "test dead follower",
  122. args: args{
  123. activeBrokers: activeBrokers,
  124. followerCount: 1,
  125. assignments: []*mq_pb.BrokerPartitionAssignment{
  126. {
  127. LeaderBroker: "localhost:1",
  128. Partition: &mq_pb.Partition{},
  129. FollowerBrokers: []string{
  130. "localhost:200",
  131. },
  132. },
  133. },
  134. },
  135. hasChanges: true,
  136. },
  137. {
  138. name: "test dead leader and follower",
  139. args: args{
  140. activeBrokers: activeBrokers,
  141. followerCount: 1,
  142. assignments: []*mq_pb.BrokerPartitionAssignment{
  143. {
  144. LeaderBroker: "localhost:100",
  145. Partition: &mq_pb.Partition{},
  146. FollowerBrokers: []string{
  147. "localhost:200",
  148. },
  149. },
  150. },
  151. },
  152. hasChanges: true,
  153. },
  154. {
  155. name: "test missing two followers",
  156. args: args{
  157. activeBrokers: activeBrokers,
  158. followerCount: 3,
  159. assignments: []*mq_pb.BrokerPartitionAssignment{
  160. {
  161. LeaderBroker: "localhost:1",
  162. Partition: &mq_pb.Partition{},
  163. FollowerBrokers: []string{
  164. "localhost:2",
  165. },
  166. },
  167. },
  168. },
  169. hasChanges: true,
  170. },
  171. {
  172. name: "test missing some followers",
  173. args: args{
  174. activeBrokers: activeBrokers,
  175. followerCount: 10,
  176. assignments: []*mq_pb.BrokerPartitionAssignment{
  177. {
  178. LeaderBroker: "localhost:1",
  179. Partition: &mq_pb.Partition{},
  180. FollowerBrokers: []string{
  181. "localhost:2",
  182. },
  183. },
  184. },
  185. },
  186. hasChanges: true,
  187. },
  188. {
  189. name: "test low active brokers",
  190. args: args{
  191. activeBrokers: lowActiveBrokers,
  192. followerCount: 3,
  193. assignments: []*mq_pb.BrokerPartitionAssignment{
  194. {
  195. LeaderBroker: "localhost:1",
  196. Partition: &mq_pb.Partition{},
  197. FollowerBrokers: []string{
  198. "localhost:2",
  199. },
  200. },
  201. },
  202. },
  203. hasChanges: false,
  204. },
  205. {
  206. name: "test low active brokers with one follower",
  207. args: args{
  208. activeBrokers: lowActiveBrokers,
  209. followerCount: 1,
  210. assignments: []*mq_pb.BrokerPartitionAssignment{
  211. {
  212. LeaderBroker: "localhost:1",
  213. Partition: &mq_pb.Partition{},
  214. },
  215. },
  216. },
  217. hasChanges: true,
  218. },
  219. {
  220. name: "test single active broker",
  221. args: args{
  222. activeBrokers: singleActiveBroker,
  223. followerCount: 3,
  224. assignments: []*mq_pb.BrokerPartitionAssignment{
  225. {
  226. LeaderBroker: "localhost:1",
  227. Partition: &mq_pb.Partition{},
  228. FollowerBrokers: []string{
  229. "localhost:2",
  230. },
  231. },
  232. },
  233. },
  234. hasChanges: true,
  235. },
  236. }
  237. for _, tt := range tests {
  238. t.Run(tt.name, func(t *testing.T) {
  239. fmt.Printf("%v before %v\n", tt.name, tt.args.assignments)
  240. hasChanges := EnsureAssignmentsToActiveBrokers(tt.args.activeBrokers, tt.args.followerCount, tt.args.assignments)
  241. assert.Equalf(t, tt.hasChanges, hasChanges, "EnsureAssignmentsToActiveBrokers(%v, %v, %v)", tt.args.activeBrokers, tt.args.followerCount, tt.args.assignments)
  242. fmt.Printf("%v after %v\n", tt.name, tt.args.assignments)
  243. })
  244. }
  245. }