-
Notifications
You must be signed in to change notification settings - Fork 808
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
race when using codec with grpc #205
Comments
On 30 September 2016 at 12:38, chocnutfriday notifications@github.com
The generated Marshal method is already thread safe.
|
I'm not sure why the race isn't happening for you. Did you just run the generate script and go test? I just checked after "go get"ing the latest gogo/protobuf and grpcs. |
Gist now updated with example output from the race detector as well as the generated pbs. |
I think you need to send me the new gist link. |
My bad. I forgot to hit the update button or something yesterday. Maybe it will make more sense after you looked at the code that is generated as well as the output. |
Ok its updated, but I still don't see where you are importing codec? |
Well, in the generated pb protobuf/proto is imported. Proto.MarshalTo is called. Previous write at 0x00c4202781ce by goroutine 78: |
But can you explain to me how grpc/rpc_util is able to call gogo/protobuf/codec without you passing it to the grpc server? |
From the grpc source: func (protoCodec) Marshal(v interface{}) ([]byte, error) { |
Ok and now. How does it get to the github.com/gogo/protobuf/codec ? On 6 October 2016 at 13:54, chocnutfriday notifications@github.com wrote:
|
gogo protobuf satisfies the grpc codec interface and it is used by default. |
How is it used by default? where? |
Yes, it is injected somewhere. Magic of auto-generated code. It shows up on the race-detector in most of my grpc projects. The fact of the matter is that when something injects is into something that expects a thread-safe buffer it's not going to happen, causing a race. |
generated code can be read. Code is not magic. Where is it begin injected? |
Yes, you are completely right. I couldn't find where the use of codec was generated, because it isn't generated. It is done in the grpc server itself. Which makes me wonder how the race isn't a problem for more people. in at line 196: Well I'm surprised. |
Well done, see no magic :) Now you will need to edit your gist to always use the github.com/gogo/protobuf/codec . Please see the grpc-go Server and Client Options. Their should be some option called |
The gist has been updated to use the protobuf codec as "custom codec". |
Looks like it has only been updated on the server and not the client. But might be a good idea to see if that alone reproduces the problem. I'll have a look as soon as I can, but I am quite busy at the moment with moving. So expect some delays. |
Yes, the output from the race detector shows that the race happens for the server. I think it is because new requests can arrive while other requests are being processed. The client code in this case is quite thread-safe, so there's no need for a thread-safe codec. Thank you. |
Thats also good to know. |
Its really weird, but when I clone your gist I can really weird file names.
Maybe its easier if you remove the folder. Also please change the proto_path to just assume that you are in ./src/somefolder and that gogoprotobuf and all deps are already cloned. That way someone can just check it out and start fiddling. |
hello? |
Sorry for not being active on this. I have stopped working on this issue for now. The default PB marshaler is good enough for its purpose and this is what GRPC uses by default. I could not come up with a scheme for a codec that is efficient, fast and thread-safe. Though the current proto/codec is not safe for concurrent use, it is efficient, fast and good for reuse. If you can think of a way to get similar performance in a thread-safe way let me know. I tried using sync.Pool, but gave up on that since I had to choose between doing a copy or risk a race when returning the buffer coupled with a defered insert into the pool. |
All that work can be very useful in making an argument to grpc-go. |
I don't mind doing this. I just want to get clarity about what a good solution would be. Parallel encoding is currently done by sharing a single codec. My thoughts are that, for go, it would be better to have a pool of codec objects that never gets accessed concurrently. Given the cost of assuring synchronisation having a single shared codec isn't worth it currently. At least, this is true for go, but not for all languages. C++ has arena to get around the safety issue, for example. In other words, this default behavior of sharing a codec isn't always bad and the implications of changing this assumption extends beyond go. So before I raise the issue let me know what you would suggest as I'm at a loss. |
We are not challenging grpc just the grpc-go library. I don't mind raising the issue with them, if you don't want to, but I need data and code to support this and as you know this takes time to make. We need three things:
Then in the issue (you or I) can link to the gist(s) that you made you simply argue the point that asks them to implement codec pooling. |
Ok, I'll work on this. I'll let you know when I've updated the gist. |
Jumping on the bandwagon here. gRPC expect the As for using a pool, I did some benchmark using a Here are the results, first one is simple
The performance advantage of the pool, in our case, is lost type marshalerTo interface {
Size() int
MarshalTo(data []byte) (n int, err error)
} In the end, we are using this very simple codec: type GogoCodec struct {
grpc.Codec
}
func (g *GogoCodec) Marshal(v interface{}) ([]byte, error) {
return proto.Marshal(v.(proto.Message))
}
func (g *GogoCodec) Unmarshal(data []byte, v interface{}) error {
return proto.Unmarshal(data, v.(proto.Message))
}
func (g *GogoCodec) String() string {
return "proto"
} |
Thank you for the data. Can you also provide the protobuf you used, since it looks like it could be a small one? |
Sure, here goes (proto3), compiled with marshaler and sizer: message Sample {
string str1 = 1;
string str2 = 2;
string str3 = 3;
repeated string str_array1 = 4;
repeated string str_array2 = 5;
} |
All the fields were set, and the arrays to one item only |
Ok yes as suspected this is a very small proto message. Good to know.
Thanks alot
…On Tue, 24 Jan 2017, 13:44 Steeve Morin, ***@***.***> wrote:
All the fields were set, and the arrays to one item only
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#205 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ABvsLaPRLsI7vUqZ26oAa1Ad-dy5Xj8Kks5rVfIpgaJpZM4KK9B6>
.
|
Going back on this, is there a reason for the gogo grpc codec to keep its bytes as state, thus suffering from a data race when concurrent calls to |
grpc expects marshalers to be thread-safe. This is not true in gogo protobuf currently. In most cases this is best, soI am not suggesting that the default behavior changes. However, it would be nice if an option, such as
"option (gogoproto.concurrent_marshaler_all) = true"
could be used to enforce thread-safety in marshalers.
I have created a small example that demonstrates the issue:
https://gist.github.com/chocnutfriday/a864630a5bcbafd5c15ae634ccc776d3
Run it with "go test -race"
The text was updated successfully, but these errors were encountered: